From 2f3ae275d90966efed7630957b2f8a42858cde39 Mon Sep 17 00:00:00 2001
From: hanyongwei <2043702190@qq.com>
Date: Mon, 24 Aug 2026 12:48:49 +0800
Subject: [PATCH] =?UTF-8?q?=E6=9C=80=E5=90=8E=E4=B8=80=E4=B8=AA=E8=84=89?=
=?UTF-8?q?=E5=86=B2=E4=B8=8B=E9=99=8D=E6=B2=BF=E5=BC=BA=E5=88=B6=E6=8B=89?=
=?UTF-8?q?=E4=BD=8E=E7=94=B5=E5=B9=B3=EF=BC=8C=E9=81=BF=E5=85=8D=E5=87=BA?=
=?UTF-8?q?=E7=8E=B0=E6=9E=81=E7=AA=84=E7=9A=84=E8=84=89=E5=86=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: hanyongwei <2043702190@qq.com>
---
iar/plsr.dep | 1 +
plsr/param/plsr_param.c | 70 +++++++++++------------
plsr/plsr.c | 2 +-
plsr/pulse_driver/plsr_pulse_driver.c | 81 ++++++++++++++++++++++++++-
plsr/pulse_driver/plsr_pulse_driver.h | 12 ++++
plsr/run_control/plsr_run_control.c | 14 +++--
6 files changed, 138 insertions(+), 42 deletions(-)
diff --git a/iar/plsr.dep b/iar/plsr.dep
index 284e4f6..e2d4444 100644
--- a/iar/plsr.dep
+++ b/iar/plsr.dep
@@ -474,6 +474,7 @@
$PROJ_DIR$\Debug\Obj\stm32f4xx_hal_sdram.xcl
$PROJ_DIR$\Debug\Obj\startup_stm32f407xx.o
$PROJ_DIR$\Debug\Obj\os_cpu_c.xcl
+ $PROJ_DIR$\..\..\..\Desktop\plsr\app\main.c
[ROOT_NODE]
diff --git a/plsr/param/plsr_param.c b/plsr/param/plsr_param.c
index df161e3..ae285f5 100644
--- a/plsr/param/plsr_param.c
+++ b/plsr/param/plsr_param.c
@@ -39,41 +39,41 @@ static volatile uint8_t s_xfer_active; /* 1=正在接收一批分帧 */
* @brief 出厂默认参数(见 plsr_param.h)
* @note 与上位机 initCommonDefaults 约定一致,便于未写 PLC 时行为可预期
*/
-void PlsrParamInitDefault(void)
-{
- uint16_t i;
-
- memset(&s_cfg, 0, sizeof(s_cfg));
- memset(s_seg, 0, sizeof(s_seg));
-
- /* 与上位机默认约定一致;真正运行参数由 ApplyFromHold / PersistLoad 覆盖 */
- s_cfg.pulse_y = 0U;
- s_cfg.dir_y = 3U;
- s_cfg.wait_x_sel = 0U;
- s_cfg.ext_x_sel = 0U;
- s_cfg.send_mode = PLSR_SEND_COMPLETE;
- s_cfg.dir_delay_ms = 10U;
- s_cfg.dir_logic = PLSR_DIR_LOGIC_POS;
- s_cfg.accel_mode = PLSR_ACCEL_LINEAR;
- s_cfg.run_mode = PLSR_POS_RELATIVE;
- s_cfg.seg_count = 0U;
- s_cfg.start_seg = 1U;
- s_cfg.default_speed = 1000UL;
- s_cfg.start_speed = 0UL;
- s_cfg.end_speed = 0UL;
- s_cfg.accel_ms = 100U;
- s_cfg.decel_ms = 100U;
-
- for (i = 0U; i < PLSR_SEG_MAX; i++)
- {
- s_seg[i].freq_hz = 0;
- s_seg[i].pulse_cnt = 0;
- s_seg[i].wait_type = PLSR_WAIT_TIME;
- s_seg[i].wait_ms = 0U;
- s_seg[i].act_ms = 0U;
- s_seg[i].jump_seg = 0U;
- }
-}
+//void PlsrParamInitDefault(void)
+//{
+// uint16_t i;
+//
+// memset(&s_cfg, 0, sizeof(s_cfg));
+// memset(s_seg, 0, sizeof(s_seg));
+//
+// /* 与上位机默认约定一致;真正运行参数由 ApplyFromHold / PersistLoad 覆盖 */
+// s_cfg.pulse_y = 0U;
+// s_cfg.dir_y = 3U;
+// s_cfg.wait_x_sel = 0U;
+// s_cfg.ext_x_sel = 0U;
+// s_cfg.send_mode = PLSR_SEND_COMPLETE;
+// s_cfg.dir_delay_ms = 10U;
+// s_cfg.dir_logic = PLSR_DIR_LOGIC_POS;
+// s_cfg.accel_mode = PLSR_ACCEL_LINEAR;
+// s_cfg.run_mode = PLSR_POS_RELATIVE;
+// s_cfg.seg_count = 0U;
+// s_cfg.start_seg = 1U;
+// s_cfg.default_speed = 1000UL;
+// s_cfg.start_speed = 0UL;
+// s_cfg.end_speed = 0UL;
+// s_cfg.accel_ms = 100U;
+// s_cfg.decel_ms = 100U;
+//
+// for (i = 0U; i < PLSR_SEG_MAX; i++)
+// {
+// s_seg[i].freq_hz = 0;
+// s_seg[i].pulse_cnt = 0;
+// s_seg[i].wait_type = PLSR_WAIT_TIME;
+// s_seg[i].wait_ms = 0U;
+// s_seg[i].act_ms = 0U;
+// s_seg[i].jump_seg = 0U;
+// }
+//}
/** @return 公共参数映像指针(见 plsr_param.h) */
PlsrCfg_t *PlsrParamGetCfg(void)
diff --git a/plsr/plsr.c b/plsr/plsr.c
index 73e27c7..0280b0e 100644
--- a/plsr/plsr.c
+++ b/plsr/plsr.c
@@ -29,7 +29,7 @@
*/
void PlsrInit(void)
{
- PlsrParamInitDefault();
+ //PlsrParamInitDefault();
PlsrPersistLoad(); /* BKPSRAM 稀疏映像 → g_hold_reg */
(void)PlsrParamBlockApplyFromHold();
PlsrPulseDriverInit();
diff --git a/plsr/pulse_driver/plsr_pulse_driver.c b/plsr/pulse_driver/plsr_pulse_driver.c
index ce84d01..1ab9359 100644
--- a/plsr/pulse_driver/plsr_pulse_driver.c
+++ b/plsr/pulse_driver/plsr_pulse_driver.c
@@ -55,6 +55,7 @@ static volatile uint8_t s_req_pending;
* 1=DIR_WAIT 已装载寄存器且 CEN 关:到期 Commit 前必须 CNT=0 再开 PWM。
*/
static uint8_t s_regs_prepared;
+static volatile uint8_t s_seg_end_fall_armed; /* 1=末拍 CC1 下降沿后强制拉低 */
/*============================================================================*/
/* 路选择 / 时钟 / GPIO */
@@ -121,6 +122,36 @@ static void PlsrPulseDriverDirGpioInit(void)
* HAL_TIM_PWM_Stop 会清 CC1E,脚变成 AF 高阻,飞线接地的沿会耦合出极短脉冲。
* Forced inactive + 通道保持使能:TIM 推挽把脚主动拉低(段间空闲低)。
*/
+static void PlsrPulseDriverClearSegEndFallArm(TIM_HandleTypeDef *htim)
+{
+ s_seg_end_fall_armed = 0U;
+ if ((htim == (TIM_HandleTypeDef *)0) || (htim->Instance == (TIM_TypeDef *)0))
+ {
+ return;
+ }
+ __HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1);
+ __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC1);
+}
+
+/**
+ * 末拍下降沿:只切 Forced inactive 拉低,CEN/OPM/UPDATE 继续跑到周期结束。
+ */
+static void PlsrPulseDriverOcForceLowKeepRun(TIM_HandleTypeDef *htim)
+{
+ uint32_t ccmr;
+
+ if ((htim == (TIM_HandleTypeDef *)0) || (htim->Instance == (TIM_TypeDef *)0))
+ {
+ return;
+ }
+
+ ccmr = htim->Instance->CCMR1;
+ ccmr &= (uint32_t)(~TIM_CCMR1_OC1M);
+ ccmr |= TIM_OCMODE_FORCED_INACTIVE;
+ htim->Instance->CCMR1 = ccmr;
+ htim->Instance->CCER |= TIM_CCER_CC1E;
+}
+
static void PlsrPulseDriverOcHoldLow(TIM_HandleTypeDef *htim)
{
uint32_t ccmr;
@@ -131,6 +162,7 @@ static void PlsrPulseDriverOcHoldLow(TIM_HandleTypeDef *htim)
}
__HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE);
+ PlsrPulseDriverClearSegEndFallArm(htim);
htim->Instance->CR1 &= (uint32_t)(~(TIM_CR1_CEN | TIM_CR1_OPM));
ccmr = htim->Instance->CCMR1;
@@ -803,7 +835,9 @@ void PlsrPulseDriverStop(void)
s_last_arr = 0xFFFFFFFFUL;
}
-/** @brief 武装 OPM 段末停表(见 plsr_pulse_driver.h) */
+/**
+ * @brief 武装 OPM 段末停表(见 plsr_pulse_driver.h)
+ */
void PlsrPulseDriverArmOnePulseStop(void)
{
TIM_HandleTypeDef *htim = s_active_htim;
@@ -816,6 +850,38 @@ void PlsrPulseDriverArmOnePulseStop(void)
htim->Instance->CR1 |= TIM_CR1_OPM;
}
+/**
+ * @brief 段末停表:OPM + 末拍 CC1 下降沿立刻拉低(见 plsr_pulse_driver.h)
+ */
+void PlsrPulseDriverArmSegEndStop(void)
+{
+ TIM_HandleTypeDef *htim = s_active_htim;
+
+ if (htim == (TIM_HandleTypeDef *)0)
+ {
+ return;
+ }
+
+ htim->Instance->CR1 |= TIM_CR1_OPM;
+ s_seg_end_fall_armed = 1U;
+ __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC1);
+ __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
+}
+
+/** @brief HAL PWM 脉宽结束(CC1 匹配 ≈ 下降沿) */
+void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
+{
+ if ((s_seg_end_fall_armed == 0U) ||
+ (htim != s_active_htim) ||
+ (PlsrPulseDriverIsPulseTim(htim->Instance) == 0U))
+ {
+ return;
+ }
+
+ PlsrPulseDriverClearSegEndFallArm(htim);
+ PlsrPulseDriverOcForceLowKeepRun(htim);
+}
+
/** @brief 取消 OPM(见 plsr_pulse_driver.h) */
void PlsrPulseDriverClearOnePulseStop(void)
{
@@ -826,4 +892,17 @@ void PlsrPulseDriverClearOnePulseStop(void)
return;
}
htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_OPM);
+ PlsrPulseDriverClearSegEndFallArm(htim);
+}
+
+/** @brief OPM 段末 UPDATE 后立刻拉低,消除 CNT 回零 PWM1 假上升沿(见 plsr_pulse_driver.h) */
+void PlsrPulseDriverHoldOutputLow(void)
+{
+ TIM_HandleTypeDef *htim = s_active_htim;
+
+ if (htim == (TIM_HandleTypeDef *)0)
+ {
+ return;
+ }
+ PlsrPulseDriverStopHtim(htim);
}
diff --git a/plsr/pulse_driver/plsr_pulse_driver.h b/plsr/pulse_driver/plsr_pulse_driver.h
index 50f5ff1..6324ee3 100644
--- a/plsr/pulse_driver/plsr_pulse_driver.h
+++ b/plsr/pulse_driver/plsr_pulse_driver.h
@@ -106,11 +106,23 @@ void PlsrPulseDriverStop(void);
*/
void PlsrPulseDriverArmOnePulseStop(void);
+/**
+ * @brief 段末停表:OPM 等周期结束 + CC1 下降沿立刻 Forced 拉低
+ * @note 仅非 FOLLOW-keep 段末使用;ACT 切段仍用 ArmOnePulseStop
+ */
+void PlsrPulseDriverArmSegEndStop(void);
+
/**
* @brief 取消单脉冲停表(后续模式同向衔接 / CutSeg keep 时)
*/
void PlsrPulseDriverClearOnePulseStop(void);
+/**
+ * @brief 立即将当前活动路输出强制拉低(Forced inactive),不关其它路
+ * @note ISR 安全;OPM 段末 UPDATE 后 CNT 回零时 PWM1 可能短暂为高,须先于收尾调用
+ */
+void PlsrPulseDriverHoldOutputLow(void);
+
/**
* @brief 判断 instance 是否为本模块脉冲 TIM
* @return 1=TIM10/11/13;0=否
diff --git a/plsr/run_control/plsr_run_control.c b/plsr/run_control/plsr_run_control.c
index b881816..9e2fd2e 100644
--- a/plsr/run_control/plsr_run_control.c
+++ b/plsr/run_control/plsr_run_control.c
@@ -31,8 +31,8 @@
* 减速在 remain==dec_n+1 切入;纯减速开表再预装一拍。
*
* 【段末停表】非 FOLLOW-keep 时开段锁 s_seg_end_opm:
- * UPDATE≈上升沿;s_done 到 target 时武装 OPM,末拍整周期跑完后下一 UPDATE
- * 再 AfterSegDone 且不再 ++ → 末拍完整且不多 1。FOLLOW-keep 到点立刻衔接。
+ * UPDATE≈上升沿;s_done 到 target 时 ArmSegEndStop(OPM+CC1 末拍下降沿拉低),
+ * 周期 UPDATE 再 HoldOutputLow + AfterSegDone 且不再 ++。FOLLOW-keep 到点立刻衔接。
*
* 【故障诊断 0x2006】(PlsrCommandSetFault,告警码 1~3 不停机;4 禁止启动)
* 0x01 段结束 AfterSegDone:s_done != s_target
@@ -1717,6 +1717,11 @@ void PlsrRunControlOnPulseIsr(void)
{
s_last_period_wait = 0U;
s_act_cut_pending = 0U;
+ /*
+ * 末拍下降沿已在 CC1 中断拉低;本 UPDATE 为 OPM 周期结束,不再 ++。
+ * 再 HoldOutputLow 完整停表,交 AfterSegDone。
+ */
+ PlsrPulseDriverHoldOutputLow();
PlsrRunControlAfterSegDone();
return;
}
@@ -1753,10 +1758,9 @@ void PlsrRunControlOnPulseIsr(void)
{
/*
* 本 UPDATE = 末拍上升沿,已计入 target。
- * 武装 OPM:本周期完整跑完后下一 UPDATE 停表 → s_last_period_wait 收尾。
- * 此处不 AfterSegDone/Stop,否则会截断末拍成尖刺。
+ * ArmSegEndStop:CC1 下降沿立刻拉低,OPM 等周期 UPDATE 再收尾。
*/
- PlsrPulseDriverArmOnePulseStop();
+ PlsrPulseDriverArmSegEndStop();
s_last_period_wait = 1U;
return;
}