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; }