From 5bd7cb9c53526a041155137ef5b3aa943ea1a285 Mon Sep 17 00:00:00 2001 From: hanyongwei <2043702190@qq.com> Date: Wed, 2 Sep 2026 09:22:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E6=8E=89=E4=BA=8C=E5=88=86=E9=99=8D?= =?UTF-8?q?=E5=B3=B0=E5=90=8E=E9=87=8D=E5=A4=8D=E5=88=A4=E6=96=AD=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hanyongwei <2043702190@qq.com> --- plsr/accel_curve/plsr_accel_curve.c | 1637 ++++++++++++------------- plsr/accel_curve/plsr_accel_curve.h | 9 +- plsr/command/plsr_command.c | 67 +- plsr/param/plsr_param.c | 80 +- plsr/plsr.c | 2 +- plsr/plsr.h | 6 +- plsr/pulse_driver/plsr_pulse_driver.c | 539 ++++---- plsr/pulse_driver/plsr_pulse_driver.h | 8 +- plsr/run_control/plsr_run_control.c | 1329 ++++++++++---------- plsr/signal_io/plsr_signal_io.c | 63 +- 10 files changed, 1887 insertions(+), 1853 deletions(-) diff --git a/plsr/accel_curve/plsr_accel_curve.c b/plsr/accel_curve/plsr_accel_curve.c index f0ad4ef..9ac1892 100644 --- a/plsr/accel_curve/plsr_accel_curve.c +++ b/plsr/accel_curve/plsr_accel_curve.c @@ -5,26 +5,26 @@ #include "plsr_accel_curve.h" #include -PlsrAccelPlan_t g_plsr_accel_plan; -PlsrAccelRuntime_t g_plsr_accel_runtime; - -/* 正弦 raised-cosine 形状表(千分比) */ -static const uint16_t s_plsr_sine_shape_tab[33] = { - 0U, 2U, 10U, 22U, 38U, 59U, 84U, 113U, - 146U, 183U, 222U, 264U, 309U, 355U, 402U, 451U, - 500U, 549U, 598U, 645U, 691U, 736U, 778U, 817U, - 854U, 887U, 916U, 941U, 962U, 978U, 990U, 998U, - 1000U +PlsrAccelPlan_t g_plsr_accel_plan; /* 当前段三相规划结果 */ /* 整段规划全局一份 */ +PlsrAccelRuntime_t g_plsr_accel_runtime; /* 当前相 ISR 逐拍状态 */ /* 当前相运行态全局一份 */ + +/* 正弦 raised-cosine 形状表(千分比 0..1000) */ +static const uint16_t s_plsr_sine_shape_tab[33] = { /* 半个余弦形状的进度表,0到1000 */ + 0U, 2U, 10U, 22U, 38U, 59U, 84U, 113U, /* 前半段:进度小,形状值也小 */ + 146U, 183U, 222U, 264U, 309U, 355U, 402U, 451U, /* 中间往上爬 */ + 500U, 549U, 598U, 645U, 691U, 736U, 778U, 817U, /* 过半:500是中点 */ + 854U, 887U, 916U, 941U, 962U, 978U, 990U, 998U, /* 后半段往1000收 */ + 1000U /* 终点1000=形状走完 */ }; /* S/正弦频率预计算表:PlanSeg 时填好;ISR 只切换/查表。匀速不改频。 */ -#define PLSR_RAMP_TBL_MAX 4096U -static uint32_t s_accel_freq_table[PLSR_RAMP_TBL_MAX]; -static uint32_t s_decel_freq_table[PLSR_RAMP_TBL_MAX]; -static uint32_t s_accel_table_length; -static uint32_t s_accel_table_stride; -static uint32_t s_decel_table_length; -static uint32_t s_decel_table_stride; +#define PLSR_RAMP_TBL_MAX 4096U /* 表最长4096项,超了就抽样 */ +static uint32_t s_accel_freq_table[PLSR_RAMP_TBL_MAX]; /* 加速相频率表 */ /* 加速相每拍频率 */ +static uint32_t s_decel_freq_table[PLSR_RAMP_TBL_MAX]; /* 减速相频率表 */ /* 减速相每拍频率 */ +static uint32_t s_accel_table_length; /* 加速表有效项数 */ /* 加速表用了几项 */ +static uint32_t s_accel_table_stride; /* 加速表抽样步长 */ /* 加速表几个脉冲读一项 */ +static uint32_t s_decel_table_length; /* 减速表有效项数 */ /* 减速表用了几项 */ +static uint32_t s_decel_table_stride; /* 减速表抽样步长 */ /* 减速表几个脉冲读一项 */ /* 静态辅助函数前置声明 */ static uint32_t PlsrAccelCurveClampFreqHz(uint32_t freq_hz); @@ -81,7 +81,7 @@ static uint32_t PlsrAccelCurveCalcRampPulses(uint32_t start_freq_hz, uint32_t en PlsrAccelMode_e curve_mode); static uint32_t PlsrAccelCurveFitTargetFreq(uint32_t total_pulses, uint32_t start_freq_hz, - uint32_t requested_target_freq_hz, + uint32_t peak_tgt_hz, uint32_t end_freq_hz, uint32_t accel_rate_hz_per_s, uint32_t decel_rate_hz_per_s, @@ -94,15 +94,6 @@ static void PlsrAccelCurveCalcPhasePulses(uint32_t start_freq_hz, PlsrAccelMode_e curve_mode, uint32_t *accel_pulses, uint32_t *decel_pulses); -static uint32_t PlsrAccelCurveFitTargetToPulseBudget(uint32_t total_pulses, - uint32_t start_freq_hz, - uint32_t requested_target_freq_hz, - uint32_t end_freq_hz, - uint32_t accel_rate_hz_per_s, - uint32_t decel_rate_hz_per_s, - PlsrAccelMode_e curve_mode, - uint32_t *accel_pulses, - uint32_t *decel_pulses); static void PlsrAccelRuntimeCalcTimes(PlsrAccelRuntime_t *runtime); static void PlsrAccelRuntimeBeginRamp(PlsrAccelRuntime_t *runtime, uint32_t start_freq_hz, @@ -125,32 +116,35 @@ static void PlsrAccelRuntimeSelectFreqTable(PlsrAccelRuntime_t *runtime, /* 公共 API */ /*============================================================================*/ -/*计算起始频率*/ +/* 配置起速 → 本段实际入口频率 */ uint32_t PlsrAccelCurveResolveStartHz(uint32_t configured_freq_hz, uint32_t target_freq_hz, uint32_t default_speed_hz, uint32_t accel_time_ms, uint32_t decel_time_ms) { - /*resolving_start=1 用 accel_time_ms 算 a;resolving_start=0 用 decel_time_ms(ResolveEndHz 止速侧)*/ + /* resolving_start=1:用 accel_time_ms 算 a */ return PlsrAccelCurveResolveBoundaryFreq(configured_freq_hz, target_freq_hz, default_speed_hz, accel_time_ms, decel_time_ms, 1U); } -/*计算终止频率*/ +/* 配置止速 → 本段实际出口频率 */ uint32_t PlsrAccelCurveResolveEndHz(uint32_t configured_freq_hz, uint32_t target_freq_hz, uint32_t default_speed_hz, uint32_t accel_time_ms, uint32_t decel_time_ms) { - /*resolving_start=1 用 accel_time_ms 算 a;resolving_start=0 用 decel_time_ms(ResolveEndHz 止速侧)*/ + /* resolving_start=0:用 decel_time_ms 算 a(止速侧) */ return PlsrAccelCurveResolveBoundaryFreq(configured_freq_hz, target_freq_hz, default_speed_hz, accel_time_ms, decel_time_ms, 0U); } /** - * @brief 规划一整段脉冲 + * @brief 规划一整段脉冲:起/峰/止 + 斜率 → 加速/匀速/减速脉冲预算 + * + * 流程:钳频 → 解析起止 → 算 a → 按目标峰估相位脉冲 → + * 够则梯形留匀速,不够则二分降峰成三角。 */ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, uint32_t total_pulses, @@ -162,171 +156,174 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, uint32_t decel_time_ms, PlsrAccelMode_e curve_mode) { - uint32_t accel_pulses; - uint32_t decel_pulses; - uint32_t peak_freq_hz; - uint32_t accel_rate_hz_per_s; - uint32_t decel_rate_hz_per_s; - PlsrAccelMode_e selected_mode;/*曲线模式*/ + uint32_t accel_pulses; /* 本段加速要几拍 */ + uint32_t decel_pulses; /* 本段减速要几拍 */ + uint32_t peak_freq_hz; /* 实际峰值(可能被砍) */ + uint32_t accel_rate_hz_per_s; /* 加速斜率 Hz/s */ + uint32_t decel_rate_hz_per_s; /* 减速斜率 Hz/s */ + PlsrAccelMode_e selected_mode; /* 曲线模式 */ - if (plan == (PlsrAccelPlan_t *)0) + if (plan == (PlsrAccelPlan_t *)0) /* 空指针直接走人 */ { - return; + return; /* 没plan别往下算 */ } - start_freq_hz = PlsrAccelCurveClampFreqHz(start_freq_hz); - target_freq_hz = PlsrAccelCurveClampFreqHz(target_freq_hz); - end_freq_hz = PlsrAccelCurveClampFreqHz(end_freq_hz); + /* 入口先钳到 100k,避免后续开方/乘溢出 */ + start_freq_hz = PlsrAccelCurveClampFreqHz(start_freq_hz); /* 起频钳住 */ + target_freq_hz = PlsrAccelCurveClampFreqHz(target_freq_hz); /* 目标峰钳住 */ + end_freq_hz = PlsrAccelCurveClampFreqHz(end_freq_hz); /* 止频钳住 */ - /*加减速曲线模式*/ - selected_mode = (curve_mode > PLSR_ACCEL_SINE) ? PLSR_ACCEL_LINEAR : curve_mode; + /* 非法模式回退直线 */ + selected_mode = (curve_mode > PLSR_ACCEL_SINE) ? PLSR_ACCEL_LINEAR : curve_mode; /* 超范围就当直线 */ - /*起始频率小于1,计算一个合适的起始频率*/ - if (start_freq_hz < 1U) + /* 起速未配(<1):按配置/起跳规则补入口 */ + if (start_freq_hz < 1U) /* 起速没配 */ { - start_freq_hz = PlsrAccelCurveResolveStartHz(0U, target_freq_hz, default_speed_hz, + start_freq_hz = PlsrAccelCurveResolveStartHz(0U, target_freq_hz, default_speed_hz, /* 补实际入口频 */ accel_time_ms, decel_time_ms); } - /*终止频率小于1,计算一个合适的终止频率*/ - if (end_freq_hz < 1U) + /* 止速未配(<1):按配置/起跳规则补出口 */ + if (end_freq_hz < 1U) /* 止速没配 */ { - end_freq_hz = PlsrAccelCurveResolveEndHz(0U, target_freq_hz, default_speed_hz, + end_freq_hz = PlsrAccelCurveResolveEndHz(0U, target_freq_hz, default_speed_hz, /* 补实际出口频 */ accel_time_ms, decel_time_ms); } + /* a = default*1000/t_ms;无默认速度时用本段频差 */ accel_rate_hz_per_s = PlsrAccelCurveCalcRate(default_speed_hz, start_freq_hz, target_freq_hz, - accel_time_ms);/*计算加速斜率*/ + accel_time_ms); /* 加速斜率 Hz/s */ decel_rate_hz_per_s = PlsrAccelCurveCalcRate(default_speed_hz, target_freq_hz, end_freq_hz, - decel_time_ms);/*计算减速斜率*/ - - /*将结果写进规划结果*/ - peak_freq_hz = target_freq_hz; - - plan->start_freq_hz = start_freq_hz; - plan->end_freq_hz = end_freq_hz; - plan->curve_mode = selected_mode; - plan->accel_rate_hz_per_s = accel_rate_hz_per_s; - plan->decel_rate_hz_per_s = decel_rate_hz_per_s; - - /*按峰值重算加速/减速脉冲预算*/ - PlsrAccelCurveCalcPhasePulses(start_freq_hz, - peak_freq_hz, - end_freq_hz, - accel_rate_hz_per_s, - decel_rate_hz_per_s, - selected_mode, - &accel_pulses, - &decel_pulses); + decel_time_ms); /* 减速斜率 Hz/s */ + + /* 先按请求峰值写死不变字段;峰值可能随后被 FitPeak 下调 */ + peak_freq_hz = target_freq_hz; /* 先假定能到请求的峰 */ + + plan->start_freq_hz = start_freq_hz; /* 写入口频 */ + plan->end_freq_hz = end_freq_hz; /* 写出口频 */ + plan->curve_mode = selected_mode; /* 写曲线模式 */ + plan->accel_rate_hz_per_s = accel_rate_hz_per_s; /* 写加速斜率 */ + plan->decel_rate_hz_per_s = decel_rate_hz_per_s; /* 写减速斜率 */ + + /* 按当前峰估 acc/dec 脉冲(直线闭合式;S/正弦仿真) */ + PlsrAccelCurveCalcPhasePulses(start_freq_hz, /* 起 */ + peak_freq_hz, /* 峰 */ + end_freq_hz, /* 止 */ + accel_rate_hz_per_s, /* 加速斜率 */ + decel_rate_hz_per_s, /* 减速斜率 */ + selected_mode, /* 直线/S/正弦 */ + &accel_pulses, /* 写出加速拍数 */ + &decel_pulses); /* 写出减速拍数 */ /* --- 特例:本段 0 脉冲 --- */ - if (total_pulses == 0U) + if (total_pulses == 0U) /* 本段0脉冲 */ { - plan->const_pulses = 0U; - plan->target_freq_hz = peak_freq_hz; - plan->accel_pulses = 0U; - plan->decel_pulses = 0U; - return; + plan->const_pulses = 0U; /* 匀速拍数清零 */ + plan->target_freq_hz = peak_freq_hz; /* 峰还是请求值 */ + plan->accel_pulses = 0U; /* 加速0拍 */ + plan->decel_pulses = 0U; /* 减速0拍 */ + return; /* 整段没活干,收工 */ } /* * --- 特例:出口=目标 且 光加速就要用光 N 个脉冲 --- - * 整段当纯加速/纯减,无 dec、无 const(例如短段只爬到目标就停) + * 整段当纯加速,无 dec、无 const(短段只爬峰就停) */ - if ((end_freq_hz == target_freq_hz) && (accel_pulses > total_pulses)) + if ((end_freq_hz == target_freq_hz) && (accel_pulses > total_pulses)) /* 出口就是峰,且加速拍已超总脉冲 */ { - plan->const_pulses = 0U; - plan->target_freq_hz = peak_freq_hz; - plan->accel_pulses = total_pulses; - plan->decel_pulses = 0U; - return; + plan->const_pulses = 0U; /* 匀速不要了 */ + plan->target_freq_hz = peak_freq_hz; /* 峰仍按请求 */ + plan->accel_pulses = total_pulses; /* 所有脉冲都拿去加速 */ + plan->decel_pulses = 0U; /* 不减速 */ + return; /* 短段只爬峰就停 */ } /* - * --- 主分支:脉冲够不够装下 acc + dec + const --- - * 够:const_pulses = 余量(标准梯形) - * 不够:const_pulses=0,FitPeak 降低 peak_freq_hz 直到 accel_pulses+decel_pulses <= N(三角波,可能报 0x02) + * --- 主分支:脉冲够不够装下 acc + dec --- + * 够:余量给匀速(梯形) + * 不够:砍匀速并降峰,使 acc+dec<=N(三角;禁止只截断 dec) */ - if (accel_pulses + decel_pulses <= total_pulses) + if (accel_pulses + decel_pulses <= total_pulses) /* acc+dec装得下? */ { - plan->const_pulses = total_pulses - accel_pulses - decel_pulses; + plan->const_pulses = total_pulses - accel_pulses - decel_pulses; /* 够装:剩下的给匀速(梯形) */ } else { - /* - * 脉冲不够:先砍掉匀速段,保证加减速按完整剖面预算; - * 仍超出则降峰成三角,禁止 decel_pulses=total-accel_pulses 式截断。 - */ - plan->const_pulses = 0U; - peak_freq_hz = PlsrAccelCurveFitTargetToPulseBudget(total_pulses, start_freq_hz, target_freq_hz, end_freq_hz, - accel_rate_hz_per_s, decel_rate_hz_per_s, selected_mode, - &accel_pulses, &decel_pulses); + plan->const_pulses = 0U; /* 不够:砍匀速,三角波 */ + peak_freq_hz = PlsrAccelCurveFitTargetFreq(total_pulses, start_freq_hz, target_freq_hz, end_freq_hz, /* 二分找能塞下的最高峰 */ + accel_rate_hz_per_s, decel_rate_hz_per_s, selected_mode); + PlsrAccelCurveCalcPhasePulses(start_freq_hz, peak_freq_hz, end_freq_hz, /* 按降峰后的峰重算 acc/dec */ + accel_rate_hz_per_s, decel_rate_hz_per_s, selected_mode, + &accel_pulses, &decel_pulses); } /* - * --- 补丁:峰值 > 出口 但 decel_pulses 算出来为 0 --- - * 强制留 1 个脉冲做收尾,从 acc 或 const 里挪 1 个给 dec + * --- 补丁:峰值 > 出口 但 dec 算成 0 --- + * 强制留 1 脉冲收尾,从 acc 或 const 挪给 dec */ - if ((peak_freq_hz > end_freq_hz) && (total_pulses > 1U) && (decel_pulses == 0U)) + if ((peak_freq_hz > end_freq_hz) && (total_pulses > 1U) && (decel_pulses == 0U)) /* 该减速却算出0拍 */ { - decel_pulses = 1U; - if (accel_pulses >= total_pulses) + decel_pulses = 1U; /* 硬塞1拍减速 */ + if (accel_pulses >= total_pulses) /* 加速占满了? */ { - accel_pulses = total_pulses - 1U; + accel_pulses = total_pulses - 1U; /* 从加速挪1拍给减速 */ } - if (plan->const_pulses > 0U) + if (plan->const_pulses > 0U) /* 匀速还有余量? */ { - plan->const_pulses--; + plan->const_pulses--; /* 匀速减1给减速 */ } else { - plan->const_pulses = total_pulses - accel_pulses - decel_pulses; + plan->const_pulses = total_pulses - accel_pulses - decel_pulses; /* 没匀速就重算余量 */ } } - plan->target_freq_hz = peak_freq_hz; - plan->accel_pulses = accel_pulses; - plan->decel_pulses = decel_pulses; + plan->target_freq_hz = peak_freq_hz; /* 可能低于请求目标 */ + plan->accel_pulses = accel_pulses; /* 写回加速拍数 */ + plan->decel_pulses = decel_pulses; /* 写回减速拍数 */ } /** * @brief 按已完成脉冲数取频(任务侧;ISR 用 PlsrAccelNextFreq) + * 相位:加速 [0, accel) → 匀速 [accel, accel+const) → 减速 */ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan, uint32_t completed_seg_pulses) { - uint32_t const_phase_end; - uint32_t pulse_count; - uint32_t freq_hz; - uint8_t freq_rising; + uint32_t const_phase_end; /* 匀速段结束边界 */ + uint32_t pulse_count; /* 减速相内第几拍 */ + uint32_t freq_hz; /* 算出来的频率 */ + uint8_t freq_rising; /* 1=往上爬频,0=往下掉 */ - if (plan == (PlsrAccelPlan_t *)0) + if (plan == (PlsrAccelPlan_t *)0) /* 空plan返回0 */ { - return 0U; + return 0U; /* 没plan没法取频 */ } - const_phase_end = plan->accel_pulses + plan->const_pulses; + const_phase_end = plan->accel_pulses + plan->const_pulses; /* 匀速段末边界 */ - /* 加速相:0 .. accel_pulses-1 完成后仍在加速;completed_seg_pulses 为已完成数 */ - if ((plan->accel_pulses > 0U) && (completed_seg_pulses < plan->accel_pulses) && - (plan->start_freq_hz != plan->target_freq_hz)) + /* 加速相:completed < accel 且起峰不同频 */ + if ((plan->accel_pulses > 0U) && (completed_seg_pulses < plan->accel_pulses) && /* 还在加速相 */ + (plan->start_freq_hz != plan->target_freq_hz)) /* 起峰不同才爬 */ { - freq_rising = (plan->target_freq_hz >= plan->start_freq_hz) ? 1U : 0U; - if (plan->curve_mode == PLSR_ACCEL_LINEAR) + freq_rising = (plan->target_freq_hz >= plan->start_freq_hz) ? 1U : 0U; /* 看峰比起高还是低 */ + if (plan->curve_mode == PLSR_ACCEL_LINEAR) /* 直线走v^2公式 */ { - uint32_t selected_rate_hz_per_s = (freq_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; + /* 升用 accel_rate,降用 decel_rate */ + uint32_t selected_rate_hz_per_s = (freq_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; /* 挑斜率 */ freq_hz = PlsrAccelCurveLinearFreqAtPulse(plan->start_freq_hz, selected_rate_hz_per_s, - completed_seg_pulses, freq_rising, plan->target_freq_hz); + completed_seg_pulses, freq_rising, plan->target_freq_hz); /* 按脉冲序号用平方关系取频 */ } else { - uint32_t selected_rate_hz_per_s = (freq_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; + /* S/正弦:按脉冲序号积分时间再取频 */ + uint32_t selected_rate_hz_per_s = (freq_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; /* 挑斜率 */ freq_hz = PlsrAccelCurveTimedFreqAtPulse( plan->start_freq_hz, @@ -335,42 +332,42 @@ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan, plan->curve_mode, completed_seg_pulses); } - if ((freq_hz < 1U) && (plan->target_freq_hz >= 1U)) + if ((freq_hz < 1U) && (plan->target_freq_hz >= 1U)) /* 算出0但目标有效? */ { - freq_hz = 1U; + freq_hz = 1U; /* 避免 0Hz 写 ARR */ } return PlsrAccelCurveClampFreqHz(freq_hz); } - /* 匀速 */ - if (completed_seg_pulses < const_phase_end) + /* 匀速:保持峰值 */ + if (completed_seg_pulses < const_phase_end) /* 还在匀速区间 */ { - return PlsrAccelCurveClampFreqHz(plan->target_freq_hz); + return PlsrAccelCurveClampFreqHz(plan->target_freq_hz); /* 钉峰值 */ } - /* 减速 / 无减速 */ - if ((plan->decel_pulses == 0U) || (plan->target_freq_hz == plan->end_freq_hz)) + /* 无减速或峰=出口:直接出口频 */ + if ((plan->decel_pulses == 0U) || (plan->target_freq_hz == plan->end_freq_hz)) /* 不用减速 */ { - return PlsrAccelCurveClampFreqHz(plan->end_freq_hz); + return PlsrAccelCurveClampFreqHz(plan->end_freq_hz); /* 直接出口 */ } - pulse_count = completed_seg_pulses - const_phase_end; - if (pulse_count >= plan->decel_pulses) + pulse_count = completed_seg_pulses - const_phase_end; /* 减速相内序号 */ + if (pulse_count >= plan->decel_pulses) /* 减速拍用尽 */ { - return PlsrAccelCurveClampFreqHz(plan->end_freq_hz); + return PlsrAccelCurveClampFreqHz(plan->end_freq_hz); /* 钉出口 */ } - freq_rising = (plan->end_freq_hz >= plan->target_freq_hz) ? 1U : 0U; - if (plan->curve_mode == PLSR_ACCEL_LINEAR) + freq_rising = (plan->end_freq_hz >= plan->target_freq_hz) ? 1U : 0U; /* 减速相:看止比峰高还是低 */ + if (plan->curve_mode == PLSR_ACCEL_LINEAR) /* 直线 */ { - uint32_t selected_rate_hz_per_s = (freq_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; + uint32_t selected_rate_hz_per_s = (freq_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; /* 挑斜率 */ freq_hz = PlsrAccelCurveLinearFreqAtPulse(plan->target_freq_hz, selected_rate_hz_per_s, - pulse_count, freq_rising, plan->end_freq_hz); + pulse_count, freq_rising, plan->end_freq_hz); /* 从峰往止按直线取频 */ } - else + else /* S/正弦 */ { - uint32_t selected_rate_hz_per_s = (freq_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; + uint32_t selected_rate_hz_per_s = (freq_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; /* 挑斜率 */ freq_hz = PlsrAccelCurveTimedFreqAtPulse( plan->target_freq_hz, @@ -379,57 +376,60 @@ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan, plan->curve_mode, pulse_count); } - if (freq_hz < 1U) + if (freq_hz < 1U) /* 兜底别出0Hz */ { - freq_hz = 1U; + freq_hz = 1U; /* 钉成1Hz */ } return PlsrAccelCurveClampFreqHz(freq_hz); } /** * PlanSeg 后预建加/减速表(任务上下文,勿在 ISR 里做)。 + * 直线不建表;S/正弦各相用临时 runtime 仿真填表。 */ void PlsrAccelPrebuildFreqTables(const PlsrAccelPlan_t *plan) { - PlsrAccelRuntime_t temporary_runtime; + PlsrAccelRuntime_t temporary_runtime; /* 临时跑一相,用来填表 */ - s_accel_table_length = 0U; - s_decel_table_length = 0U; - s_accel_table_stride = 1U; - s_decel_table_stride = 1U; + s_accel_table_length = 0U; /* 清加速表长度 */ + s_decel_table_length = 0U; /* 清减速表长度 */ + s_accel_table_stride = 1U; /* 加速步长先按1 */ + s_decel_table_stride = 1U; /* 减速步长先按1 */ - if ((plan == (const PlsrAccelPlan_t *)0) || - (plan->curve_mode == PLSR_ACCEL_LINEAR)) + if ((plan == (const PlsrAccelPlan_t *)0) || /* 没plan或 */ + (plan->curve_mode == PLSR_ACCEL_LINEAR)) /* 直线模式 */ { - return; + return; /* 直线 ISR 走 NextFreqLinear,无需表 */ } - if ((plan->accel_pulses > 0U) && (plan->start_freq_hz != plan->target_freq_hz)) + /* 加速表:起 → 峰 */ + if ((plan->accel_pulses > 0U) && (plan->start_freq_hz != plan->target_freq_hz)) /* 有加速且起峰不同 */ { - PlsrAccelRuntimeBeginRamp(&temporary_runtime, - plan->start_freq_hz, - plan->target_freq_hz, - plan->accel_pulses, - plan->accel_rate_hz_per_s, - plan->decel_rate_hz_per_s, - plan->curve_mode); - s_accel_table_length = PlsrAccelRuntimeBuildFreqTable(&temporary_runtime, s_accel_freq_table, - PLSR_RAMP_TBL_MAX, - &s_accel_table_stride); + PlsrAccelRuntimeBeginRamp(&temporary_runtime, /* 开临时加速相 */ + plan->start_freq_hz, /* 起→峰 */ + plan->target_freq_hz, /* 到峰 */ + plan->accel_pulses, /* 加速总拍数 */ + plan->accel_rate_hz_per_s, /* 加速斜率 */ + plan->decel_rate_hz_per_s, /* 减速斜率也带上(方向里头会选) */ + plan->curve_mode); /* 曲线模式 */ + s_accel_table_length = PlsrAccelRuntimeBuildFreqTable(&temporary_runtime, s_accel_freq_table, /* 仿真整相写进加速表 */ + PLSR_RAMP_TBL_MAX, /* 表容量上限 */ + &s_accel_table_stride); /* 抽样步长写回 */ } - if ((plan->decel_pulses > 0U) && (plan->target_freq_hz != plan->end_freq_hz)) + /* 减速表:峰 → 止 */ + if ((plan->decel_pulses > 0U) && (plan->target_freq_hz != plan->end_freq_hz)) /* 有减速且峰止不同 */ { - PlsrAccelRuntimeBeginRamp(&temporary_runtime, - plan->target_freq_hz, - plan->end_freq_hz, - plan->decel_pulses, - plan->accel_rate_hz_per_s, - plan->decel_rate_hz_per_s, - plan->curve_mode); - s_decel_table_length = PlsrAccelRuntimeBuildFreqTable(&temporary_runtime, s_decel_freq_table, - PLSR_RAMP_TBL_MAX, - &s_decel_table_stride); + PlsrAccelRuntimeBeginRamp(&temporary_runtime, /* 开临时减速相 */ + plan->target_freq_hz, /* 峰→止 */ + plan->end_freq_hz, /* 到止 */ + plan->decel_pulses, /* 减速总拍数 */ + plan->accel_rate_hz_per_s, /* 斜率 */ + plan->decel_rate_hz_per_s, /* 斜率 */ + plan->curve_mode); /* 模式 */ + s_decel_table_length = PlsrAccelRuntimeBuildFreqTable(&temporary_runtime, s_decel_freq_table, /* 仿真写进减速表 */ + PLSR_RAMP_TBL_MAX, /* 容量 */ + &s_decel_table_stride); /* 步长写回 */ } } @@ -437,199 +437,202 @@ void PlsrAccelPrebuildFreqTables(const PlsrAccelPlan_t *plan) void PlsrAccelBeginAccel(PlsrAccelRuntime_t *runtime, const PlsrAccelPlan_t *plan) { - if ((runtime == (PlsrAccelRuntime_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) - { - return; - } - PlsrAccelRuntimeBeginRamp(runtime, - plan->start_freq_hz, - plan->target_freq_hz, - plan->accel_pulses, - plan->accel_rate_hz_per_s, - plan->decel_rate_hz_per_s, - plan->curve_mode); - PlsrAccelRuntimeSelectFreqTable(runtime, 1U, s_accel_table_length, - s_accel_table_stride); + if ((runtime == (PlsrAccelRuntime_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) /* 指针检查 */ + { + return; /* 缺谁都不开相 */ + } + PlsrAccelRuntimeBeginRamp(runtime, /* 填运行态:起→峰 */ + plan->start_freq_hz, /* 入口频 */ + plan->target_freq_hz, /* 峰值 */ + plan->accel_pulses, /* 加速拍预算 */ + plan->accel_rate_hz_per_s, /* 加速斜率 */ + plan->decel_rate_hz_per_s, /* 减速斜率 */ + plan->curve_mode); /* 曲线模式 */ + PlsrAccelRuntimeSelectFreqTable(runtime, 1U, s_accel_table_length, /* 绑加速预建表 id=1 */ + s_accel_table_stride); /* 步长一起绑 */ } /** @brief 进入减速相 */ void PlsrAccelBeginDecel(PlsrAccelRuntime_t *runtime, const PlsrAccelPlan_t *plan) { - if ((runtime == (PlsrAccelRuntime_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) + if ((runtime == (PlsrAccelRuntime_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) /* 指针检查 */ { - return; + return; /* 缺谁都不开相 */ } - PlsrAccelRuntimeBeginRamp(runtime, - plan->target_freq_hz, - plan->end_freq_hz, - plan->decel_pulses, - plan->accel_rate_hz_per_s, - plan->decel_rate_hz_per_s, - plan->curve_mode); + PlsrAccelRuntimeBeginRamp(runtime, /* 填运行态:峰→止 */ + plan->target_freq_hz, /* 从峰 */ + plan->end_freq_hz, /* 到止 */ + plan->decel_pulses, /* 减速拍预算 */ + plan->accel_rate_hz_per_s, /* 斜率 */ + plan->decel_rate_hz_per_s, /* 斜率 */ + plan->curve_mode); /* 模式 */ /* 表已在 PlanSeg/Prebuild 填好;ISR 内禁止再建表 */ - PlsrAccelRuntimeSelectFreqTable(runtime, 2U, s_decel_table_length, - s_decel_table_stride); + PlsrAccelRuntimeSelectFreqTable(runtime, 2U, s_decel_table_length, /* 绑减速预建表 id=2 */ + s_decel_table_stride); /* 步长一起绑 */ } /** @brief 进入匀速相 */ void PlsrAccelBeginConstSpeed(PlsrAccelRuntime_t *runtime, const PlsrAccelPlan_t *plan) { - if ((runtime == (PlsrAccelRuntime_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) - { - return; - } - runtime->start_freq_hz = plan->target_freq_hz; - runtime->end_freq_hz = plan->target_freq_hz; - runtime->cur_freq_hz = plan->target_freq_hz; - runtime->accel_hz_per_s = 0U; - runtime->completed_pulses = 0U; - runtime->total_pulses = plan->const_pulses; - runtime->freq_rising = 1U; - runtime->curve_mode = plan->curve_mode; + if ((runtime == (PlsrAccelRuntime_t *)0) || (plan == (const PlsrAccelPlan_t *)0)) /* 指针检查 */ + { + return; /* 缺谁都不开相 */ + } + runtime->start_freq_hz = plan->target_freq_hz; /* 起点钉峰值 */ + runtime->end_freq_hz = plan->target_freq_hz; /* 终点也是峰值 */ + runtime->cur_freq_hz = plan->target_freq_hz; /* 当前频=峰 */ + runtime->accel_hz_per_s = 0U; /* 斜率清零:不改频 */ + runtime->completed_pulses = 0U; /* 匀速相计数清零 */ + runtime->total_pulses = plan->const_pulses; /* 匀速总拍数 */ + runtime->freq_rising = 1U; /* 方向随便填,反正不爬 */ + runtime->curve_mode = plan->curve_mode; /* 模式照抄 */ runtime->is_active = 0U; /* 匀速:ISR 不改频 */ - runtime->freq_table_id = 0U; - runtime->table_length = 0U; - runtime->table_stride = 1U; - runtime->elapsed_time_us = 0U; - runtime->jerk_time_us = 0U; - runtime->const_accel_time_us = 0U; - runtime->ramp_time_us = 0U; + runtime->freq_table_id = 0U; /* 不用频率表 */ + runtime->table_length = 0U; /* 表长0 */ + runtime->table_stride = 1U; /* 步长无关 */ + runtime->elapsed_time_us = 0U; /* 时间清零 */ + runtime->jerk_time_us = 0U; /* 加加速度阶段时间清零 */ + runtime->const_accel_time_us = 0U; /* 恒加速时间清零 */ + runtime->ramp_time_us = 0U; /* 斜坡总时间清零 */ } /** - * @brief ISR 热路径:本相再前进 1 脉冲,返回下一拍应写入 ARR 的频率 + * @brief ISR 里走:本相再往前一拍,返回下一拍该写成多大频率 + * 分支:直线逼近 / 查预建表 / 建表失败则按时间一步步算;末拍前避免提前钉死到终点频。 */ uint32_t PlsrAccelNextFreq(PlsrAccelRuntime_t *runtime) { - const uint32_t *freq_table; - uint32_t table_index; + const uint32_t *freq_table; /* 指向加速表或减速表 */ + uint32_t table_index; /* 表下标 */ - if (runtime == (PlsrAccelRuntime_t *)0) + if (runtime == (PlsrAccelRuntime_t *)0) /* 空指针 */ { - return 0U; + return 0U; /* 没runtime返回0 */ } - if (runtime->is_active == 0U) + if (runtime->is_active == 0U) /* 相已停 */ { - return PlsrAccelCurveClampFreqHz(runtime->cur_freq_hz); + return PlsrAccelCurveClampFreqHz(runtime->cur_freq_hz); /* 已停相:保持 */ } - if (runtime->completed_pulses < 0xFFFFFFFFUL) + if (runtime->completed_pulses < 0xFFFFFFFFUL) /* 防溢出再加拍 */ { - runtime->completed_pulses++; + runtime->completed_pulses++; /* 本相已完成拍数+1 */ } - if (runtime->curve_mode == PLSR_ACCEL_LINEAR) + if (runtime->curve_mode == PLSR_ACCEL_LINEAR) /* 直线模式 */ { - if (runtime->accel_hz_per_s == 0U) + if (runtime->accel_hz_per_s == 0U) /* 斜率为0 */ { - runtime->cur_freq_hz = runtime->end_freq_hz; + runtime->cur_freq_hz = runtime->end_freq_hz; /* a=0:阶跃到终点 */ } else { - runtime->cur_freq_hz = PlsrAccelNextFreqLinear(runtime); + runtime->cur_freq_hz = PlsrAccelNextFreqLinear(runtime); /* 用平方目标±1逼近下一频 */ } } - else if (runtime->freq_table_id != 0U) + else if (runtime->freq_table_id != 0U) /* 有预建表 */ { - /* ISR 热路径:只查表,不做 S/正弦实时积分 */ - if (runtime->table_length < 1U) + /* ISR 里只查表,不做 S/正弦实时积分(算太慢) */ + if (runtime->table_length < 1U) /* 表空了? */ { - runtime->cur_freq_hz = runtime->end_freq_hz; + runtime->cur_freq_hz = runtime->end_freq_hz; /* 直接钉终点 */ } else { - uint32_t table_stride = (runtime->table_stride < 1U) ? - 1U : runtime->table_stride; + uint32_t table_stride = (runtime->table_stride < 1U) ? /* 步长至少1 */ + 1U : runtime->table_stride; /* 防0步长 */ - table_index = (runtime->completed_pulses - 1U) / table_stride; - if (table_index >= runtime->table_length) + table_index = (runtime->completed_pulses - 1U) / table_stride; /* completed从1起,除步长得下标 */ + if (table_index >= runtime->table_length) /* 越界? */ { - table_index = runtime->table_length - 1U; + table_index = runtime->table_length - 1U; /* 夹到最后一项 */ } - freq_table = (runtime->freq_table_id == 1U) ? - s_accel_freq_table : - s_decel_freq_table; - runtime->cur_freq_hz = freq_table[table_index]; + freq_table = (runtime->freq_table_id == 1U) ? /* 1=加速表,其它=减速表 */ + s_accel_freq_table : /* 加速频率表 */ + s_decel_freq_table; /* 减速频率表 */ + runtime->cur_freq_hz = freq_table[table_index]; /* 查表得本拍频率 */ } } else { /* 建表失败兜底:仍走时间步进 */ - runtime->cur_freq_hz = PlsrAccelNextFreqTimed(runtime); + runtime->cur_freq_hz = PlsrAccelNextFreqTimed(runtime); /* 时间域取下一频 */ } - if ((runtime->total_pulses > 0U) && (runtime->completed_pulses >= runtime->total_pulses)) + /* 本相脉冲用尽:钉终点并停相 */ + if ((runtime->total_pulses > 0U) && (runtime->completed_pulses >= runtime->total_pulses)) /* 拍数用尽? */ { - runtime->cur_freq_hz = runtime->end_freq_hz; - runtime->is_active = 0U; + runtime->cur_freq_hz = runtime->end_freq_hz; /* 钉到本相终点频 */ + runtime->is_active = 0U; /* 停相 */ } - else if (runtime->curve_mode == PLSR_ACCEL_LINEAR) + else if (runtime->curve_mode == PLSR_ACCEL_LINEAR) /* 直线未用尽 */ { /* * 未到本相最后一拍:不要钳到 end。 * 否则减速在 n=N-1 就落到止速,ARPE 下会表现为末两拍同频。 */ - if (runtime->freq_rising == 0U) + if (runtime->freq_rising == 0U) /* 往下掉频 */ { - if ((runtime->cur_freq_hz <= runtime->end_freq_hz) && - (runtime->end_freq_hz < 100000U)) + if ((runtime->cur_freq_hz <= runtime->end_freq_hz) && /* 已经碰到或越过终点 */ + (runtime->end_freq_hz < 100000U)) /* 终点还没顶到100k */ { - runtime->cur_freq_hz = runtime->end_freq_hz + 1U; + runtime->cur_freq_hz = runtime->end_freq_hz + 1U; /* 故意高1Hz,末拍再落地 */ } } - else if ((runtime->cur_freq_hz >= runtime->end_freq_hz) && - (runtime->end_freq_hz > 1U) && - (runtime->total_pulses > 0U) && - (runtime->completed_pulses < runtime->total_pulses)) + else if ((runtime->cur_freq_hz >= runtime->end_freq_hz) && /* 往上爬且已到/过终点 */ + (runtime->end_freq_hz > 1U) && /* 终点不是1 */ + (runtime->total_pulses > 0U) && /* 还有总拍数 */ + (runtime->completed_pulses < runtime->total_pulses)) /* 还没到最后一拍 */ { - runtime->cur_freq_hz = runtime->end_freq_hz - 1U; + runtime->cur_freq_hz = runtime->end_freq_hz - 1U; /* 故意低1Hz,别提前钉死 */ } } - else if (runtime->freq_table_id != 0U) + else if (runtime->freq_table_id != 0U) /* 查表路径同样处理 */ { /* 查表:最后一拍之前若已是 end,同样让出 1Hz */ - if ((runtime->total_pulses > 0U) && - (runtime->completed_pulses < runtime->total_pulses)) + if ((runtime->total_pulses > 0U) && /* 还没跑完本相 */ + (runtime->completed_pulses < runtime->total_pulses)) /* 未到最后一拍 */ { - if (runtime->freq_rising == 0U) + if (runtime->freq_rising == 0U) /* 往下掉 */ { - if ((runtime->cur_freq_hz <= runtime->end_freq_hz) && - (runtime->end_freq_hz < 100000U)) + if ((runtime->cur_freq_hz <= runtime->end_freq_hz) && /* 已经<=终点 */ + (runtime->end_freq_hz < 100000U)) /* 终点未顶格 */ { - runtime->cur_freq_hz = runtime->end_freq_hz + 1U; + runtime->cur_freq_hz = runtime->end_freq_hz + 1U; /* 让出1Hz */ } } - else if ((runtime->cur_freq_hz >= runtime->end_freq_hz) && - (runtime->end_freq_hz > 1U)) + else if ((runtime->cur_freq_hz >= runtime->end_freq_hz) && /* 往上爬已>=终点 */ + (runtime->end_freq_hz > 1U)) /* 终点有效 */ { - runtime->cur_freq_hz = runtime->end_freq_hz - 1U; + runtime->cur_freq_hz = runtime->end_freq_hz - 1U; /* 让出1Hz */ } } } - else if (runtime->freq_table_id == 0U) + else if (runtime->freq_table_id == 0U) /* 时间步进兜底 */ { - if ((runtime->ramp_time_us > 0U) && (runtime->elapsed_time_us >= runtime->ramp_time_us)) + /* 时间步进路径:到时或越过终点则停 */ + if ((runtime->ramp_time_us > 0U) && (runtime->elapsed_time_us >= runtime->ramp_time_us)) /* 时间到了斜坡总时间 */ { - runtime->cur_freq_hz = runtime->end_freq_hz; - runtime->is_active = 0U; + runtime->cur_freq_hz = runtime->end_freq_hz; /* 钉终点 */ + runtime->is_active = 0U; /* 停相 */ } - else if (runtime->freq_rising != 0U) + else if (runtime->freq_rising != 0U) /* 往上爬 */ { - if (runtime->cur_freq_hz >= runtime->end_freq_hz) + if (runtime->cur_freq_hz >= runtime->end_freq_hz) /* 频已到终点 */ { - runtime->cur_freq_hz = runtime->end_freq_hz; - runtime->is_active = 0U; + runtime->cur_freq_hz = runtime->end_freq_hz; /* 钉终点 */ + runtime->is_active = 0U; /* 停相 */ } } - else if (runtime->cur_freq_hz <= runtime->end_freq_hz) + else if (runtime->cur_freq_hz <= runtime->end_freq_hz) /* 往下掉且已到/过终点 */ { - runtime->cur_freq_hz = runtime->end_freq_hz; - runtime->is_active = 0U; + runtime->cur_freq_hz = runtime->end_freq_hz; /* 钉终点 */ + runtime->is_active = 0U; /* 停相 */ } } - return PlsrAccelCurveClampFreqHz(runtime->cur_freq_hz); + return PlsrAccelCurveClampFreqHz(runtime->cur_freq_hz); /* 最后钳一次再返回 */ } /*============================================================================*/ @@ -639,46 +642,46 @@ uint32_t PlsrAccelNextFreq(PlsrAccelRuntime_t *runtime) /* 频率大于 100k 时暂时钳到 100k;启动门禁另报 0x04 */ static uint32_t PlsrAccelCurveClampFreqHz(uint32_t freq_hz) { - if (freq_hz > 100000U) + if (freq_hz > 100000U) /* 超100k就砍 */ { - freq_hz = 100000U; + freq_hz = 100000U; /* 钉100k */ } - return freq_hz; + return freq_hz; /* 返回钳后值 */ } /** @brief 两个无符号数之间的距离 */ static uint32_t PlsrAccelCurveAbsDiff(uint32_t first_val, uint32_t second_val) { - return (first_val >= second_val) ? - (first_val - second_val) : (second_val - first_val); + return (first_val >= second_val) ? /* 大减小,保证非负差 */ + (first_val - second_val) : (second_val - first_val); /* 谁大谁当被减数 */ } /** 64 位整数平方根(牛顿法),支持 freq_hz^2 + 2an */ static uint32_t PlsrAccelCurveIntSqrt(uint64_t squared_freq) { - uint64_t estimate; - uint64_t next_estimate; - uint32_t loop_index; + uint64_t estimate; /* 当前估计 */ + uint64_t next_estimate; /* 下一步估计 */ + uint32_t loop_index; /* 迭代次数 */ - if (squared_freq <= 1ULL) + if (squared_freq <= 1ULL) /* 0或1开方就是自己 */ { - return (uint32_t)squared_freq; + return (uint32_t)squared_freq; /* 直接回 */ } - estimate = squared_freq; - if (estimate > 100000ULL) + estimate = squared_freq; /* 初值先用原数 */ + if (estimate > 100000ULL) /* 太大就从100k起迭代 */ { - estimate = 100000ULL; + estimate = 100000ULL; /* 缩小初值 */ } - for (loop_index = 0U; loop_index < 40U; loop_index++) + for (loop_index = 0U; loop_index < 40U; loop_index++) /* 牛顿迭代最多40轮 */ { - next_estimate = (estimate + squared_freq / estimate) / 2ULL; - if (next_estimate >= estimate) + next_estimate = (estimate + squared_freq / estimate) / 2ULL; /* estimate = (x + n/x)/2 */ + if (next_estimate >= estimate) /* 不再变小就停 */ { - break; + break; /* 收敛了 */ } - estimate = next_estimate; + estimate = next_estimate; /* 继续收紧 */ } - return (uint32_t)estimate; + return (uint32_t)estimate; /* 整数部分开方结果 */ } /** @@ -687,15 +690,15 @@ static uint32_t PlsrAccelCurveIntSqrt(uint64_t squared_freq) */ static uint32_t PlsrAccelCurveRateFromDefaultSpeed(uint32_t default_speed_hz, uint32_t ramp_time_ms) { - if (ramp_time_ms == 0U) + if (ramp_time_ms == 0U) /* 时间为0:斜率0(阶跃) */ { - return 0U; + return 0U; /* a=0 */ } - if (default_speed_hz == 0U) + if (default_speed_hz == 0U) /* 默认速度没配 */ { - return 0U; + return 0U; /* 也当0 */ } - return (default_speed_hz * 1000UL) / ramp_time_ms; + return (default_speed_hz * 1000UL) / ramp_time_ms; /* a=默认速度*1000/斜坡毫秒,单位Hz/s */ } /** 按默认速度计算变化率;默认速度未配置时用本段频差计算。 */ @@ -704,22 +707,22 @@ static uint32_t PlsrAccelCurveCalcRate(uint32_t default_speed_hz, uint32_t end_freq_hz, uint32_t ramp_time_ms) { - uint32_t rate_hz_per_s; - uint32_t freq_diff_hz; + uint32_t rate_hz_per_s; /* 算出来的斜率 */ + uint32_t freq_diff_hz; /* 本段频差 */ - rate_hz_per_s = PlsrAccelCurveRateFromDefaultSpeed(default_speed_hz, ramp_time_ms); - if ((rate_hz_per_s != 0U) || (ramp_time_ms == 0U)) + rate_hz_per_s = PlsrAccelCurveRateFromDefaultSpeed(default_speed_hz, ramp_time_ms); /* 优先用默认速度那套 */ + if ((rate_hz_per_s != 0U) || (ramp_time_ms == 0U)) /* 有斜率,或时间本来就是0 */ { - return rate_hz_per_s; + return rate_hz_per_s; /* 直接用 */ } freq_diff_hz = - PlsrAccelCurveAbsDiff(start_freq_hz, end_freq_hz); - if (freq_diff_hz == 0U) + PlsrAccelCurveAbsDiff(start_freq_hz, end_freq_hz); /* 没默认速度:改用|起-止| */ + if (freq_diff_hz == 0U) /* 同频? */ { - return 0U; + return 0U; /* 没差就0斜率 */ } - return (freq_diff_hz * 1000UL) / ramp_time_ms; + return (freq_diff_hz * 1000UL) / ramp_time_ms; /* a=频差*1000/毫秒 */ } /** @@ -728,20 +731,20 @@ static uint32_t PlsrAccelCurveCalcRate(uint32_t default_speed_hz, */ static uint32_t PlsrAccelCurveCalcJumpFreq(uint32_t starting_freq_hz, uint32_t accel_hz_per_s) { - uint64_t squared_freq; - uint32_t freq_hz; + uint64_t squared_freq; /* 频率平方累加量 */ + uint32_t freq_hz; /* 开方后的频率 */ - if (accel_hz_per_s == 0U) + if (accel_hz_per_s == 0U) /* a=0:不起跳 */ { - return (starting_freq_hz >= 1U) ? PlsrAccelCurveClampFreqHz(starting_freq_hz) : 1U; + return (starting_freq_hz >= 1U) ? PlsrAccelCurveClampFreqHz(starting_freq_hz) : 1U; /* 有起点用起点,否则1Hz */ } - squared_freq = (uint64_t)starting_freq_hz * (uint64_t)starting_freq_hz + (2ULL * (uint64_t)accel_hz_per_s); - freq_hz = PlsrAccelCurveIntSqrt(squared_freq); - if (freq_hz < 1U) + squared_freq = (uint64_t)starting_freq_hz * (uint64_t)starting_freq_hz + (2ULL * (uint64_t)accel_hz_per_s); /* f^2 = f0^2 + 2a(脉冲域等价) */ + freq_hz = PlsrAccelCurveIntSqrt(squared_freq); /* 开方得起跳频 */ + if (freq_hz < 1U) /* 别出0 */ { - freq_hz = 1U; + freq_hz = 1U; /* 至少1Hz */ } - return PlsrAccelCurveClampFreqHz(freq_hz); + return PlsrAccelCurveClampFreqHz(freq_hz); /* 再钳100k */ } /** @@ -761,105 +764,106 @@ static uint32_t PlsrAccelCurveResolveBoundaryFreq(uint32_t configured_freq_hz, uint32_t decel_time_ms, uint8_t resolving_start) { - uint32_t ramp_time_ms; - uint32_t accel_hz_per_s; - uint32_t jump_freq_hz; + uint32_t ramp_time_ms; /* 用哪侧斜坡时间 */ + uint32_t accel_hz_per_s; /* 峰值加速度对应的斜率 */ + uint32_t jump_freq_hz; /* 起跳频率 */ /* 验证频率是否超过100k */ - configured_freq_hz = PlsrAccelCurveClampFreqHz(configured_freq_hz); - target_freq_hz = PlsrAccelCurveClampFreqHz(target_freq_hz); - if (target_freq_hz < 1U) + configured_freq_hz = PlsrAccelCurveClampFreqHz(configured_freq_hz); /* 配置值钳住 */ + target_freq_hz = PlsrAccelCurveClampFreqHz(target_freq_hz); /* 目标钳住 */ + if (target_freq_hz < 1U) /* 目标无效 */ { - return 1U; + return 1U; /* 至少给1Hz出口/入口 */ } - /* 配置起始速度/终止止速 > 目标频率:用配置速度 */ - if (configured_freq_hz > target_freq_hz) + /* 配置起/止 > 目标:直接用配置(高位进/出) */ + if (configured_freq_hz > target_freq_hz) /* 配置比目标还高 */ { - return configured_freq_hz; + return configured_freq_hz; /* 高位进/出,不用起跳 */ } - ramp_time_ms = (resolving_start != 0U) ? accel_time_ms : decel_time_ms; - /*计算加速度*/ + ramp_time_ms = (resolving_start != 0U) ? accel_time_ms : decel_time_ms; /* 起用加速时间,止用减速时间 */ + /* a 与 Plan 同式,保证起跳与斜坡一致 */ accel_hz_per_s = - PlsrAccelCurveCalcRate(default_speed_hz, - configured_freq_hz, - target_freq_hz, - ramp_time_ms); - if (accel_hz_per_s == 0U) + PlsrAccelCurveCalcRate(default_speed_hz, /* 按同Plan公式算a */ + configured_freq_hz, /* 从配置频 */ + target_freq_hz, /* 到目标 */ + ramp_time_ms); /* 斜坡毫秒 */ + if (accel_hz_per_s == 0U) /* a=0 */ { - return (configured_freq_hz >= 1U) ? configured_freq_hz : target_freq_hz; + return (configured_freq_hz >= 1U) ? configured_freq_hz : target_freq_hz; /* 有配置用配置,否则用目标 */ } - /*按运动学公式计算起跳频率*/ - jump_freq_hz = PlsrAccelCurveCalcJumpFreq(configured_freq_hz, accel_hz_per_s); + /* jump = sqrt(f0^2 + 2a);配置为 0 时即 sqrt(2a) */ + jump_freq_hz = PlsrAccelCurveCalcJumpFreq(configured_freq_hz, accel_hz_per_s); /* 算起跳:sqrt(f0^2+2a) */ - /* 目标 < 起跳 → 用目标;目标 >= 起跳 → 用起跳 */ - if (target_freq_hz < jump_freq_hz) + /* 目标 < 起跳 → 用目标;否则用起跳 */ + if (target_freq_hz < jump_freq_hz) /* 目标比起跳还低 */ { - return target_freq_hz; + return target_freq_hz; /* 没必要从起跳起,用目标 */ } - return jump_freq_hz; + return jump_freq_hz; /* 否则用起跳频 */ } -/*线性插值*/ +/** 千分比线性插值:ratio=0→start,ratio≥1000→end */ static uint32_t PlsrAccelCurveInterpolate(uint32_t start_val, uint32_t end_val, uint32_t ratio_permille) { - if (ratio_permille >= 1000U) + if (ratio_permille >= 1000U) /* 进度>=1000 */ { - return end_val; + return end_val; /* 直接终点 */ } - if (end_val >= start_val) + if (end_val >= start_val) /* 终点>=起点:往上插 */ { - return start_val + - ((end_val - start_val) * ratio_permille) / 1000UL; + return start_val + /* start + 差*千分比 */ + ((end_val - start_val) * ratio_permille) / 1000UL; /* 按千分比摊 */ } - return start_val - - ((start_val - end_val) * ratio_permille) / 1000UL; -} + return start_val - /* 往下插 */ + ((start_val - end_val) * ratio_permille) / 1000UL; /* start - 差*千分比 */ +} /* 按千分比摊 */ /*============================================================================*/ /* 直线 */ /*============================================================================*/ /** - * 脉冲闭合:N = ceil(|end_freq_hz^2 - start_freq_hz^2| / (2a))。 + * 脉冲闭合:N = ceil(|end² - start²| / (2a))。 * a=0 且频差非 0 → 0(阶跃,无斜坡脉冲)。 */ static uint32_t PlsrAccelCurveCalcLinearRampPulses(uint32_t start_freq_hz, uint32_t end_freq_hz, uint32_t accel_hz_per_s) { - uint64_t start_freq_squared; - uint64_t end_freq_squared; - uint64_t squared_freq_diff; - uint64_t twice_accel; - uint64_t pulse_count; + uint64_t start_freq_squared; /* 起点频率平方 */ + uint64_t end_freq_squared; /* 终点频率平方 */ + uint64_t squared_freq_diff; /* |f1^2-f0^2| */ + uint64_t twice_accel; /* 2a */ + uint64_t pulse_count; /* 要几拍 */ - if (start_freq_hz == end_freq_hz) + if (start_freq_hz == end_freq_hz) /* 同频:0拍 */ { - return 0U; + return 0U; /* 不用爬 */ } - if (accel_hz_per_s == 0U) + if (accel_hz_per_s == 0U) /* a=0 */ { - return 0U; + return 0U; /* 阶跃 */ } - start_freq_squared = (uint64_t)start_freq_hz * (uint64_t)start_freq_hz; - end_freq_squared = (uint64_t)end_freq_hz * (uint64_t)end_freq_hz; - squared_freq_diff = (end_freq_squared > start_freq_squared) ? (end_freq_squared - start_freq_squared) : (start_freq_squared - end_freq_squared); - twice_accel = 2ULL * (uint64_t)accel_hz_per_s; - pulse_count = (squared_freq_diff + twice_accel - 1ULL) / twice_accel; - if (pulse_count == 0ULL) + start_freq_squared = (uint64_t)start_freq_hz * (uint64_t)start_freq_hz; /* f0^2 */ + end_freq_squared = (uint64_t)end_freq_hz * (uint64_t)end_freq_hz; /* f1^2 */ + squared_freq_diff = (end_freq_squared > start_freq_squared) ? (end_freq_squared - start_freq_squared) : (start_freq_squared - end_freq_squared); /* 平方差取绝对值 */ + twice_accel = 2ULL * (uint64_t)accel_hz_per_s; /* 分母2a */ + /* ceil(Δ(f²) / (2a)) */ + pulse_count = (squared_freq_diff + twice_accel - 1ULL) / twice_accel; /* 向上取整:差多少平方要除2a */ + if (pulse_count == 0ULL) /* 算成0? */ { - pulse_count = 1ULL; - } + pulse_count = 1ULL; /* 至少1拍 */ + } /* 超32位? */ if (pulse_count > 0xFFFFFFFFULL) - { + { /* 钉满 */ return 0xFFFFFFFFUL; } - return (uint32_t)pulse_count; + return (uint32_t)pulse_count; /* 回拍数 */ } /** 直线:freq_hz = sqrt(start_freq_hz^2 + 2*a*pulse_count),升到/降到不超过 target_limit_hz 方向 */ @@ -867,163 +871,167 @@ static uint32_t PlsrAccelCurveLinearFreqAtPulse(uint32_t start_freq_hz, uint32_t uint32_t pulse_count, uint8_t freq_rising, uint32_t target_limit_hz) { - uint64_t squared_freq; - uint32_t freq_hz; + uint64_t squared_freq; /* 当前频率平方 */ + uint32_t freq_hz; /* 算得频率 */ - if (pulse_count == 0U) + if (pulse_count == 0U) /* 第0拍:还在起点 */ { - freq_hz = start_freq_hz; + freq_hz = start_freq_hz; /* 频率=起点 */ } - else if (accel_hz_per_s == 0U) + else if (accel_hz_per_s == 0U) /* a=0:一步到位 */ { - freq_hz = target_limit_hz; + freq_hz = target_limit_hz; /* 直接目标限 */ } else { - squared_freq = (uint64_t)start_freq_hz * (uint64_t)start_freq_hz; - if (freq_rising != 0U) + squared_freq = (uint64_t)start_freq_hz * (uint64_t)start_freq_hz; /* 先放f0^2 */ + if (freq_rising != 0U) /* 往上爬 */ { - squared_freq += 2ULL * (uint64_t)accel_hz_per_s * (uint64_t)pulse_count; - freq_hz = PlsrAccelCurveIntSqrt(squared_freq); - if (freq_hz > target_limit_hz) + squared_freq += 2ULL * (uint64_t)accel_hz_per_s * (uint64_t)pulse_count; /* f^2 = f0^2 + 2*a*n */ + freq_hz = PlsrAccelCurveIntSqrt(squared_freq); /* 开方 */ + if (freq_hz > target_limit_hz) /* 别超过上限 */ { - freq_hz = target_limit_hz; + freq_hz = target_limit_hz; /* 钳到目标限 */ } } - else + else /* 往下掉 */ { - uint64_t freq_drop = 2ULL * (uint64_t)accel_hz_per_s * (uint64_t)pulse_count; - if (freq_drop >= squared_freq) + uint64_t freq_drop = 2ULL * (uint64_t)accel_hz_per_s * (uint64_t)pulse_count; /* 要减掉的平方量 2*a*n */ + if (freq_drop >= squared_freq) /* 减穿了? */ { - freq_hz = target_limit_hz; + freq_hz = target_limit_hz; /* 落到目标限 */ } else { - freq_hz = PlsrAccelCurveIntSqrt(squared_freq - freq_drop); - if (freq_hz < target_limit_hz) + freq_hz = PlsrAccelCurveIntSqrt(squared_freq - freq_drop); /* f = sqrt(f0^2 - 2an) */ + if (freq_hz < target_limit_hz) /* 别低于下限 */ { - freq_hz = target_limit_hz; + freq_hz = target_limit_hz; /* 钳到目标限 */ } } } } - if (freq_hz < 1U) + if (freq_hz < 1U) /* 别出0 */ { - freq_hz = 1U; + freq_hz = 1U; /* 至少1 */ } - return PlsrAccelCurveClampFreqHz(freq_hz); + return PlsrAccelCurveClampFreqHz(freq_hz); /* 钳100k返回 */ } /** - * 直线:用上一拍 freq_hz ±1 逼近 target_freq_squared,不全量开方。 - * 低频 freq_diff_hz/dn 大时循环次数多,但周期也长,ISR 仍可承受。 + * 直线:用上一拍 freq ±1 逼近 target_freq_squared,不全量开方。 + * 目标:f^2 = start^2 ± 2*a*n;低频 df/dn 大时循环多,但周期也长。 */ static uint32_t PlsrAccelNextFreqLinear(PlsrAccelRuntime_t *runtime) { - uint64_t target_freq_squared; - uint64_t cur_freq_squared; - uint64_t start_freq_squared; - uint32_t freq_hz; - uint32_t iteration_guard; + uint64_t target_freq_squared; /* 本拍目标f^2 */ + uint64_t cur_freq_squared; /* 试探频的平方 */ + uint64_t start_freq_squared; /* 起点平方 */ + uint32_t freq_hz; /* 试探频率 */ + uint32_t iteration_guard; /* 循环保险丝,防死转 */ - start_freq_squared = (uint64_t)runtime->start_freq_hz * (uint64_t)runtime->start_freq_hz; - if (runtime->freq_rising != 0U) + /* 本拍应逼近的频率平方 */ + start_freq_squared = (uint64_t)runtime->start_freq_hz * (uint64_t)runtime->start_freq_hz; /* 起点f^2 */ + if (runtime->freq_rising != 0U) /* 往上爬 */ { - target_freq_squared = start_freq_squared + (2ULL * (uint64_t)runtime->accel_hz_per_s * (uint64_t)runtime->completed_pulses); + target_freq_squared = start_freq_squared + (2ULL * (uint64_t)runtime->accel_hz_per_s * (uint64_t)runtime->completed_pulses); /* 目标f^2 = f0^2 + 2*a*n */ } - else + else /* 往下掉 */ { - uint64_t freq_drop = 2ULL * (uint64_t)runtime->accel_hz_per_s * (uint64_t)runtime->completed_pulses; - target_freq_squared = (freq_drop >= start_freq_squared) ? 0ULL : (start_freq_squared - freq_drop); + uint64_t freq_drop = 2ULL * (uint64_t)runtime->accel_hz_per_s * (uint64_t)runtime->completed_pulses; /* 要减的平方量 */ + target_freq_squared = (freq_drop >= start_freq_squared) ? 0ULL : (start_freq_squared - freq_drop); /* 减穿就目标0,否则f0^2-2an */ } - freq_hz = runtime->cur_freq_hz; - if (freq_hz < 1U) + freq_hz = runtime->cur_freq_hz; /* 从上一拍频率起步 */ + if (freq_hz < 1U) /* 保护 */ { - freq_hz = 1U; + freq_hz = 1U; /* 至少1 */ } - for (iteration_guard = 0U; iteration_guard < 2048U; iteration_guard++) + /* 从当前频逐步 ±1,直到最贴近 target_freq_squared */ + for (iteration_guard = 0U; iteration_guard < 2048U; iteration_guard++) /* 最多试2048次±1 */ { - cur_freq_squared = (uint64_t)freq_hz * (uint64_t)freq_hz; - if (runtime->freq_rising != 0U) + cur_freq_squared = (uint64_t)freq_hz * (uint64_t)freq_hz; /* 当前试探的f^2 */ + if (runtime->freq_rising != 0U) /* 升频分支 */ { - if ((freq_hz < runtime->end_freq_hz) && (((uint64_t)(freq_hz + 1U) * (uint64_t)(freq_hz + 1U)) <= target_freq_squared)) + if ((freq_hz < runtime->end_freq_hz) && (((uint64_t)(freq_hz + 1U) * (uint64_t)(freq_hz + 1U)) <= target_freq_squared)) /* 还能往上且(f+1)^2还没超过目标 */ { - freq_hz++; - continue; + freq_hz++; /* 频+1 */ + continue; /* 再试 */ } - if ((freq_hz > 1U) && (cur_freq_squared > target_freq_squared)) + if ((freq_hz > 1U) && (cur_freq_squared > target_freq_squared)) /* 偏高了往回退 */ { - freq_hz--; - continue; + freq_hz--; /* 频-1 */ + continue; /* 再试 */ } - break; + break; /* 贴住了,收工 */ } - else + else /* 降频分支 */ { - if ((freq_hz > runtime->end_freq_hz) && (cur_freq_squared > target_freq_squared)) + if ((freq_hz > runtime->end_freq_hz) && (cur_freq_squared > target_freq_squared)) /* 还能往下且当前平方还大于目标 */ { - freq_hz--; - continue; + freq_hz--; /* 频-1 */ + continue; /* 再试 */ } - if ((freq_hz < 100000U) && - (((uint64_t)(freq_hz + 1U) * (uint64_t)(freq_hz + 1U)) < target_freq_squared)) + if ((freq_hz < 100000U) && /* 偏低了往上补 */ + (((uint64_t)(freq_hz + 1U) * (uint64_t)(freq_hz + 1U)) < target_freq_squared)) /* (f+1)^2仍小于目标 */ { - freq_hz++; - continue; + freq_hz++; /* 频+1 */ + continue; /* 再试 */ } - break; + break; /* 贴住了 */ } } - if (runtime->freq_rising != 0U) + /* 不超过本相终点 */ + if (runtime->freq_rising != 0U) /* 升频:别超过终点 */ { - if (freq_hz > runtime->end_freq_hz) + if (freq_hz > runtime->end_freq_hz) /* 超了 */ { - freq_hz = runtime->end_freq_hz; + freq_hz = runtime->end_freq_hz; /* 钉终点 */ } } - else + else /* 降频:别低于终点 */ { - if (freq_hz < runtime->end_freq_hz) + if (freq_hz < runtime->end_freq_hz) /* 低了 */ { - freq_hz = runtime->end_freq_hz; + freq_hz = runtime->end_freq_hz; /* 钉终点 */ } } - if (freq_hz < 1U) + if (freq_hz < 1U) /* 保护 */ { - freq_hz = 1U; + freq_hz = 1U; /* 至少1 */ } - return PlsrAccelCurveClampFreqHz(freq_hz); + return PlsrAccelCurveClampFreqHz(freq_hz); /* 钳后返回 */ } /*============================================================================*/ /* S / 正弦 */ /*============================================================================*/ +/** raised-cosine 形状:进度千分比 → 形状千分比(查 33 点表再插值) */ static uint32_t PlsrAccelCurveShapeSinePermille(uint32_t progress_permille) { - uint32_t table_index; - uint32_t seg_progress; - uint32_t min_val; - uint32_t max_val; + uint32_t table_index; /* 表下标 */ + uint32_t seg_progress; /* 段内进度 */ + uint32_t min_val; /* 段左端形状值 */ + uint32_t max_val; /* 段右端形状值 */ - if (progress_permille >= 1000U) + if (progress_permille >= 1000U) /* 进度满了 */ { - return 1000U; + return 1000U; /* 形状也满1000 */ } - /* progress_permille/1000 → 表下标 0..32,相邻点线性插值 */ - table_index = (progress_permille * 32UL) / 1000UL; - if (table_index >= 32U) + /* progress/1000 → 表下标 0..32,相邻点线性插值 */ + table_index = (progress_permille * 32UL) / 1000UL; /* 映射到0..32格 */ + if (table_index >= 32U) /* 末格? */ { - return 1000U; + return 1000U; /* 直接1000 */ } seg_progress = (progress_permille * 32UL) - (table_index * 1000UL); /* 0..999 对应段内进度 */ - min_val = (uint32_t)s_plsr_sine_shape_tab[table_index]; - max_val = (uint32_t)s_plsr_sine_shape_tab[table_index + 1U]; - return min_val + - (((max_val - min_val) * seg_progress) / 1000UL); + min_val = (uint32_t)s_plsr_sine_shape_tab[table_index]; /* 左点 */ + max_val = (uint32_t)s_plsr_sine_shape_tab[table_index + 1U]; /* 右点 */ + return min_val + /* 两点之间按段内进度插 */ + (((max_val - min_val) * seg_progress) / 1000UL); /* 线性摊 */ } /** @@ -1036,198 +1044,199 @@ static void PlsrAccelCurveCalcSCurveTimes(uint32_t start_freq_hz, uint32_t end_f uint32_t *const_accel_time_us_out, uint32_t *ramp_time_us_out) { - uint32_t freq_diff_hz; - uint64_t numerator; - uint64_t denominator; - uint32_t calc_jerk_time_us; + uint32_t freq_diff_hz; /* 起止频差 */ + uint64_t numerator; /* 分子:频差*1e6 */ + uint64_t denominator; /* 分母:3*峰值加速度 */ + uint32_t calc_jerk_time_us; /* 加加速度阶段时间(微秒) */ - *jerk_time_us_out = 0U; - *const_accel_time_us_out = 0U; - *ramp_time_us_out = 0U; + *jerk_time_us_out = 0U; /* 先清零输出 */ + *const_accel_time_us_out = 0U; /* 恒加速阶段清零 */ + *ramp_time_us_out = 0U; /* 斜坡总时间清零 */ - freq_diff_hz = PlsrAccelCurveAbsDiff(start_freq_hz, end_freq_hz); - if ((freq_diff_hz < 1U) || (accel_hz_per_s < 1U)) + freq_diff_hz = PlsrAccelCurveAbsDiff(start_freq_hz, end_freq_hz); /* 算|Δf| */ + if ((freq_diff_hz < 1U) || (accel_hz_per_s < 1U)) /* 没差或没加速度 */ { - return; + return; /* 时间全0返回 */ } /* Tj_us = ceil(freq_diff_hz * 1e6 / (3A)) */ - numerator = (uint64_t)freq_diff_hz * 1000000ULL; - denominator = 3ULL * (uint64_t)accel_hz_per_s; - calc_jerk_time_us = - (uint32_t)((numerator + denominator - 1ULL) / denominator); - if (calc_jerk_time_us < 1U) + numerator = (uint64_t)freq_diff_hz * 1000000ULL; /* 分子=频差*1e6(换成微秒) */ + denominator = 3ULL * (uint64_t)accel_hz_per_s; /* 分母=3*峰值加速度A */ + calc_jerk_time_us = /* Tj=频差/(3*峰值加速度),向上取整,单位微秒 */ + (uint32_t)((numerator + denominator - 1ULL) / denominator); /* ceil除法 */ + if (calc_jerk_time_us < 1U) /* 太小? */ { - calc_jerk_time_us = 1U; + calc_jerk_time_us = 1U; /* 至少1微秒 */ } - *jerk_time_us_out = calc_jerk_time_us; - *const_accel_time_us_out = calc_jerk_time_us * 2U; - *ramp_time_us_out = calc_jerk_time_us * 4U; + *jerk_time_us_out = calc_jerk_time_us; /* 写出加加速度阶段时间Tj */ + *const_accel_time_us_out = calc_jerk_time_us * 2U; /* Ta=2*Tj,恒加速段 */ + *ramp_time_us_out = calc_jerk_time_us * 4U; /* 斜坡总时间T=4*Tj(1+2+1) */ } /** 正弦 raised-cosine:峰值加速度 = A ⇒ T = π·Δf / (2A) */ static void PlsrAccelCurveCalcSineCurveTime(uint32_t start_freq_hz, uint32_t end_freq_hz, uint32_t accel_hz_per_s, uint32_t *ramp_time_us) { - uint32_t freq_diff_hz; - uint64_t numerator; - uint64_t denominator; + uint32_t freq_diff_hz; /* 起止频差 */ + uint64_t numerator; /* 分子 */ + uint64_t denominator; /* 分母 */ - *ramp_time_us = 0U; - freq_diff_hz = PlsrAccelCurveAbsDiff(start_freq_hz, end_freq_hz); - if ((freq_diff_hz < 1U) || (accel_hz_per_s < 1U)) + *ramp_time_us = 0U; /* 先清斜坡总时间 */ + freq_diff_hz = PlsrAccelCurveAbsDiff(start_freq_hz, end_freq_hz); /* 算|Δf| */ + if ((freq_diff_hz < 1U) || (accel_hz_per_s < 1U)) /* 无效就返回 */ { - return; + return; /* 不填时间 */ } /* T_us = ceil(π*freq_diff_hz*1e6 / (2A)),π≈355/113 */ - numerator = (uint64_t)freq_diff_hz * 1000000ULL * 355ULL; - denominator = 2ULL * (uint64_t)accel_hz_per_s * 113ULL; - *ramp_time_us = (uint32_t)((numerator + denominator - 1ULL) / denominator); - if (*ramp_time_us < 1U) + numerator = (uint64_t)freq_diff_hz * 1000000ULL * 355ULL; /* 分子=Δf*1e6*355(π≈355/113) */ + denominator = 2ULL * (uint64_t)accel_hz_per_s * 113ULL; /* 分母=2*A*113 */ + *ramp_time_us = (uint32_t)((numerator + denominator - 1ULL) / denominator); /* 斜坡总时间T=π*频差/(2*峰值加速度),向上取整,单位微秒 */ + if (*ramp_time_us < 1U) /* 太小? */ { - *ramp_time_us = 1U; + *ramp_time_us = 1U; /* 至少1微秒 */ } } /** Δf = A * elapsed_time_us / 1e6 */ static uint32_t PlsrAccelCurveDeltaHzFromAt(uint32_t accel_hz_per_s, uint32_t elapsed_time_us) { - return (uint32_t)(((uint64_t)accel_hz_per_s * (uint64_t)elapsed_time_us) / 1000000ULL); + return (uint32_t)(((uint64_t)accel_hz_per_s * (uint64_t)elapsed_time_us) / 1000000ULL); /* Δf=A*t/1e6,匀加速走过的频差 */ } /** Δf = A * elapsed_time_us^2 / (2 * jerk_time_us * 1e6) — jerk 段 */ static uint32_t PlsrAccelCurveDeltaHzFromJerk(uint32_t accel_hz_per_s, uint32_t elapsed_time_us, uint32_t jerk_time_us) { - uint64_t calc; + uint64_t calc; /* 中间累乘 */ - if ((jerk_time_us < 1U) || (elapsed_time_us < 1U) || (accel_hz_per_s < 1U)) + if ((jerk_time_us < 1U) || (elapsed_time_us < 1U) || (accel_hz_per_s < 1U)) /* 缺参数 */ { - return 0U; + return 0U; /* 变不出频差 */ } /* ((A * t / jerk_time_us) * t) / 2e6 */ - calc = ((uint64_t)accel_hz_per_s * (uint64_t)elapsed_time_us) / (uint64_t)jerk_time_us; - calc = (calc * (uint64_t)elapsed_time_us) / 2000000ULL; - if (calc > 0xFFFFFFFFULL) + calc = ((uint64_t)accel_hz_per_s * (uint64_t)elapsed_time_us) / (uint64_t)jerk_time_us; /* 先 A*t/Tj */ + calc = (calc * (uint64_t)elapsed_time_us) / 2000000ULL; /* 再 *t / 2e6 → ½*(A/Tj)*t² */ + if (calc > 0xFFFFFFFFULL) /* 超32位? */ { - return 0xFFFFFFFFUL; + return 0xFFFFFFFFUL; /* 钉满 */ } - return (uint32_t)calc; + return (uint32_t)calc; /* 这段加加速度爬出的频差 */ } /** - * 时刻 elapsed_time_us 的频率(相对进度 0..freq_diff_hz,再映射到 start_freq_hz→end_freq_hz)。 + * S 曲线时刻取频:jerk↑ → 恒 a → jerk↓,Δf 再映射到 start→end。 + * 公式:jerk 段 ½(A/Tj)t²;恒 a:½A·Tj + A(t-Tj);末 jerk 对称扣回。 */ static uint32_t PlsrAccelCurveSCurveFreqAtTime(uint32_t start_freq_hz, uint32_t end_freq_hz, uint32_t accel_hz_per_s, uint32_t jerk_time_us, uint32_t const_accel_time_us, uint32_t ramp_time_us, uint32_t elapsed_time_us) { - uint32_t freq_diff_hz; - uint32_t freq_change_hz; - uint32_t decel_start_time_us; - uint32_t decel_elapsed_us; - uint8_t freq_rising; + uint32_t freq_diff_hz; /* 总频差 */ + uint32_t freq_change_hz; /* 此刻已变的频差 */ + uint32_t decel_start_time_us; /* 末段开始时刻 */ + uint32_t decel_elapsed_us; /* 末段里走了多久 */ + uint8_t freq_rising; /* 升还是降 */ - freq_diff_hz = PlsrAccelCurveAbsDiff(start_freq_hz, end_freq_hz); - freq_rising = (end_freq_hz >= start_freq_hz) ? 1U : 0U; + freq_diff_hz = PlsrAccelCurveAbsDiff(start_freq_hz, end_freq_hz); /* 算总|Δf| */ + freq_rising = (end_freq_hz >= start_freq_hz) ? 1U : 0U; /* 看方向 */ - if ((freq_diff_hz < 1U) || (ramp_time_us < 1U) || (accel_hz_per_s < 1U)) + if ((freq_diff_hz < 1U) || (ramp_time_us < 1U) || (accel_hz_per_s < 1U)) /* 参数不齐 */ { - return PlsrAccelCurveClampFreqHz(end_freq_hz); + return PlsrAccelCurveClampFreqHz(end_freq_hz); /* 直接终点 */ } - if (elapsed_time_us >= ramp_time_us) + if (elapsed_time_us >= ramp_time_us) /* 时间到了 */ { - return PlsrAccelCurveClampFreqHz(end_freq_hz); + return PlsrAccelCurveClampFreqHz(end_freq_hz); /* 钉终点 */ } - if ((jerk_time_us < 1U) || (elapsed_time_us <= jerk_time_us)) + if ((jerk_time_us < 1U) || (elapsed_time_us <= jerk_time_us)) /* 还在第一段:加速度从0爬到最大 */ { - /* jerk 升:freq_change_hz = 0.5*(A/Tj)*t^2 */ - freq_change_hz = PlsrAccelCurveDeltaHzFromJerk(accel_hz_per_s, elapsed_time_us, (jerk_time_us < 1U) ? 1U : jerk_time_us); + /* jerk 升:Δf = 0.5*(A/Tj)*t^2 */ + freq_change_hz = PlsrAccelCurveDeltaHzFromJerk(accel_hz_per_s, elapsed_time_us, (jerk_time_us < 1U) ? 1U : jerk_time_us); /* Δf=½*(A/Tj)*t² */ } else { - decel_start_time_us = jerk_time_us + const_accel_time_us; - if (elapsed_time_us <= decel_start_time_us) + decel_start_time_us = jerk_time_us + const_accel_time_us; /* 恒加速段结束= Tj+Ta */ + if (elapsed_time_us <= decel_start_time_us) /* 还在恒加速 */ { - /* 恒加速:freq_change_hz = 0.5*A*Tj + A*(t-Tj) */ - freq_change_hz = PlsrAccelCurveDeltaHzFromJerk(accel_hz_per_s, jerk_time_us, jerk_time_us); - freq_change_hz += PlsrAccelCurveDeltaHzFromAt(accel_hz_per_s, elapsed_time_us - jerk_time_us); + /* 恒加速:Δf = 0.5*A*Tj + A*(t-Tj) */ + freq_change_hz = PlsrAccelCurveDeltaHzFromJerk(accel_hz_per_s, jerk_time_us, jerk_time_us); /* 先加上第一段贡献 ½*A*Tj */ + freq_change_hz += PlsrAccelCurveDeltaHzFromAt(accel_hz_per_s, elapsed_time_us - jerk_time_us); /* 再加上 A*(t-Tj) */ } else { - /* jerk 降:freq_change_hz = 0.5*A*Tj + A*Ta + A*τ - 0.5*(A/Tj)*τ^2 */ - decel_elapsed_us = elapsed_time_us - decel_start_time_us; - if (decel_elapsed_us > jerk_time_us) + /* jerk 降:Δf = 0.5*A*Tj + A*Ta + A*τ - 0.5*(A/Tj)*τ^2 */ + decel_elapsed_us = elapsed_time_us - decel_start_time_us; /* 末段相对时间τ */ + if (decel_elapsed_us > jerk_time_us) /* τ别超Tj */ { - decel_elapsed_us = jerk_time_us; + decel_elapsed_us = jerk_time_us; /* 夹到Tj */ } - freq_change_hz = PlsrAccelCurveDeltaHzFromJerk(accel_hz_per_s, jerk_time_us, jerk_time_us); - freq_change_hz += PlsrAccelCurveDeltaHzFromAt(accel_hz_per_s, const_accel_time_us); - freq_change_hz += PlsrAccelCurveDeltaHzFromAt(accel_hz_per_s, decel_elapsed_us); + freq_change_hz = PlsrAccelCurveDeltaHzFromJerk(accel_hz_per_s, jerk_time_us, jerk_time_us); /* 前面两段累计 */ + freq_change_hz += PlsrAccelCurveDeltaHzFromAt(accel_hz_per_s, const_accel_time_us); /* 加上恒加速整段 */ + freq_change_hz += PlsrAccelCurveDeltaHzFromAt(accel_hz_per_s, decel_elapsed_us); /* 末段先当匀加速加上A*τ */ { - uint32_t freq_drop = PlsrAccelCurveDeltaHzFromJerk(accel_hz_per_s, decel_elapsed_us, jerk_time_us); - if (freq_change_hz > freq_drop) + uint32_t freq_drop = PlsrAccelCurveDeltaHzFromJerk(accel_hz_per_s, decel_elapsed_us, jerk_time_us); /* 再扣回½*(A/Tj)*τ²(加速度往0收) */ + if (freq_change_hz > freq_drop) /* 够扣? */ { - freq_change_hz -= freq_drop; + freq_change_hz -= freq_drop; /* 扣掉 */ } else { - freq_change_hz = 0U; + freq_change_hz = 0U; /* 不够就清零 */ } } } } if (freq_change_hz > freq_diff_hz) - { - freq_change_hz = freq_diff_hz; + { /* 别超过总频差 */ + freq_change_hz = freq_diff_hz; /* 钳到总频差 */ } - if (freq_rising != 0U) + if (freq_rising != 0U) /* 升频:起点+变化 */ { - return PlsrAccelCurveClampFreqHz(start_freq_hz + freq_change_hz); + return PlsrAccelCurveClampFreqHz(start_freq_hz + freq_change_hz); /* 钳后返回 */ } - if (start_freq_hz > freq_change_hz) + if (start_freq_hz > freq_change_hz) /* 降频且扣得动 */ { - return PlsrAccelCurveClampFreqHz(start_freq_hz - freq_change_hz); + return PlsrAccelCurveClampFreqHz(start_freq_hz - freq_change_hz); /* 起点-变化 */ } - return PlsrAccelCurveClampFreqHz(end_freq_hz); + return PlsrAccelCurveClampFreqHz(end_freq_hz); /* 扣穿了就终点 */ } /** - * 正弦 raised-cosine:freq_hz = start_freq_hz + freq_diff_hz * (1-cos(π progress_permille))/2,progress_permille=t/T - * 用现有 33 点 sine 形状表(已是 raised-cosine 千分比)。 + * 正弦 raised-cosine:f = f0 + Δf·shape(t/T) + * shape≈(1-cos(πp))/2,查 33 点千分比表再插值。 */ static uint32_t PlsrAccelCurveSineFreqAtTime(uint32_t start_freq_hz, uint32_t end_freq_hz, uint32_t ramp_time_us, uint32_t elapsed_time_us) { - uint32_t progress_permille; - uint32_t ratio_permille; - uint32_t freq_hz; + uint32_t progress_permille; /* 时间进度千分比 */ + uint32_t ratio_permille; /* 形状千分比 */ + uint32_t freq_hz; /* 插值后频率 */ - if ((ramp_time_us < 1U) || (start_freq_hz == end_freq_hz)) + if ((ramp_time_us < 1U) || (start_freq_hz == end_freq_hz)) /* 没时间或同频 */ { - return PlsrAccelCurveClampFreqHz(end_freq_hz); + return PlsrAccelCurveClampFreqHz(end_freq_hz); /* 直接终点 */ } - if (elapsed_time_us >= ramp_time_us) + if (elapsed_time_us >= ramp_time_us) /* 时间走完 */ { - return PlsrAccelCurveClampFreqHz(end_freq_hz); + return PlsrAccelCurveClampFreqHz(end_freq_hz); /* 钉终点 */ } - progress_permille = (uint32_t)(((uint64_t)elapsed_time_us * 1000ULL) / (uint64_t)ramp_time_us); - if (progress_permille > 1000U) + progress_permille = (uint32_t)(((uint64_t)elapsed_time_us * 1000ULL) / (uint64_t)ramp_time_us); /* p=t/T */ + if (progress_permille > 1000U) /* 进度超了? */ { - progress_permille = 1000U; + progress_permille = 1000U; /* 夹到1000 */ } - ratio_permille = PlsrAccelCurveShapeSinePermille(progress_permille); - freq_hz = PlsrAccelCurveInterpolate(start_freq_hz, end_freq_hz, ratio_permille); - if (freq_hz < 1U) + ratio_permille = PlsrAccelCurveShapeSinePermille(progress_permille); /* 半个余弦形状:进度→形状 */ + freq_hz = PlsrAccelCurveInterpolate(start_freq_hz, end_freq_hz, ratio_permille); /* 按形状在起止间插频 */ + if (freq_hz < 1U) /* 保护 */ { - freq_hz = 1U; + freq_hz = 1U; /* 至少1 */ } - return PlsrAccelCurveClampFreqHz(freq_hz); + return PlsrAccelCurveClampFreqHz(freq_hz); /* 钳后返回 */ } -/** 按 S/正弦时间曲线计算指定脉冲位置的频率。 */ +/** 按 S/正弦时间曲线,从起点逐步积分到第 completed_pulses 拍的频率 */ static uint32_t PlsrAccelCurveTimedFreqAtPulse( uint32_t start_freq_hz, uint32_t end_freq_hz, @@ -1235,103 +1244,107 @@ static uint32_t PlsrAccelCurveTimedFreqAtPulse( PlsrAccelMode_e curve_mode, uint32_t completed_pulses) { - uint32_t jerk_time_us = 0U; - uint32_t const_accel_time_us = 0U; - uint32_t ramp_time_us = 0U; - uint32_t elapsed_time_us = 0U; - uint32_t cur_freq_hz = start_freq_hz; - uint32_t pulse_index; - - if (curve_mode == PLSR_ACCEL_S) - { - PlsrAccelCurveCalcSCurveTimes(start_freq_hz, - end_freq_hz, - rate_hz_per_s, - &jerk_time_us, - &const_accel_time_us, - &ramp_time_us); + uint32_t jerk_time_us = 0U; /* 加加速度阶段时间 */ + uint32_t const_accel_time_us = 0U; /* 恒加速时间 */ + uint32_t ramp_time_us = 0U; /* 斜坡总时间 */ + uint32_t elapsed_time_us = 0U; /* 累计已过微秒 */ + uint32_t cur_freq_hz = start_freq_hz; /* 从起点频开始积 */ + uint32_t pulse_index; /* 拍循环下标 */ + + /* 先算整段斜坡时间参数 */ + if (curve_mode == PLSR_ACCEL_S) /* S曲线 */ + { + PlsrAccelCurveCalcSCurveTimes(start_freq_hz, /* 起点频率 */ + end_freq_hz, /* 终点频率 */ + rate_hz_per_s, /* 峰值加速度 A */ + &jerk_time_us, /* 出:加速度爬升阶段时间 Tj */ + &const_accel_time_us, /* 出:恒加速阶段时间 Ta */ + &ramp_time_us); /* 出:斜坡总时间 T=4*Tj */ } else { - PlsrAccelCurveCalcSineCurveTime(start_freq_hz, - end_freq_hz, - rate_hz_per_s, - &ramp_time_us); + PlsrAccelCurveCalcSineCurveTime(start_freq_hz, /* 起点频率 */ + end_freq_hz, /* 终点频率 */ + rate_hz_per_s, /* 峰值加速度 A */ + &ramp_time_us); /* 出:斜坡总时间 T */ } - for (pulse_index = 0U; pulse_index < completed_pulses; pulse_index++) + /* 每拍用上一拍周期推进时间,再按 t 取频 */ + for (pulse_index = 0U; pulse_index < completed_pulses; pulse_index++) /* 一拍一拍积到目标拍数 */ { - if (cur_freq_hz < 1U) + if (cur_freq_hz < 1U) /* 保护当前频 */ { - cur_freq_hz = 1U; + cur_freq_hz = 1U; /* 至少1 */ } - elapsed_time_us += 1000000UL / cur_freq_hz; + elapsed_time_us += 1000000UL / cur_freq_hz; /* Δt = 1/f(µs) */ - if (curve_mode == PLSR_ACCEL_S) + if (curve_mode == PLSR_ACCEL_S) /* S:按累计时间取频 */ { cur_freq_hz = - PlsrAccelCurveSCurveFreqAtTime(start_freq_hz, - end_freq_hz, - rate_hz_per_s, - jerk_time_us, - const_accel_time_us, - ramp_time_us, - elapsed_time_us); + PlsrAccelCurveSCurveFreqAtTime(start_freq_hz, /* 起点频率 */ + end_freq_hz, /* 终点频率 */ + rate_hz_per_s, /* 峰值加速度 A */ + jerk_time_us, /* Tj */ + const_accel_time_us, /* Ta */ + ramp_time_us, /* 斜坡总时间 T */ + elapsed_time_us); /* 已经过了多少微秒 */ } else { cur_freq_hz = - PlsrAccelCurveSineFreqAtTime(start_freq_hz, - end_freq_hz, - ramp_time_us, - elapsed_time_us); + PlsrAccelCurveSineFreqAtTime(start_freq_hz, /* 起点频率 */ + end_freq_hz, /* 终点频率 */ + ramp_time_us, /* 斜坡总时间 T */ + elapsed_time_us); /* 已经过了多少微秒 */ } } - return cur_freq_hz; + return cur_freq_hz; /* 积完返回该拍频率 */ } -/*仿真离散脉冲频率,算出该段加/减速一共需要输出多少个脉冲*/ +/** + * 仿真离散脉冲:从 start 走到 end,返回本斜坡需要的脉冲数。 + * 用于 S/正弦脉冲预算(无闭合公式时只能仿真)。 + */ static uint32_t PlsrAccelCurveSimulateRampPulses(uint32_t start_freq_hz, uint32_t end_freq_hz, uint32_t accel_hz_per_s, PlsrAccelMode_e curve_mode) { - PlsrAccelRuntime_t runtime; - uint32_t iteration_guard; + PlsrAccelRuntime_t runtime; /* 临时运行态 */ + uint32_t iteration_guard; /* 循环保险丝 */ - /*起始频率 = 终止频率,或者加速度=0,返回0*/ - if (start_freq_hz == end_freq_hz || accel_hz_per_s == 0U) + /* 同频或 a=0:无斜坡脉冲 */ + if (start_freq_hz == end_freq_hz || accel_hz_per_s == 0U) /* 同频或a=0 */ { - return 0U; + return 0U; /* 0拍斜坡 */ } - /* 填写一个加速或减速相的运行数据 */ - PlsrAccelRuntimeBeginRamp(&runtime, - start_freq_hz, - end_freq_hz, - 0xFFFFFFFFUL,/*总脉冲数,填写最大值*/ - accel_hz_per_s, - accel_hz_per_s, - curve_mode); - /* 算出来的斜坡时间是 0(无效)时,仍按至少 1 个脉冲处理。 */ - if (runtime.ramp_time_us < 1U) + /* 开相:total 填满,靠 is_active 自然停 */ + PlsrAccelRuntimeBeginRamp(&runtime, /* 开相仿真 */ + start_freq_hz, /* 起始频率 */ + end_freq_hz, /* 终止频率 */ + 0xFFFFFFFFUL, /* 不限脉冲上限 */ + accel_hz_per_s, /* 斜率 */ + accel_hz_per_s, /* 同斜率(单相) */ + curve_mode); /* 模式 */ + /* 斜坡时间无效时,至少算 1 脉冲 */ + if (runtime.ramp_time_us < 1U) { - return 1U; + return 1U; /* 至少当1拍 */ } - iteration_guard = 0U; - while ((runtime.is_active != 0U) && (iteration_guard < 5000000U)) + iteration_guard = 0U; /* 计数清零 */ + while ((runtime.is_active != 0U) && (iteration_guard < 5000000U)) /* 还在跑且没到上限 */ { - iteration_guard++; - /* 单个脉冲仿真 */ - PlsrAccelRuntimeSimulateOnePulse(&runtime); + iteration_guard++; /* 计一轮 */ + PlsrAccelRuntimeSimulateOnePulse(&runtime); /* 时间步进一拍 */ } - /*使用的脉冲数至少为1个*/ - if (runtime.completed_pulses == 0U) + /* 未走出任何脉冲时兜底为 1 */ + if (runtime.completed_pulses == 0U) /* 一拍都没走出? */ { - return 1U; + return 1U; /* 兜底1 */ } - return runtime.completed_pulses; /*返回仿真的后的总脉冲数*/ + return runtime.completed_pulses; /* 仿真得到的拍数=加速从起点爬到终点要几拍 */ } /** @@ -1339,142 +1352,156 @@ static uint32_t PlsrAccelCurveSimulateRampPulses(uint32_t start_freq_hz, uint32_ */ static uint32_t PlsrAccelNextFreqTimed(PlsrAccelRuntime_t *runtime) { - uint32_t previous_freq_hz; - uint32_t pulse_period_us; - uint32_t freq_hz; + uint32_t previous_freq_hz; /* 上一拍频率 */ + uint32_t pulse_period_us; /* 上一拍周期微秒 */ + uint32_t freq_hz; /* 本拍算出的频 */ - if ((runtime->ramp_time_us < 1U) || (runtime->accel_hz_per_s < 1U)) + if ((runtime->ramp_time_us < 1U) || (runtime->accel_hz_per_s < 1U)) /* 没斜坡时间或没加速度 */ { - return PlsrAccelCurveClampFreqHz(runtime->end_freq_hz); + return PlsrAccelCurveClampFreqHz(runtime->end_freq_hz); /* 直接终点 */ } - previous_freq_hz = runtime->cur_freq_hz; - if (previous_freq_hz < 1U) + previous_freq_hz = runtime->cur_freq_hz; /* 记下上一频 */ + if (previous_freq_hz < 1U) { - previous_freq_hz = 1U; + previous_freq_hz = 1U; /* 至少1Hz */ } - pulse_period_us = 1000000UL / previous_freq_hz; + pulse_period_us = 1000000UL / previous_freq_hz; /* 上一拍周期 µs */ - if (runtime->elapsed_time_us < (0xFFFFFFFFUL - pulse_period_us)) + /* 累加时间,防溢出钉死上限 */ + if (runtime->elapsed_time_us < (0xFFFFFFFFUL - pulse_period_us)) /* 累加不会溢出? */ { - runtime->elapsed_time_us += pulse_period_us; + runtime->elapsed_time_us += pulse_period_us; /* 时间+=上一拍周期 */ } else { - runtime->elapsed_time_us = 0xFFFFFFFFUL; + runtime->elapsed_time_us = 0xFFFFFFFFUL; /* 溢了就钉死最大,最大4295秒 */ } - if (runtime->elapsed_time_us >= runtime->ramp_time_us) + if (runtime->elapsed_time_us >= runtime->ramp_time_us) /* 到了斜坡总时间 */ { - return PlsrAccelCurveClampFreqHz(runtime->end_freq_hz); + return PlsrAccelCurveClampFreqHz(runtime->end_freq_hz); /* 返回终点频 */ } - if (runtime->curve_mode == PLSR_ACCEL_S) + if (runtime->curve_mode == PLSR_ACCEL_S) /* S曲线 */ { - freq_hz = PlsrAccelCurveSCurveFreqAtTime(runtime->start_freq_hz, runtime->end_freq_hz, runtime->accel_hz_per_s, - runtime->jerk_time_us, runtime->const_accel_time_us, runtime->ramp_time_us, - runtime->elapsed_time_us); + freq_hz = PlsrAccelCurveSCurveFreqAtTime(runtime->start_freq_hz, runtime->end_freq_hz, runtime->accel_hz_per_s, /* 按三段时间取频 */ + runtime->jerk_time_us, runtime->const_accel_time_us, runtime->ramp_time_us, /* 带上Tj/Ta/T和已过时间 */ + runtime->elapsed_time_us); /* 已过微秒 */ } else { - freq_hz = PlsrAccelCurveSineFreqAtTime(runtime->start_freq_hz, runtime->end_freq_hz, runtime->ramp_time_us, runtime->elapsed_time_us); + freq_hz = PlsrAccelCurveSineFreqAtTime(runtime->start_freq_hz, runtime->end_freq_hz, runtime->ramp_time_us, runtime->elapsed_time_us); /* 正弦按时间取频 */ } - return freq_hz; + return freq_hz; /* 返回本拍频 */ } /*============================================================================*/ /* 规划 */ /*============================================================================*/ -/* S或者正弦,采用仿真方式,直线采用直接计算方式 */ +/* 单段斜坡脉冲数:S/正弦仿真;直线闭合式 N=ceil(|f1²-f0²|/(2a)) */ static uint32_t PlsrAccelCurveCalcRampPulses(uint32_t start_freq_hz, uint32_t end_freq_hz, uint32_t accel_hz_per_s, PlsrAccelMode_e curve_mode) { - if ((curve_mode == PLSR_ACCEL_SINE) || (curve_mode == PLSR_ACCEL_S)) + if ((curve_mode == PLSR_ACCEL_SINE) || (curve_mode == PLSR_ACCEL_S)) /* S或正弦 */ { - return PlsrAccelCurveSimulateRampPulses(start_freq_hz, end_freq_hz, accel_hz_per_s, curve_mode); + return PlsrAccelCurveSimulateRampPulses(start_freq_hz, end_freq_hz, accel_hz_per_s, curve_mode); /* 只能仿真出拍数 */ } - return PlsrAccelCurveCalcLinearRampPulses(start_freq_hz, end_freq_hz, accel_hz_per_s); + return PlsrAccelCurveCalcLinearRampPulses(start_freq_hz, end_freq_hz, accel_hz_per_s); /* 直线:用v^2闭合式直接算 */ } /** - * 二分峰值:使 acc+dec 脉冲 <= total(脉冲闭合公式)。 + * 二分找峰值偏移:在 [0, |段表峰-起点|] 上找最大 offset,使 acc+dec <= total。 + * 返回实际能跑到的最高峰(往上爬)或最低峰(往下掉)。 */ static uint32_t PlsrAccelCurveFitTargetFreq(uint32_t total_pulses, uint32_t start_freq_hz, - uint32_t requested_target_freq_hz, + uint32_t peak_tgt_hz, uint32_t end_freq_hz, uint32_t accel_rate_hz_per_s, uint32_t decel_rate_hz_per_s, PlsrAccelMode_e curve_mode) { - uint32_t lowest_offset_hz = 0U; - uint32_t highest_offset_hz; - uint32_t candidate_offset_hz; - uint32_t best_offset_hz = 0U; - uint32_t candidate_freq_hz; - uint32_t accel_pulses; - uint32_t decel_pulses; - uint32_t search_range_hz; + uint32_t low; /* 二分左界:偏移量下界,从 0 起 */ + uint32_t high; /* 二分右界:偏移量上界 */ + uint32_t mid; /* 二分中点:当前试探的偏移量 */ + uint32_t best; /* 目前可行且最大的偏移量 */ + uint32_t peak_hz; /* 由 mid 算出的试探峰值 */ + uint32_t acc_n; /* 起→峰 要几拍 */ + uint32_t dec_n; /* 峰→止 要几拍 */ + uint32_t max_offset; /* 偏移上界 = |段表峰 - 起点| */ + uint8_t peak_up; /* 1=段表峰在起点之上,0=在之下 */ - if (requested_target_freq_hz >= start_freq_hz) + /* 段表峰相对起点是往上还是往下 */ + peak_up = (peak_tgt_hz >= start_freq_hz) ? 1U : 0U; /* 看段表峰比起高还是低 */ + if (peak_up != 0U) /* 往上爬 */ { - search_range_hz = requested_target_freq_hz - start_freq_hz; + max_offset = peak_tgt_hz - start_freq_hz; /* 上界 = 段表峰 - 起点 */ } - else + else /* 往下掉 */ { - search_range_hz = start_freq_hz - requested_target_freq_hz; + max_offset = start_freq_hz - peak_tgt_hz; /* 上界 = 起点 - 段表峰 */ } - highest_offset_hz = search_range_hz; - while (lowest_offset_hz <= highest_offset_hz) + low = 0U; /* 偏移从 0 开始试 */ + high = max_offset; /* 最多偏到段表峰 */ + best = 0U; /* 还没找到更好的 */ + + while (low <= high) /* 标准二分 */ { - candidate_offset_hz = lowest_offset_hz + ((highest_offset_hz - lowest_offset_hz) / 2UL); - if (requested_target_freq_hz >= start_freq_hz) + mid = low + ((high - low) / 2UL); /* 取中点偏移 */ + + /* 起点 ± mid 得到本轮回试探的峰值 */ + if (peak_up != 0U) /* 往上:峰 = 起点 + 偏移 */ { - candidate_freq_hz = start_freq_hz + candidate_offset_hz; - accel_pulses = PlsrAccelCurveCalcRampPulses(start_freq_hz, candidate_freq_hz, accel_rate_hz_per_s, curve_mode); + peak_hz = start_freq_hz + mid; /* 试探峰 */ + acc_n = PlsrAccelCurveCalcRampPulses(start_freq_hz, peak_hz, accel_rate_hz_per_s, curve_mode); /* 起→峰,用加速斜率 */ } - else + else /* 往下:峰 = 起点 - 偏移 */ { - candidate_freq_hz = start_freq_hz - candidate_offset_hz; - accel_pulses = PlsrAccelCurveCalcRampPulses(start_freq_hz, candidate_freq_hz, decel_rate_hz_per_s, curve_mode); + peak_hz = start_freq_hz - mid; /* 试探峰 */ + acc_n = PlsrAccelCurveCalcRampPulses(start_freq_hz, peak_hz, decel_rate_hz_per_s, curve_mode); /* 起→峰往下,用减速斜率 */ } - decel_pulses = PlsrAccelCurveCalcRampPulses(candidate_freq_hz, end_freq_hz, - (end_freq_hz > candidate_freq_hz) ? accel_rate_hz_per_s : decel_rate_hz_per_s, curve_mode); + /* 峰→止:看止速比峰高还是低,选对应斜率 */ + dec_n = PlsrAccelCurveCalcRampPulses(peak_hz, end_freq_hz, + (end_freq_hz > peak_hz) ? accel_rate_hz_per_s : decel_rate_hz_per_s, curve_mode); - if ((accel_pulses + decel_pulses) <= total_pulses) + if ((acc_n + dec_n) <= total_pulses) /* 加减速拍数塞得进总脉冲? */ { - best_offset_hz = candidate_offset_hz; - if (candidate_offset_hz == search_range_hz) + best = mid; /* 这个偏移可行,先记下来 */ + if (mid == max_offset) /* 已经顶到段表峰了 */ { - break; + break; /* 没法再大了 */ } - lowest_offset_hz = candidate_offset_hz + 1UL; - if (lowest_offset_hz > highest_offset_hz) + low = mid + 1UL; /* 往更大的偏移试 */ + if (low > high) /* 左右界碰头了 */ { - break; + break; /* 搜完了 */ } } - else + else /* 超预算了 */ { - if (candidate_offset_hz == 0U) + if (mid == 0U) /* 偏移为 0 都塞不进 */ { - break; + break; /* 没救,只能停在起点 */ } - highest_offset_hz = candidate_offset_hz - 1UL; + high = mid - 1UL; /* 缩小右界,试更小的峰 */ } } - if (requested_target_freq_hz >= start_freq_hz) + if (peak_up != 0U) /* 往上爬:返回起点 + 最好偏移 */ { - return start_freq_hz + best_offset_hz; + return start_freq_hz + best; /* 能到的最高峰 */ } - return start_freq_hz - best_offset_hz; + return start_freq_hz - best; /* 往下掉:返回起点 - 最好偏移 */ } -/** 按峰值重算加速/减速脉冲预算 */ +/** + * 按峰值重算加速/减速脉冲预算。 + * 注意:频率“向下走”的那段要用 decel_rate,向上走用 accel_rate。 + */ static void PlsrAccelCurveCalcPhasePulses(uint32_t start_freq_hz, uint32_t peak_freq_hz, uint32_t end_freq_hz, @@ -1484,103 +1511,57 @@ static void PlsrAccelCurveCalcPhasePulses(uint32_t start_freq_hz, uint32_t *accel_pulses, uint32_t *decel_pulses) { - /*如果起始频率 > 峰值频率,加速脉冲数*/ - if (start_freq_hz > peak_freq_hz) + /* 起→峰 */ + if (start_freq_hz > peak_freq_hz) /* 起比峰高:这段其实在掉频 */ { - *accel_pulses = PlsrAccelCurveCalcRampPulses(start_freq_hz, peak_freq_hz, decel_rate_hz_per_s, curve_mode); + *accel_pulses = PlsrAccelCurveCalcRampPulses(start_freq_hz, peak_freq_hz, decel_rate_hz_per_s, curve_mode); /* 用减速斜率算加速相拍数 */ } else { - *accel_pulses = PlsrAccelCurveCalcRampPulses(start_freq_hz, peak_freq_hz, accel_rate_hz_per_s, curve_mode); + *accel_pulses = PlsrAccelCurveCalcRampPulses(start_freq_hz, peak_freq_hz, accel_rate_hz_per_s, curve_mode); /* 正常往上爬:用加速斜率 */ } - if (end_freq_hz > peak_freq_hz) + /* 峰→止 */ + if (end_freq_hz > peak_freq_hz) /* 止比峰高:峰→止在往上 */ { - *decel_pulses = PlsrAccelCurveCalcRampPulses(peak_freq_hz, end_freq_hz, accel_rate_hz_per_s, curve_mode); + *decel_pulses = PlsrAccelCurveCalcRampPulses(peak_freq_hz, end_freq_hz, accel_rate_hz_per_s, curve_mode); /* 用加速斜率 */ } else { - *decel_pulses = PlsrAccelCurveCalcRampPulses(peak_freq_hz, end_freq_hz, decel_rate_hz_per_s, curve_mode); - } -} - -/** - * FitPeak 后再对齐离散取整:禁止只截断 decel_pulses,逐步降峰直到 acc+dec<=total。 - */ -static uint32_t PlsrAccelCurveFitTargetToPulseBudget(uint32_t total_pulses, - uint32_t start_freq_hz, - uint32_t requested_target_freq_hz, - uint32_t end_freq_hz, - uint32_t accel_rate_hz_per_s, - uint32_t decel_rate_hz_per_s, - PlsrAccelMode_e curve_mode, - uint32_t *accel_pulses, - uint32_t *decel_pulses) -{ - uint32_t peak_freq_hz; - uint32_t iteration_guard; - - peak_freq_hz = PlsrAccelCurveFitTargetFreq(total_pulses, start_freq_hz, requested_target_freq_hz, end_freq_hz, - accel_rate_hz_per_s, decel_rate_hz_per_s, curve_mode); - PlsrAccelCurveCalcPhasePulses(start_freq_hz, peak_freq_hz, end_freq_hz, accel_rate_hz_per_s, decel_rate_hz_per_s, curve_mode, - accel_pulses, decel_pulses); - - iteration_guard = 0U; - while ((*accel_pulses + *decel_pulses) > total_pulses && (iteration_guard < 100000U)) - { - iteration_guard++; - if (requested_target_freq_hz >= start_freq_hz) - { - if (peak_freq_hz <= start_freq_hz) - { - break; - } - peak_freq_hz--; - } - else - { - if (peak_freq_hz >= start_freq_hz) - { - break; - } - peak_freq_hz++; - } - PlsrAccelCurveCalcPhasePulses(start_freq_hz, peak_freq_hz, end_freq_hz, accel_rate_hz_per_s, decel_rate_hz_per_s, curve_mode, - accel_pulses, decel_pulses); + *decel_pulses = PlsrAccelCurveCalcRampPulses(peak_freq_hz, end_freq_hz, decel_rate_hz_per_s, curve_mode); /* 正常峰→止往下:用减速斜率 */ } - return peak_freq_hz; } /*============================================================================*/ /* 运行态 */ /*============================================================================*/ -/* 运行时计算时间*/ +/* 按曲线模式预填 Tj/Ta/T(直线不填时间) */ static void PlsrAccelRuntimeCalcTimes(PlsrAccelRuntime_t *runtime) { - runtime->elapsed_time_us = 0U; - runtime->jerk_time_us = 0U; - runtime->const_accel_time_us = 0U; - runtime->ramp_time_us = 0U; + runtime->elapsed_time_us = 0U; /* 已过时间清零 */ + runtime->jerk_time_us = 0U; /* 加加速度阶段清零 */ + runtime->const_accel_time_us = 0U; /* 恒加速清零 */ + runtime->ramp_time_us = 0U; /* 斜坡总时间清零 */ - /*加速度小于1,或者起始频率 = 终止频率,直接结束*/ - if ((runtime->accel_hz_per_s < 1U) || (runtime->start_freq_hz == runtime->end_freq_hz)) + /* a=0 或同频:无斜坡时间 */ + if ((runtime->accel_hz_per_s < 1U) || (runtime->start_freq_hz == runtime->end_freq_hz)) /* 没斜率或同频 */ { - return; + return; /* 时间保持0 */ } - /*S曲线计算时间*/ - if (runtime->curve_mode == PLSR_ACCEL_S) + if (runtime->curve_mode == PLSR_ACCEL_S) /* S模式 */ { - PlsrAccelCurveCalcSCurveTimes(runtime->start_freq_hz, runtime->end_freq_hz, runtime->accel_hz_per_s, - &runtime->jerk_time_us, &runtime->const_accel_time_us, &runtime->ramp_time_us); + /* Tj:Ta:Tj=1:2:1 → T=4*Tj */ + PlsrAccelCurveCalcSCurveTimes(runtime->start_freq_hz, runtime->end_freq_hz, runtime->accel_hz_per_s, /* 填Tj/Ta/斜坡总时间 */ + &runtime->jerk_time_us, &runtime->const_accel_time_us, &runtime->ramp_time_us); /* 写进runtime */ } - /* 正弦曲线计算时间*/ - else if (runtime->curve_mode == PLSR_ACCEL_SINE) + else if (runtime->curve_mode == PLSR_ACCEL_SINE) /* 正弦模式 */ { - PlsrAccelCurveCalcSineCurveTime(runtime->start_freq_hz, runtime->end_freq_hz, runtime->accel_hz_per_s, &runtime->ramp_time_us); + /* T = π·Δf / (2A) */ + PlsrAccelCurveCalcSineCurveTime(runtime->start_freq_hz, runtime->end_freq_hz, runtime->accel_hz_per_s, &runtime->ramp_time_us); /* 只填斜坡总时间 */ } } -/** 填写一个加速或减速相的运行数据。 */ +/** 开相:填起/止/斜率/方向,并预计算时间参数 */ static void PlsrAccelRuntimeBeginRamp(PlsrAccelRuntime_t *runtime, uint32_t start_freq_hz, uint32_t end_freq_hz, @@ -1589,149 +1570,153 @@ static void PlsrAccelRuntimeBeginRamp(PlsrAccelRuntime_t *runtime, uint32_t decel_rate_hz_per_s, PlsrAccelMode_e curve_mode) { - runtime->start_freq_hz = start_freq_hz; - runtime->end_freq_hz = end_freq_hz; - runtime->cur_freq_hz = start_freq_hz; - runtime->completed_pulses = 0U; - runtime->total_pulses = total_pulses; - /*终点 > 起点,加速过程*/ + runtime->start_freq_hz = start_freq_hz; /* 本相起点 */ + runtime->end_freq_hz = end_freq_hz; /* 本相终点 */ + runtime->cur_freq_hz = start_freq_hz; /* 当前从起点开跑 */ + runtime->completed_pulses = 0U; /* 拍计数清零 */ + runtime->total_pulses = total_pulses; /* 本相总拍数 */ runtime->freq_rising = - (end_freq_hz >= start_freq_hz) ? 1U : 0U; - /*加速度,上升用加速斜率,下降用减速斜率*/ - runtime->accel_hz_per_s = + (end_freq_hz >= start_freq_hz) ? 1U : 0U; /* 1=升频 */ + /* 升用加速斜率,降用减速斜率 */ + runtime->accel_hz_per_s = /* 本相实际用的斜率 */ (runtime->freq_rising != 0U) ? - accel_rate_hz_per_s : decel_rate_hz_per_s; - /*曲线模式*/ - runtime->curve_mode = curve_mode; - /* 1=当前相仍在运行 */ + accel_rate_hz_per_s : decel_rate_hz_per_s; /* 升用accel,降用decel */ + runtime->curve_mode = curve_mode; /* 选好的斜率 */ + /* 有脉冲且起止不同才激活 */ runtime->is_active = ((total_pulses > 0U) && - (start_freq_hz != end_freq_hz)) ? 1U : 0U; - runtime->freq_table_id = 0U; - runtime->table_length = 0U; - runtime->table_stride = 1U; - PlsrAccelRuntimeCalcTimes(runtime);/*计算加速时间*/ + (start_freq_hz != end_freq_hz)) ? 1U : 0U; /* 有拍且起止不同才算活跃 */ + runtime->freq_table_id = 0U; /* 开相先不绑表;BeginAcc/Dec 再 Select */ + runtime->table_length = 0U; /* 表长清 */ + runtime->table_stride = 1U; /* 步长默认1 */ + PlsrAccelRuntimeCalcTimes(runtime); /* 按模式预填时间参数 */ } -/** 离散仿真一步:与建表 / 脉冲预算共用 */ +/** 离散仿真一步:与建表 / 脉冲预算共用(时间步进) */ static void PlsrAccelRuntimeSimulateOnePulse(PlsrAccelRuntime_t *runtime) { - if (runtime->completed_pulses < 0xFFFFFFFFUL) + if (runtime->completed_pulses < 0xFFFFFFFFUL) /* 防溢出 */ { - runtime->completed_pulses++; + runtime->completed_pulses++; /* 仿真拍+1 */ } - runtime->cur_freq_hz = PlsrAccelNextFreqTimed(runtime); - if ((runtime->ramp_time_us > 0U) && (runtime->elapsed_time_us >= runtime->ramp_time_us)) + runtime->cur_freq_hz = PlsrAccelNextFreqTimed(runtime); /* 时间域推进一拍取频 */ + /* 到时或越过终点 → 钉终点并停相 */ + if ((runtime->ramp_time_us > 0U) && (runtime->elapsed_time_us >= runtime->ramp_time_us)) /* 时间到斜坡总时间? */ { - runtime->cur_freq_hz = runtime->end_freq_hz; - runtime->is_active = 0U; + runtime->cur_freq_hz = runtime->end_freq_hz; /* 钉终点 */ + runtime->is_active = 0U; /* 停 */ } - else if (runtime->freq_rising != 0U) + else if (runtime->freq_rising != 0U) /* 升频 */ { - if (runtime->cur_freq_hz >= runtime->end_freq_hz) + if (runtime->cur_freq_hz >= runtime->end_freq_hz) /* 已到/过终点 */ { - runtime->cur_freq_hz = runtime->end_freq_hz; - runtime->is_active = 0U; + runtime->cur_freq_hz = runtime->end_freq_hz; /* 钉终点 */ + runtime->is_active = 0U; /* 停 */ } } else { - if (runtime->cur_freq_hz <= runtime->end_freq_hz) + if (runtime->cur_freq_hz <= runtime->end_freq_hz) /* 降频已到/过终点 */ { - runtime->cur_freq_hz = runtime->end_freq_hz; - runtime->is_active = 0U; + runtime->cur_freq_hz = runtime->end_freq_hz; /* 钉终点 */ + runtime->is_active = 0U; /* 停 */ } } } /** * 将本相离散频率写入 freq_table[],返回写入长度;*table_stride_out 为抽样步长。 + * 脉冲数 > 容量时 stride=ceil(N/cap),ISR 用 completed/stride 取下标。 */ static uint32_t PlsrAccelRuntimeBuildFreqTable(PlsrAccelRuntime_t *runtime, uint32_t *freq_table, uint32_t table_capacity, uint32_t *table_stride_out) { - PlsrAccelRuntime_t simulation; - uint32_t loop_index; - uint32_t table_index; - uint32_t table_stride; - uint32_t table_length; + PlsrAccelRuntime_t simulation; /* 独立仿真副本 */ + uint32_t loop_index; /* 脉冲循环 */ + uint32_t table_index; /* 写入下标 */ + uint32_t table_stride; /* 抽样步长 */ + uint32_t table_length; /* 有效表长 */ - *table_stride_out = 1U; - if ((runtime->is_active == 0U) || (runtime->total_pulses < 1U) || - (runtime->curve_mode == PLSR_ACCEL_LINEAR) || (freq_table == (uint32_t *)0) || - (table_capacity < 1U)) + *table_stride_out = 1U; /* 默认步长1 */ + if ((runtime->is_active == 0U) || (runtime->total_pulses < 1U) || /* 不活跃/无拍/直线/空表/无容量 */ + (runtime->curve_mode == PLSR_ACCEL_LINEAR) || (freq_table == (uint32_t *)0) || /* 直线不建表 */ + (table_capacity < 1U)) /* 条件不满足 */ { - return 0U; + return 0U; /* 直线或不活跃:不建表 */ } - table_stride = 1U; - if (runtime->total_pulses > table_capacity) + /* 超容量则抽样,保证能塞进表 */ + table_stride = 1U; /* 先按1 */ + if (runtime->total_pulses > table_capacity) /* 脉冲比表容量多? */ { - table_stride = (runtime->total_pulses + table_capacity - 1U) / table_capacity; + table_stride = (runtime->total_pulses + table_capacity - 1U) / table_capacity; /* 步长=ceil(总拍/容量),向上取整 */ } - *table_stride_out = table_stride; + *table_stride_out = table_stride; /* 告诉调用方步长 */ - simulation = *runtime; - simulation.completed_pulses = 0U; - simulation.cur_freq_hz = runtime->start_freq_hz; - simulation.is_active = 1U; - PlsrAccelRuntimeCalcTimes(&simulation); - if (simulation.ramp_time_us < 1U) + /* 独立副本仿真,避免改坏调用方 runtime */ + simulation = *runtime; /* 拷一份runtime */ + simulation.completed_pulses = 0U; /* 仿真从0拍起 */ + simulation.cur_freq_hz = runtime->start_freq_hz; /* 频回到起点 */ + simulation.is_active = 1U; /* 强制活跃 */ + PlsrAccelRuntimeCalcTimes(&simulation); /* 重算时间参数 */ + if (simulation.ramp_time_us < 1U) /* 斜坡总时间无效 */ { - freq_table[0] = runtime->end_freq_hz; - return 1U; + freq_table[0] = runtime->end_freq_hz; /* 表里塞一个终点 */ + return 1U; /* 长度1 */ } - table_length = 0U; - for (loop_index = 0U; loop_index < runtime->total_pulses; loop_index++) + table_length = 0U; /* 表长从0计 */ + for (loop_index = 0U; loop_index < runtime->total_pulses; loop_index++) /* 按总拍逐拍仿真 */ { - PlsrAccelRuntimeSimulateOnePulse(&simulation); - table_index = (simulation.completed_pulses - 1U) / table_stride; - if (table_index >= table_capacity) + PlsrAccelRuntimeSimulateOnePulse(&simulation); /* 推一拍 */ + table_index = (simulation.completed_pulses - 1U) / table_stride; /* completed/stride → 下标 */ + if (table_index >= table_capacity) /* 越界夹住 */ { - table_index = table_capacity - 1U; + table_index = table_capacity - 1U; /* 夹到末格 */ } - freq_table[table_index] = simulation.cur_freq_hz; - if ((table_index + 1U) > table_length) + freq_table[table_index] = simulation.cur_freq_hz; /* 写入当前频 */ + if ((table_index + 1U) > table_length) /* 刷新有效长度 */ { - table_length = table_index + 1U; + table_length = table_index + 1U; /* 长度至少盖住该下标 */ } - if (simulation.is_active == 0U) + /* 提前到达终点:余下表项填 end */ + if (simulation.is_active == 0U) /* 提前停了? */ { - while ((loop_index + 1U) < runtime->total_pulses) + while ((loop_index + 1U) < runtime->total_pulses) /* 把剩下拍都填成终点 */ { - loop_index++; - table_index = loop_index / table_stride; - if (table_index >= table_capacity) + loop_index++; /* 假推进loop */ + table_index = loop_index / table_stride; /* 按拍号算下标 */ + if (table_index >= table_capacity) /* 越界? */ { - table_index = table_capacity - 1U; + table_index = table_capacity - 1U; /* 夹住 */ } - freq_table[table_index] = runtime->end_freq_hz; - if ((table_index + 1U) > table_length) + freq_table[table_index] = runtime->end_freq_hz; /* 填终点频 */ + if ((table_index + 1U) > table_length) /* 更新长度 */ { - table_length = table_index + 1U; + table_length = table_index + 1U; /* 盖住 */ } } - break; + break; /* 跳出主循环 */ } } - if (table_length > 0U) + /* 末项强制终点频,避免抽样截断偏离 */ + if (table_length > 0U) /* 有表项? */ { - freq_table[table_length - 1U] = runtime->end_freq_hz; + freq_table[table_length - 1U] = runtime->end_freq_hz; /* 最后一格强制终点频 */ } - return table_length; + return table_length; /* 返回表长 */ } -/** 选择当前相使用的加速表或减速表,并记录表长度和抽样步长。 */ +/** 绑加速表(id=1)或减速表(id=2);长度为 0 则退回不用表 */ static void PlsrAccelRuntimeSelectFreqTable(PlsrAccelRuntime_t *runtime, uint8_t freq_table_id, uint32_t table_length, uint32_t table_stride) { - runtime->table_length = table_length; - runtime->table_stride = (table_stride < 1U) ? 1U : table_stride; - runtime->freq_table_id = (table_length > 0U) ? freq_table_id : 0U; + runtime->table_length = table_length; /* 记下表长 */ + runtime->table_stride = (table_stride < 1U) ? 1U : table_stride; /* 步长至少1 */ + runtime->freq_table_id = (table_length > 0U) ? freq_table_id : 0U; /* 有长度才绑id,否则退回0=不用表 */ } diff --git a/plsr/accel_curve/plsr_accel_curve.h b/plsr/accel_curve/plsr_accel_curve.h index f498b1d..cd1422f 100644 --- a/plsr/accel_curve/plsr_accel_curve.h +++ b/plsr/accel_curve/plsr_accel_curve.h @@ -80,20 +80,23 @@ typedef struct { uint8_t freq_rising; /* 1=频率升高,0=降低 */ uint8_t is_active; /* 1=当前相仍在运行 */ uint8_t freq_table_id; /* 0=不用表,1=加速表,2=减速表 */ - PlsrAccelMode_e curve_mode; + PlsrAccelMode_e curve_mode; /* 直线 / S / 正弦 */ } PlsrAccelRuntime_t; /* 当前段唯一的曲线规划和逐拍状态,run_control 直接使用,不再另存副本。 */ -extern PlsrAccelPlan_t g_plsr_accel_plan; -extern PlsrAccelRuntime_t g_plsr_accel_runtime; +extern PlsrAccelPlan_t g_plsr_accel_plan; /* 本段三相规划结果 */ +extern PlsrAccelRuntime_t g_plsr_accel_runtime; /* 当前相 ISR 逐拍状态 */ /** PlanSeg 后调用:预建 S/正弦加减速频率表(勿在 ISR) */ void PlsrAccelPrebuildFreqTables(const PlsrAccelPlan_t *plan); +/** 进入加速相:起→峰,并绑加速预建表 */ void PlsrAccelBeginAccel(PlsrAccelRuntime_t *runtime, const PlsrAccelPlan_t *plan); +/** 进入减速相:峰→止,并绑减速预建表 */ void PlsrAccelBeginDecel(PlsrAccelRuntime_t *runtime, const PlsrAccelPlan_t *plan); +/** 进入匀速相:钉峰值,ISR 不再改频 */ void PlsrAccelBeginConstSpeed(PlsrAccelRuntime_t *runtime, const PlsrAccelPlan_t *plan); diff --git a/plsr/command/plsr_command.c b/plsr/command/plsr_command.c index 099e7ac..890a806 100644 --- a/plsr/command/plsr_command.c +++ b/plsr/command/plsr_command.c @@ -30,9 +30,9 @@ * s_live_freq_req — 运行中写频请求标志,Poll 消费后清 0 * s_live_freq_hz — 待应用的 new_tgt_hz */ -static uint16_t s_fault = PLSR_ERR_NONE; -static volatile uint8_t s_live_freq_req; -static volatile uint32_t s_live_freq_hz; +static uint16_t s_fault = PLSR_ERR_NONE; /* 故障码镜像,与 0x2006 同步 */ +static volatile uint8_t s_live_freq_req; /* 1=运行中改频待 Poll 消费 */ +static volatile uint32_t s_live_freq_hz; /* 待应用的新目标频率 Hz */ /** * @brief 写 32 位值到相邻两个modbus保持寄存器 @@ -57,9 +57,9 @@ static void PlsrCommandPublishMonitor(void) if (g_plsr_busy != 0U) { - PlsrCommandWriteDWord(PLSR_MON_FREQ_L, g_plsr_output_freq_hz); - WriteHoldReg(PLSR_MON_RUN_STATUS, 1U); - WriteHoldReg(PLSR_MON_CUR_SEG, (uint16_t)(g_plsr_cur_seg_idx + 1U)); + PlsrCommandWriteDWord(PLSR_MON_FREQ_L, g_plsr_output_freq_hz); /* 0x2002/03 当前频 */ + WriteHoldReg(PLSR_MON_RUN_STATUS, 1U); /* 0x2004 运行中 */ + WriteHoldReg(PLSR_MON_CUR_SEG, (uint16_t)(g_plsr_cur_seg_idx + 1U)); /* 0x2005 1-based */ } else { @@ -118,18 +118,18 @@ void PlsrCommandInit(void) */ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity) { - uint16_t cur_seg;//当前运行段 - uint16_t seg;//当前改频段 - uint16_t offset;//偏移量 + uint16_t cur_seg; /* 当前运行段(1-based) */ + uint16_t seg; /* 本次写入对应的段下标(0-based) */ + uint16_t offset; uint32_t freqency; if (quantity != 2U) { - return; + return; /* 须为频率双字 */ } if (g_plsr_busy == 0U) { - return; + return; /* 空闲改频走参数块,不走本路径 */ } if (start_addr < PLSR_REG_SEG1_BASE) { @@ -139,7 +139,7 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity) offset = (uint16_t)(start_addr - PLSR_REG_SEG1_BASE); if ((offset % PLSR_SEG_STRIDE) != PLSR_SEG_OFF_FREQ_L) { - return; + return; /* 地址须对齐该段 FREQ_L */ } seg = (uint16_t)(offset / PLSR_SEG_STRIDE); if (seg >= PLSR_SEG_MAX) @@ -150,24 +150,22 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity) cur_seg = (uint16_t)(g_plsr_cur_seg_idx + 1U); if ((cur_seg < 1U) || ((uint16_t)(cur_seg - 1U) != seg)) { - return; + return; /* 仅允许改当前运行段 */ } freqency = (uint32_t)ReadHoldReg(start_addr) | ((uint32_t)ReadHoldReg((uint16_t)(start_addr + 1U)) << 16); - /* 运行中改频非法不改段表、不请求 ChangeFreq */ if ((freqency < 1U) || (freqency > 100000U)) { - PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); + PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); /* 非法:不改段表、不请求 */ return; } - g_plsr_segs[seg].freq_hz = (int32_t)freqency; - /* 运行中改频只把该段频率写入 BKP */ - PlsrPersistSaveSegFreqToBkp(seg, freqency); + g_plsr_segs[seg].freq_hz = (int32_t)freqency; /* 更新运行段表 */ + PlsrPersistSaveSegFreqToBkp(seg, freqency); /* 仅该段频率落 BKP */ s_live_freq_hz = freqency; - s_live_freq_req = 1U; + s_live_freq_req = 1U; /* 交 Poll → ChangeFreq */ } /** @@ -183,63 +181,56 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity) void PlsrCommandPoll(void) { uint16_t ctrl = ReadHoldReg(PLSR_CTRL_REG); - uint8_t skip_monitor = 0U; + uint8_t skip_monitor = 0U; /* 精确等待时跳过本拍监控刷新 */ if (ctrl != 0U) { - WriteHoldReg(PLSR_CTRL_REG, 0U); + WriteHoldReg(PLSR_CTRL_REG, 0U); /* 立即清,避免重复触发 */ if ((ctrl & PLSR_CTRL_BIT_STOP) != 0U) { - PlsrStop();/*停止输出*/ + PlsrStop(); /* 急停 */ } if ((ctrl & PLSR_CTRL_BIT_CLR) != 0U) { - PlsrClearAccPulse();/*清零累计脉冲与绝对原点*/ - PlsrCommandClearFault(); /* 清零故障码同步清累计脉冲 */ + PlsrClearAccPulse(); /* 清累计 + 绝对原点 */ + PlsrCommandClearFault(); /* 同步清故障码 */ } - /* 同时有停止位时不启动 */ + /* START:同拍有 STOP 则不启 */ if (((ctrl & PLSR_CTRL_BIT_START) != 0U) && ((ctrl & PLSR_CTRL_BIT_STOP) == 0U)) { if (g_plsr_busy != 0U) { - /* 0x0C:运行中重复 START,启动无效 */ - PlsrCommandSetFault(PLSR_ERR_DUP_START); + PlsrCommandSetFault(PLSR_ERR_DUP_START); /* 0x0C 重复启动 */ } - /*如果禁止启动,使用停止指令*/ else if (PlsrCommandIsStartBlocked() != 0U) { - /* 0x04~0x0B 故障码:禁止启动 */ - PlsrStop(); + PlsrStop(); /* 0x04~0x0B:拒启,仅停 */ } - /*如果允许运行,先停止清标志位,再开始输出*/ else { - PlsrStop(); - /*启动输出入口*/ + PlsrStop(); /* 先清残留再启 */ (void)PlsrStart(PlsrParamGetStartSeg()); - /*如果不需要精确等待,就跳过监控*/ if (PlsrRunControlIsPreciseWait() != 0U) { - skip_monitor = 1U; + skip_monitor = 1U; /* 换向/WAIT 精确等 TIM5 */ } } } } - /* 动态改频:标志置位后按新目标重规划剩余脉冲 */ if (s_live_freq_req != 0U) { uint32_t freq = s_live_freq_hz; s_live_freq_req = 0U; - (void)PlsrChangeFreq(freq);/*动态改频函数入口*/ + (void)PlsrChangeFreq(freq); /* 重规划剩余脉冲 */ } if (skip_monitor == 0U) { - PlsrCommandPublishMonitor();/*刷新全部监控寄存器*/ + PlsrCommandPublishMonitor(); /* 回写 0x2000~0x2006 */ } } diff --git a/plsr/param/plsr_param.c b/plsr/param/plsr_param.c index 98cc3df..0ed229f 100644 --- a/plsr/param/plsr_param.c +++ b/plsr/param/plsr_param.c @@ -17,30 +17,30 @@ #include "modbus_rtu.h" #include "ucos_ii.h" -PlsrCfg_t g_plsr_config; -PlsrSeg_t g_plsr_segs[PLSR_SEG_MAX]; +PlsrCfg_t g_plsr_config; /* 公共参数运行映像 */ +PlsrSeg_t g_plsr_segs[PLSR_SEG_MAX]; /* 段表运行映像(最多 PLSR_SEG_MAX) */ static OS_EVENT *s_param_sem; /* 分帧收齐后唤醒 ParamBlockTask */ static volatile uint16_t s_expect_frames; /* 本批期望总帧数 = 5 + 段数 */ static volatile uint16_t s_recv_frames; /* 已收帧计数 */ static volatile uint8_t s_xfer_active; /* 1=正在接收一批分帧 */ -/** @return 有效段数,须在[0, PLSR_SEG_MAX]之间 */ +/** @return 有效段数,软钳到 [0, PLSR_SEG_MAX] */ uint16_t PlsrParamGetSegCount(void) { if (g_plsr_config.seg_count < 1U) { - return 0U; + return 0U; /* 无有效段 */ } if (g_plsr_config.seg_count > PLSR_SEG_MAX) { - return (uint16_t)PLSR_SEG_MAX; + return (uint16_t)PLSR_SEG_MAX; /* 超上限钳住 */ } return g_plsr_config.seg_count; } /** - * @brief 启动段 1-based + * @brief 启动段 1-based,软钳到 [1, seg_count] */ uint16_t PlsrParamGetStartSeg(void) { @@ -48,7 +48,7 @@ uint16_t PlsrParamGetStartSeg(void) if (n < 1U) { - return 1U; + return 1U; /* 无段时仍返回 1 */ } if (g_plsr_config.start_seg < 1U) { @@ -56,7 +56,7 @@ uint16_t PlsrParamGetStartSeg(void) } if (g_plsr_config.start_seg > n) { - return n; + return n; /* 超出则钳到末段 */ } return g_plsr_config.start_seg; } @@ -120,6 +120,7 @@ static uint8_t PlsrParamIsSegFrameWrite(uint16_t start_addr, uint16_t quantity) #define PLSR_PARAM_SPD_MIN_HZ 1U #define PLSR_PARAM_SPD_MAX_HZ 100000U +/** 速度 Hz 是否落在 [1, 100k](默认速度/段频非 0) */ static uint8_t PlsrParamIsSpeedHzValid(uint32_t hz) { return ((hz >= PLSR_PARAM_SPD_MIN_HZ) && (hz <= PLSR_PARAM_SPD_MAX_HZ)) ? 1U : 0U; @@ -181,41 +182,41 @@ uint8_t PlsrParamBlockApplyFromHold(void) uint16_t base; uint16_t fault = PLSR_ERR_NONE; - g_plsr_config.pulse_y = ReadHoldReg(PLSR_REG_PULSE_Y); + g_plsr_config.pulse_y = ReadHoldReg(PLSR_REG_PULSE_Y); /* 脉冲端子 Y0~Y2 */ if (g_plsr_config.pulse_y > 2U) { - fault = PLSR_ERR_PULSE_Y; + fault = PLSR_ERR_PULSE_Y; /* 0x07:端子非法 */ } - g_plsr_config.dir_y = ReadHoldReg(PLSR_REG_DIR_Y); + g_plsr_config.dir_y = ReadHoldReg(PLSR_REG_DIR_Y); /* 方向端子须为 Y3 */ if (g_plsr_config.dir_y != 3U) { - fault = PLSR_ERR_DIR_Y; + fault = PLSR_ERR_DIR_Y; /* 0x08 */ } - g_plsr_config.wait_x_sel = ReadHoldReg(PLSR_REG_WAIT_X) ? 1U : 0U; - g_plsr_config.ext_x_sel = ReadHoldReg(PLSR_REG_EXT_X) ? 1U : 0U; + g_plsr_config.wait_x_sel = ReadHoldReg(PLSR_REG_WAIT_X) ? 1U : 0U; /* 0=X4,1=X5 */ + g_plsr_config.ext_x_sel = ReadHoldReg(PLSR_REG_EXT_X) ? 1U : 0U; /* 0=X4,1=X5 */ g_plsr_config.send_mode = (PlsrSendMode_e)(ReadHoldReg(PLSR_REG_SEND_MODE) ? 1U : 0U); - g_plsr_config.dir_delay_ms = ReadHoldReg(PLSR_REG_DIR_DELAY); + g_plsr_config.dir_delay_ms = ReadHoldReg(PLSR_REG_DIR_DELAY); /* 换向延时 ms */ g_plsr_config.dir_logic = (ReadHoldReg(PLSR_REG_DIR_LOGIC) != 0U) ? - PLSR_DIR_LOGIC_NEG : PLSR_DIR_LOGIC_POS; + PLSR_DIR_LOGIC_NEG : PLSR_DIR_LOGIC_POS; /* 方向电平逻辑 */ g_plsr_config.accel_mode = (PlsrAccelMode_e)ReadHoldReg(PLSR_REG_ACCEL_MODE); g_plsr_config.run_mode = (ReadHoldReg(PLSR_REG_RUN_MODE) != 0U) ? - PLSR_POS_ABSOLUTE : PLSR_POS_RELATIVE; + PLSR_POS_ABSOLUTE : PLSR_POS_RELATIVE; /* 绝对/相对 */ n = ReadHoldReg(PLSR_REG_SEG_COUNT); g_plsr_config.seg_count = n; if ((n < 1U) || (n > PLSR_SEG_MAX)) { - fault = PLSR_ERR_SEG_COUNT; + fault = PLSR_ERR_SEG_COUNT; /* 0x09:段数越界 */ } - g_plsr_config.start_seg = ReadHoldReg(PLSR_REG_START_SEG); + g_plsr_config.start_seg = ReadHoldReg(PLSR_REG_START_SEG); /* 1-based 启动段 */ if ((n >= 1U) && (n <= PLSR_SEG_MAX)) { if ((g_plsr_config.start_seg < 1U) || (g_plsr_config.start_seg > n)) { - fault = PLSR_ERR_START_SEG; + fault = PLSR_ERR_START_SEG; /* 0x0A:启动段越界 */ } } else if (g_plsr_config.start_seg < 1U) @@ -226,23 +227,23 @@ uint8_t PlsrParamBlockApplyFromHold(void) g_plsr_config.default_speed = PlsrParamReadDWord(PLSR_REG_DEFAULT_SPD_L); if (PlsrParamIsSpeedHzValid(g_plsr_config.default_speed) == 0U) { - fault = PLSR_ERR_DEFAULT_SPD; + fault = PLSR_ERR_DEFAULT_SPD; /* 0x0B:默认速度非法 */ } - g_plsr_config.start_speed = PlsrParamReadDWord(PLSR_REG_START_SPD_L); + g_plsr_config.start_speed = PlsrParamReadDWord(PLSR_REG_START_SPD_L); /* 起跳频,0 合法 */ if (PlsrParamIsStartEndSpeedValid(g_plsr_config.start_speed) == 0U) { fault = PLSR_ERR_START_END_SPD; } - g_plsr_config.end_speed = PlsrParamReadDWord(PLSR_REG_END_SPD_L); + g_plsr_config.end_speed = PlsrParamReadDWord(PLSR_REG_END_SPD_L); /* 止速,0 合法 */ if (PlsrParamIsStartEndSpeedValid(g_plsr_config.end_speed) == 0U) { fault = PLSR_ERR_START_END_SPD; } - g_plsr_config.accel_ms = ReadHoldReg(PLSR_REG_ACCEL_MS); - g_plsr_config.decel_ms = ReadHoldReg(PLSR_REG_DECEL_MS); + g_plsr_config.accel_ms = ReadHoldReg(PLSR_REG_ACCEL_MS); /* 加速参考时间 */ + g_plsr_config.decel_ms = ReadHoldReg(PLSR_REG_DECEL_MS); /* 减速参考时间 */ if ((n >= 1U) && (n <= PLSR_SEG_MAX)) { @@ -253,32 +254,32 @@ uint8_t PlsrParamBlockApplyFromHold(void) (int32_t)PlsrParamReadDWord((uint16_t)(base + PLSR_SEG_OFF_FREQ_L)); if (PlsrParamIsSegFreqValid(g_plsr_segs[i].freq_hz) == 0U) { - fault = PLSR_ERR_FREQ_ILLEGAL; + fault = PLSR_ERR_FREQ_ILLEGAL; /* 0x04:段频率非法 */ } g_plsr_segs[i].pulse_cnt = (int32_t)PlsrParamReadDWord((uint16_t)(base + PLSR_SEG_OFF_PULSE_L)); if (PlsrParamIsPulseCntValid(g_plsr_segs[i].pulse_cnt) == 0U) { - fault = PLSR_ERR_PULSE_RANGE; + fault = PLSR_ERR_PULSE_RANGE; /* 0x05:脉冲数 INT_MIN */ } g_plsr_segs[i].wait_type = (PlsrWaitType_e)ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT)); g_plsr_segs[i].wait_ms = - ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT_MS)); + ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT_MS)); /* 段后等待 ms */ g_plsr_segs[i].act_ms = - ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_ACT_MS)); + ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_ACT_MS)); /* ACT 定时 ms */ g_plsr_segs[i].jump_seg = - ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_JUMP)); + ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_JUMP)); /* 跳转目标段 */ } } - PlsrCommandSetFault(fault); + PlsrCommandSetFault(fault); /* 写 0x2006 镜像 */ if (fault == PLSR_ERR_NONE) { - return 1U; + return 1U; /* 可落存 BKP */ } return 0U; } @@ -301,32 +302,33 @@ void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity) if ((start_addr == PLSR_REG_COMMON_F1_BASE) && (quantity >= PLSR_PARAM_COMMON_FRAME1_WORDS)) { + /* 公共帧 1:开新一批,期望 5+段数 */ uint16_t seg_n = ReadHoldReg(PLSR_REG_SEG_COUNT); if (seg_n > PLSR_SEG_MAX) { - seg_n = (uint16_t)PLSR_SEG_MAX; + seg_n = (uint16_t)PLSR_SEG_MAX; /* 计数软钳,避免 expect 溢出 */ } s_expect_frames = (uint16_t)(PLSR_PARAM_COMMON_FRAMES + seg_n); - s_recv_frames = 1U; - s_xfer_active = 1U; + s_recv_frames = 1U; /* 帧 1 已计入 */ + s_xfer_active = 1U; /* 开始收批 */ } else if ((s_xfer_active != 0U) && ((PlsrParamIsCommonTailFrameWrite(start_addr, quantity) != 0U) || (PlsrParamIsSegFrameWrite(start_addr, quantity) != 0U))) { - s_recv_frames++; + s_recv_frames++; /* 公共帧 2~5 或段帧 +1 */ } else { - return; + return; /* 非本批帧 / 未开批 → 忽略 */ } if ((s_xfer_active != 0U) && (s_recv_frames >= s_expect_frames)) { - s_xfer_active = 0U; + s_xfer_active = 0U; /* 收齐 */ if (s_param_sem != (OS_EVENT *)0) { - (void)OSSemPost(s_param_sem); + (void)OSSemPost(s_param_sem); /* 唤醒 ParamBlockTask */ } } } diff --git a/plsr/plsr.c b/plsr/plsr.c index b728e2b..a45367b 100644 --- a/plsr/plsr.c +++ b/plsr/plsr.c @@ -50,7 +50,7 @@ void PlsrInit(void) */ void PlsrTask(void *pArg) { - static uint8_t s_booted = 0U; + static uint8_t s_booted = 0U; /* 1=已完成首次延迟对齐(等 Modbus 填 hold) */ (void)pArg; diff --git a/plsr/plsr.h b/plsr/plsr.h index 64228d7..e0dca89 100644 --- a/plsr/plsr.h +++ b/plsr/plsr.h @@ -25,9 +25,9 @@ #include /* run_control 拥有的共享运行状态;段下标从 0 开始。 */ -extern volatile uint8_t g_plsr_busy; -extern volatile uint16_t g_plsr_cur_seg_idx; -extern volatile int32_t g_plsr_accumulated_pulses; +extern volatile uint8_t g_plsr_busy; /* 运行忙标志(上位机监控) */ +extern volatile uint16_t g_plsr_cur_seg_idx; /* 当前段下标(0-based) */ +extern volatile int32_t g_plsr_accumulated_pulses; /* 全局累计脉冲(有符号) */ #include "plsr_param.h" /** diff --git a/plsr/pulse_driver/plsr_pulse_driver.c b/plsr/pulse_driver/plsr_pulse_driver.c index 296b5ee..38c1433 100644 --- a/plsr/pulse_driver/plsr_pulse_driver.c +++ b/plsr/pulse_driver/plsr_pulse_driver.c @@ -12,14 +12,21 @@ * 关键数据流 * PlanSeg → LockPscRange → DIR_WAIT → Start → ISR SetFreqIsr(只改 ARR) * 段末 ArmSegEndStop → AfterSegDone Stop / FOLLOW ClearOnePulseStop + * + * 脉冲三路定时器(本文件): + * TIM10 CH1 → PF6 = Y0,时钟 168MHz(APB2) + * TIM11 CH1 → PF7 = Y2,时钟 168MHz(APB2) + * TIM13 CH1 → PF8 = Y1,时钟 84MHz(APB1) ※端子号与 TIM 交叉 + * TIM5 不在本文件(signal_io 换向/WAIT 延时) + * Y3=PF9 方向 GPIO,不是定时器 */ #include "plsr_pulse_driver.h" #include "plsr_param.h" #include "main.h" -TIM_HandleTypeDef htim10; -TIM_HandleTypeDef htim11; -TIM_HandleTypeDef htim13; +TIM_HandleTypeDef htim10; /* TIM10:Y0 / PF6 / CH1 */ +TIM_HandleTypeDef htim11; /* TIM11:Y2 / PF7 / CH1 */ +TIM_HandleTypeDef htim13; /* TIM13:Y1 / PF8 / CH1(端子号与 TIM 交叉) */ #define PLSR_TIM_CLK_APB2_HZ 168000000UL /* TIM10 / TIM11 */ #define PLSR_TIM_CLK_APB1_HZ 84000000UL /* TIM13 */ @@ -31,35 +38,33 @@ TIM_HandleTypeDef htim13; #define PLSR_Y2_PORT GPIOF #define PLSR_Y2_PIN GPIO_PIN_7 /* TIM11 */ #define PLSR_Y3_PORT GPIOF -#define PLSR_Y3_PIN GPIO_PIN_9 - -volatile uint32_t g_plsr_output_freq_hz; -volatile uint8_t g_plsr_pwm_running; -uint8_t g_plsr_direction_forward; -uint8_t g_plsr_direction_valid; -static uint32_t s_last_psc = 0xFFFFFFFFUL; -static uint32_t s_last_arr = 0xFFFFFFFFUL; -static uint32_t s_last_ccr; -static TIM_HandleTypeDef *s_active_htim; - -static uint8_t s_psc_locked; -static uint32_t s_locked_psc; - -static volatile uint32_t s_req_freq; -static volatile uint8_t s_req_pending; -/* - * 1=DIR_WAIT 已装载寄存器且 CEN 关:到期 Commit 前必须 CNT=0 再开 PWM。 - */ +#define PLSR_Y3_PIN GPIO_PIN_9 /* 方向脚,纯 GPIO,无定时器 */ + +volatile uint32_t g_plsr_output_freq_hz; /* 当前输出频率 Hz(监控) */ +volatile uint8_t g_plsr_pwm_running; /* 1=PWM 正在跑 */ +uint8_t g_plsr_direction_forward; /* 1=正转方向 */ +uint8_t g_plsr_direction_valid; /* 1=方向脚已有效写出 */ +static uint32_t s_last_psc = 0xFFFFFFFFUL; /* 上次写入的 PSC(未装载=全 F) */ +static uint32_t s_last_arr = 0xFFFFFFFFUL; /* 上次 ARR */ +static uint32_t s_last_ccr; /* 上次 CCR(约 50% 占空) */ +static TIM_HandleTypeDef *s_active_htim; /* 当前选中的脉冲 TIM */ + +static uint8_t s_psc_locked; /* 1=本段已锁 PSC,只改 ARR */ +static uint32_t s_locked_psc; /* 锁定的 PSC 值 */ + +static volatile uint32_t s_req_freq; /* ISR 挂起改频目标 Hz */ +static volatile uint8_t s_req_pending; /* 1=有挂起改频,任务 ApplyPending */ +/* 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 下降沿后强制拉低 */ +static volatile uint8_t s_seg_end_fall_armed; /* 1=已武装末拍 CC1 下降沿拉低 */ /* * 冷启动首拍保护:Commit 后第一次 SetFreqIsr 必须先钉住工作 ARR=起跳频, * 再把下一拍写入影子。否则 ARPE 未生效时 ISR 会直接改写工作寄存器, * 示波器上首周期频率变成「第 2 个脉冲」的频率(起跳越高越明显)。 */ -static volatile uint8_t s_protect_start_period; -static uint32_t s_protect_arr; -static uint32_t s_protect_ccr; +static volatile uint8_t s_protect_start_period; /* 1=首拍须钉住工作 ARR */ +static uint32_t s_protect_arr; /* 首拍保护用 ARR */ +static uint32_t s_protect_ccr; /* 首拍保护用 CCR */ /*============================================================================*/ /* 路选择 / 时钟 / GPIO */ @@ -73,23 +78,23 @@ static TIM_HandleTypeDef *PlsrPulseDriverHtimByY(uint16_t pulse_y) { if (pulse_y == 1U) { - return &htim13; + return &htim13; /* Y1 → TIM13 CH1 → PF8(APB1 84MHz) */ } if (pulse_y == 2U) { - return &htim11; + return &htim11; /* Y2 → TIM11 CH1 → PF7(APB2 168MHz) */ } - return &htim10; + return &htim10; /* Y0(默认)→ TIM10 CH1 → PF6(APB2 168MHz) */ } /** @brief 从公共参数取脉冲端子,越界钳到 Y0 */ static uint8_t PlsrPulseDriverSelectY(void) { - uint16_t y = g_plsr_config.pulse_y; + uint16_t y = g_plsr_config.pulse_y; /* 公共参数:0=Y0/TIM10,1=Y1/TIM13,2=Y2/TIM11 */ if (y > 2U) { - y = 0U; + y = 0U; /* 非法端子 → 钳到 Y0(TIM10/PF6) */ } return (uint8_t)y; } @@ -100,9 +105,9 @@ static uint32_t PlsrPulseDriverTimClkHz(const TIM_HandleTypeDef *htim) if ((htim != (const TIM_HandleTypeDef *)0) && (htim->Instance == TIM13)) { - return PLSR_TIM_CLK_APB1_HZ; + return PLSR_TIM_CLK_APB1_HZ; /* TIM13(Y1/PF8):APB1 定时器时钟 84MHz */ } - return PLSR_TIM_CLK_APB2_HZ; + return PLSR_TIM_CLK_APB2_HZ; /* TIM10(Y0)或 TIM11(Y2):APB2 定时器时钟 168MHz */ } /** @brief 初始化 Y3 方向脚为推挽输出低 */ @@ -110,30 +115,33 @@ static void PlsrPulseDriverDirGpioInit(void) { GPIO_InitTypeDef gpio = {0}; - __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); /* 打开 GPIOF 时钟(Y0~Y3 都在 PF) */ - gpio.Pin = PLSR_Y3_PIN; - gpio.Mode = GPIO_MODE_OUTPUT_PP; + gpio.Pin = PLSR_Y3_PIN; /* PF9 = Y3 方向,不是定时器 */ + gpio.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */ gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(PLSR_Y3_PORT, &gpio); - HAL_GPIO_WritePin(PLSR_Y3_PORT, PLSR_Y3_PIN, GPIO_PIN_RESET); + HAL_GPIO_WritePin(PLSR_Y3_PORT, PLSR_Y3_PIN, GPIO_PIN_RESET); /* 空闲方向脚拉低 */ } - /*关掉末拍下降沿再锁低这套 CC1 监听;脚怎么拉低在下面的两个函数*/ +/** + * @brief 撤 CC1 下降沿武装(关 CC1 IT、清标志) + * @note 不清 Forced inactive、不停表;拉低请走 OcForceLowKeepRun / OcHoldLow + */ static void PlsrPulseDriverClearSegEndFallArm(TIM_HandleTypeDef *htim) { - s_seg_end_fall_armed = 0U;/*末拍 CC1 下降沿后强制拉低 */ + s_seg_end_fall_armed = 0U; /* 撤末拍下降沿武装标志(不是 Forced,只撤 CC1 武装) */ 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); + __HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1); /* 关 CC1 中断使能(DIER.CC1IE=0),撤武装 */ + __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC1); /* 清 SR.CC1IF,避免残留标志再进 ISR */ } /** - * 末拍下降沿:只切 Forced inactive 拉低,CEN/OPM/UPDATE 继续跑到周期结束。 + * @brief 末拍下降沿:只切 Forced inactive 拉低,CEN/OPM/UPDATE 继续跑到周期结束 */ static void PlsrPulseDriverOcForceLowKeepRun(TIM_HandleTypeDef *htim) { @@ -149,12 +157,12 @@ static void PlsrPulseDriverOcForceLowKeepRun(TIM_HandleTypeDef *htim) //- CC1E=0:通道输出关闭,引脚由 GPIO 寄存器控制。 ccmr &= (uint32_t)(~TIM_CCMR1_OC1M);//把[6:4]变成0 ccmr |= TIM_OCMODE_FORCED_INACTIVE;//写入0b100 强制无效模式到OC1M域 - htim->Instance->CCMR1 = ccmr; - htim->Instance->CCER |= TIM_CCER_CC1E; + htim->Instance->CCMR1 = ccmr; /* 写回 CCMR1:OC1M=Forced inactive → 比较输出强制无效电平(极性高时=低) */ + htim->Instance->CCER |= TIM_CCER_CC1E; /* CC1E=1:通道输出仍接到 GPIO,Forced 才能真正把脚拉低 */ } /** - * Forced inactive 拉低,关掉并清标志 + * @brief Forced inactive 拉低,并关 CEN/OPM/UPDATE(完整停通道) */ static void PlsrPulseDriverOcHoldLow(TIM_HandleTypeDef *htim) { @@ -165,19 +173,21 @@ static void PlsrPulseDriverOcHoldLow(TIM_HandleTypeDef *htim) return; } - __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); - PlsrPulseDriverClearSegEndFallArm(htim); - htim->Instance->CR1 &= (uint32_t)(~(TIM_CR1_CEN | TIM_CR1_OPM)); + __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); /* 关 UPDATE 中断(DIER.UIE=0),停表后不再进脉冲 ISR */ + PlsrPulseDriverClearSegEndFallArm(htim); /* 撤 CC1 武装(关 CC1 IT),不是 Forced */ + htim->Instance->CR1 &= (uint32_t)(~(TIM_CR1_CEN | TIM_CR1_OPM)); /* 清 CEN=停计数;清 OPM=退出单脉冲模式 */ - 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; + ccmr = htim->Instance->CCMR1;//Output Compare 1 Mode,输出比较 1 模式 + //- CC1E=1:OC 通道输出到 GPIO 引脚; + //- CC1E=0:通道输出关闭,引脚由 GPIO 寄存器控制。 + ccmr &= (uint32_t)(~TIM_CCMR1_OC1M);//把[6:4]变成0 + ccmr |= TIM_OCMODE_FORCED_INACTIVE;//写入0b100 强制无效模式到OC1M域 + htim->Instance->CCMR1 = ccmr; /* 写回:OC1M=Forced inactive,空闲主动拉低 */ + htim->Instance->CCER |= TIM_CCER_CC1E; /* 保持 CC1E=1,不关通道,避免 AF 高阻耦合假脉冲 */ - __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); - __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); - TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY); + __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); /* 清 SR.UIF */ + __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); /* 清 UPDATE 中断挂起 */ + TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY); /* HAL 通道状态回到 READY */ } /** @@ -188,40 +198,41 @@ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef gpio = {0}; - __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); /* Y0/Y1/Y2 脉冲脚都在 GPIOF */ - gpio.Mode = GPIO_MODE_AF_PP; + gpio.Mode = GPIO_MODE_AF_PP; /* 复用推挽:TIM CH1 驱动引脚 */ /* 下拉:通道若短暂高阻时保持低,避免上拉导致看不到开表上升沿 */ gpio.Pull = GPIO_PULLDOWN; gpio.Speed = GPIO_SPEED_FREQ_HIGH; if (htim->Instance == TIM10) { - __HAL_RCC_TIM10_CLK_ENABLE(); - gpio.Pin = PLSR_Y0_PIN; - gpio.Alternate = GPIO_AF3_TIM10; + /* TIM10 CH1 → PF6 = Y0,IRQ=TIM1_UP_TIM10 */ + __HAL_RCC_TIM10_CLK_ENABLE(); /* 打开 TIM10 外设时钟(APB2) */ + gpio.Pin = PLSR_Y0_PIN; /* PF6 */ + gpio.Alternate = GPIO_AF3_TIM10; /* AF3:TIM10_CH1 */ HAL_GPIO_Init(PLSR_Y0_PORT, &gpio); - HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 5, 0); + HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 5, 0); /* TIM10 与 TIM1_UP 共用向量 */ HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn); } else if (htim->Instance == TIM11) { /* TIM11_CH1 = PF7 = Y2 */ - __HAL_RCC_TIM11_CLK_ENABLE(); - gpio.Pin = PLSR_Y2_PIN; - gpio.Alternate = GPIO_AF3_TIM11; + __HAL_RCC_TIM11_CLK_ENABLE(); /* 打开 TIM11 外设时钟(APB2) */ + gpio.Pin = PLSR_Y2_PIN; /* PF7 = Y2 */ + gpio.Alternate = GPIO_AF3_TIM11; /* AF3:TIM11_CH1 */ HAL_GPIO_Init(PLSR_Y2_PORT, &gpio); - HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 5, 0); + HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 5, 0); /* TIM11 共用 TIM1_TRG_COM 向量 */ HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn); } else if (htim->Instance == TIM13) { /* TIM13_CH1 = PF8 = Y1 */ - __HAL_RCC_TIM13_CLK_ENABLE(); - gpio.Pin = PLSR_Y1_PIN; - gpio.Alternate = GPIO_AF9_TIM13; + __HAL_RCC_TIM13_CLK_ENABLE(); /* 打开 TIM13 外设时钟(APB1,84MHz) */ + gpio.Pin = PLSR_Y1_PIN; /* PF8 = Y1(端子号与 TIM 交叉) */ + gpio.Alternate = GPIO_AF9_TIM13; /* AF9:TIM13_CH1 */ HAL_GPIO_Init(PLSR_Y1_PORT, &gpio); - HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 5, 0); + HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 5, 0); /* TIM13 与 TIM8_UP 共用向量 */ HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn); } } @@ -235,34 +246,34 @@ static void PlsrPulseDriverTimInitOne(TIM_HandleTypeDef *htim, TIM_TypeDef *inst { TIM_OC_InitTypeDef oc = {0}; - htim->Instance = inst; - htim->Init.Prescaler = 167U; - htim->Init.CounterMode = TIM_COUNTERMODE_UP; - htim->Init.Period = 999U; - htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim->Instance = inst; /* 绑定硬件:TIM10=Y0 / TIM11=Y2 / TIM13=Y1 */ + htim->Init.Prescaler = 167U; /* 初始 PSC=167 → 分频=168;稍后 LoadRegs 会按频率重算 */ + htim->Init.CounterMode = TIM_COUNTERMODE_UP; /* 向上计数:CNT 从 0 数到 ARR 产生 UPDATE */ + htim->Init.Period = 999U; /* 初始 ARR=999 → 周期计数=1000;正式运行前会被改写 */ + htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 死区/滤波时钟不分频 */ /* * ARR/CCR 预装载打开:改频只写入影子寄存器,在下一 UPDATE 生效。 * 避免关预装载时在 ISR 里直接改 ARR/CCR 产生毛刺边沿(段越长多计越多, * 如设定 5000 实测 5007)。软件侧超前一拍写频率补偿延迟。 * polarity极性 */ - htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* ARPE=1:写 ARR 进影子,UPDATE 时装入工作寄存器 */ if (HAL_TIM_PWM_Init(htim) != HAL_OK) { Error_Handler(); } - oc.OCMode = TIM_OCMODE_PWM1; - oc.Pulse = 500U; - oc.OCPolarity = TIM_OCPOLARITY_HIGH;//0高电平有效,1低电平有效 + oc.OCMode = TIM_OCMODE_PWM1; /* OC1M=PWM1:CNTInstance->CCMR1 |= TIM_CCMR1_OC1PE; + htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; /* OC1PE=1:写 CCR1 进影子,UPDATE 时装入,与 ARPE 配套 */ /* 复用保持:强制无效,推挽空闲拉低;开跑后 PWM1 每周期仍先高后低 */ - PlsrPulseDriverOcHoldLow(htim); + PlsrPulseDriverOcHoldLow(htim); /* CEN=0 + Forced inactive + CC1E=1:空闲脚低、计数停 */ } /** @brief 驱动初始化 */ @@ -282,12 +293,12 @@ void PlsrPulseDriverInit(void) s_protect_start_period = 0U; s_protect_arr = 0U; s_protect_ccr = 0U; - s_active_htim = &htim10; - PlsrPulseDriverDirGpioInit(); + s_active_htim = &htim10; /* 默认活动路:TIM10=Y0 */ + PlsrPulseDriverDirGpioInit(); /* Y3=PF9 方向脚 */ /* 三路都 Init + 空闲拉低,计数器关闭;出脉冲时只 Start 选中那路 */ - PlsrPulseDriverTimInitOne(&htim10, TIM10); - PlsrPulseDriverTimInitOne(&htim11, TIM11); - PlsrPulseDriverTimInitOne(&htim13, TIM13); + PlsrPulseDriverTimInitOne(&htim10, TIM10); /* TIM10 → PF6=Y0 */ + PlsrPulseDriverTimInitOne(&htim11, TIM11); /* TIM11 → PF7=Y2 */ + PlsrPulseDriverTimInitOne(&htim13, TIM13); /* TIM13 → PF8=Y1 */ } /** @brief 写方向脚 */ @@ -297,14 +308,14 @@ void PlsrPulseDriverSetDir(uint8_t forward) if (g_plsr_config.dir_logic == PLSR_DIR_LOGIC_POS) { - level = (forward != 0U) ? 1U : 0U; + level = (forward != 0U) ? 1U : 0U; /* 正逻辑:正转=高 */ } else { - level = (forward != 0U) ? 0U : 1U; + level = (forward != 0U) ? 0U : 1U; /* 负逻辑:正转=低 */ } HAL_GPIO_WritePin(PLSR_Y3_PORT, PLSR_Y3_PIN, - level ? GPIO_PIN_SET : GPIO_PIN_RESET); + level ? GPIO_PIN_SET : GPIO_PIN_RESET); /* 只动 Y3=PF9,不动任何 TIM */ g_plsr_direction_forward = (forward != 0U) ? 1U : 0U; g_plsr_direction_valid = 1U; } @@ -312,7 +323,7 @@ void PlsrPulseDriverSetDir(uint8_t forward) /** @brief 方向脚拉低 */ void PlsrPulseDriverClearDir(void) { - HAL_GPIO_WritePin(PLSR_Y3_PORT, PLSR_Y3_PIN, GPIO_PIN_RESET); + HAL_GPIO_WritePin(PLSR_Y3_PORT, PLSR_Y3_PIN, GPIO_PIN_RESET); /* Y3 拉低 */ g_plsr_direction_forward = 0U; g_plsr_direction_valid = 0U; } @@ -320,6 +331,7 @@ void PlsrPulseDriverClearDir(void) /** @brief 是否脉冲 TIM */ uint8_t PlsrPulseDriverIsPulseTim(TIM_TypeDef *instance) { + /* 本文件三路:TIM10=Y0、TIM11=Y2、TIM13=Y1;TIM5 不在此列 */ return ((instance == TIM10) || (instance == TIM11) || (instance == TIM13)) ? 1U : 0U; } @@ -335,6 +347,7 @@ uint8_t PlsrPulseDriverIsPulseTim(TIM_TypeDef *instance) * ccr — 比较值,PWM1 模式下高电平宽度 ≈ CCR 个计数(本驱动约 50% 占空) * 目标频率:ticks = clk_hz / freq_hz ≈ (PSC+1)×(ARR+1) */ +/** @brief 给定 PSC,算 ARR/CCR(约 50% 占空);freq 钳到 1~100k */ static void PlsrPulseDriverCalcArrWithPsc(uint32_t clk_hz, uint32_t freq_hz, uint32_t psc, uint32_t *arr, uint32_t *ccr) { @@ -344,46 +357,46 @@ static void PlsrPulseDriverCalcArrWithPsc(uint32_t clk_hz, uint32_t freq_hz, uin if (clk_hz < 1U) { - clk_hz = PLSR_TIM_CLK_APB2_HZ; + clk_hz = PLSR_TIM_CLK_APB2_HZ; /* 兜底按 APB2=168MHz(TIM10/11) */ } if (freq_hz < 1U) { - freq_hz = 1U; + freq_hz = 1U; /* 下限 1Hz */ } if (freq_hz > 100000U) { - freq_hz = 100000U; + freq_hz = 100000U; /* 上限 100kHz */ } - ticks = clk_hz / freq_hz; + ticks = clk_hz / freq_hz; /* ticks≈(PSC+1)×(ARR+1):一脉冲需要多少个计数时钟周期 */ if (ticks < 2UL) { - ticks = 2UL; + ticks = 2UL; /* 至少 2 tick,否则无边沿 */ } - - a = ticks / (psc + 1UL); + + a = ticks / (psc + 1UL); /* 周期计数个数 = ticks / 分频;稍后 a-=1 才是 ARR 寄存器值 */ if (a < 2UL) { - a = 2UL; + a = 2UL; /* ARR+1 至少为 2,保证能产生高低边沿 */ } if (a > 65536UL) { - a = 65536UL; + a = 65536UL; /* 16 位定时器:ARR+1 最大 65536 → ARR 最大 65535 */ } - a -= 1UL; + a -= 1UL; /* 寄存器值 = 周期计数 − 1 */ - c = (a + 1UL) / 2UL; + c = (a + 1UL) / 2UL; /* ≈50% 占空:CCR ≈ (ARR+1)/2 */ if (c == 0UL) { - c = 1UL; + c = 1UL; /* CCR 至少 1,避免 PWM1 整拍无高电平 */ } - *arr = a; - *ccr = c; + *arr = a; /* 写出 ARR 寄存器值 */ + *ccr = c; /* 写出 CCR 寄存器值 */ } /** - * @brief 自适应选择 PSC,再算 ARR/CCR(未锁 PSC 时用) + * @brief 自适应选 PSC,再算 ARR/CCR(未锁 PSC 时用) */ static void PlsrPulseDriverCalcPscArr(uint32_t clk_hz, uint32_t freq_hz, uint32_t *psc, uint32_t *arr, uint32_t *ccr) @@ -404,29 +417,31 @@ static void PlsrPulseDriverCalcPscArr(uint32_t clk_hz, uint32_t freq_hz, freq_hz = 100000U; } - ticks = clk_hz / freq_hz; + ticks = clk_hz / freq_hz; /* 同上:一脉冲所需计数时钟 tick 数 */ if (ticks < 2UL) { - ticks = 2UL; + ticks = 2UL; /* 至少 2 tick */ } - p = (ticks + 65536UL - 1UL) / 65536UL; + /* 选最小 PSC 使 ARR 落在 16 位内 */ + p = (ticks + 65536UL - 1UL) / 65536UL; /* 向上取整:需要的最小分频倍数 (PSC+1) */ if (p == 0UL) { - p = 1UL; + p = 1UL; /* 分频至少 1(即 PSC=0) */ } - p -= 1UL; + p -= 1UL; /* 分频倍数 → PSC 寄存器值 */ if (p > 65535UL) { - p = 65535UL; + p = 65535UL; /* PSC 也是 16 位 */ } *psc = p; - PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, p, arr, ccr); + PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, p, arr, ccr); /* 用选定 PSC 再算 ARR/CCR */ } -/** @brief 按频率跨度锁 PSC - * 1 个 tick = TIM 输入时钟的 1 个周期。ticks = 输出 1 个脉冲要占多少个这种小时钟周期。 +/** + * @brief 按频率跨度锁单一 PSC(段内只改 ARR) + * @note ticks = 一脉冲所需计数时钟周期数 */ void PlsrPulseDriverLockPscRange(uint32_t f_min_hz, uint32_t f_max_hz) { @@ -435,9 +450,8 @@ void PlsrPulseDriverLockPscRange(uint32_t f_min_hz, uint32_t f_max_hz) uint32_t psc_div_max; uint32_t psc_div_min; uint32_t div; - /*获取Y端子的时钟频率,Y0/Y1为168MHz,Y2为84MHz */ uint32_t clk_hz = PlsrPulseDriverTimClkHz( - PlsrPulseDriverHtimByY(PlsrPulseDriverSelectY())); + PlsrPulseDriverHtimByY(PlsrPulseDriverSelectY())); /* Y0/Y2=168M,Y1=84M */ if (f_min_hz < 1U) { @@ -447,17 +461,15 @@ void PlsrPulseDriverLockPscRange(uint32_t f_min_hz, uint32_t f_max_hz) { f_max_hz = 1U; } - /*如果最小值小于最大值,则交换最小值与最大值*/ - if (f_max_hz < f_min_hz) + if (f_max_hz < f_min_hz) /* 交换,保证 min≤max */ { uint32_t temp = f_min_hz; f_min_hz = f_max_hz; f_max_hz = temp; } - ticks_max = clk_hz / f_min_hz;/*最大tick数=系统频率/最小频率*/ - ticks_min = clk_hz / f_max_hz;/*最小tick数=系统频率/最大频率*/ - /*如果tick数小于2,则改为2,因为tick=(psc+1)(arr+1),psc可以为0,但arr不能为0,否则输出单一电平*/ + ticks_max = clk_hz / f_min_hz; /* 低频 → 最大 tick(周期最长) */ + ticks_min = clk_hz / f_max_hz; /* 高频 → 最小 tick(周期最短) */ if (ticks_max < 2UL) { ticks_max = 2UL; @@ -467,34 +479,29 @@ void PlsrPulseDriverLockPscRange(uint32_t f_min_hz, uint32_t f_max_hz) ticks_min = 2UL; } - /* psc_div = PSC+1:低频要求 psc 足够大,高频要求 psc 足够小 */ - /* psc = tick / (ARR + 1) ,当arr+1最大时,psc为最小值,再小就不满足乘积=tick*/ - psc_div_min = (ticks_max + 65535UL) / 65536UL; + /* psc_div=PSC+1:低频要够大、高频要够小 */ + psc_div_min = (ticks_max + 65535UL) / 65536UL; /* ARR 顶满(65535)时,盖住低频所需的最小分频 */ if (psc_div_min < 1UL) { psc_div_min = 1UL; } - /* psc = tick / (ARR + 1) ,当arr+1最小时,psc为最大值,再大就不满足乘积=tick*/ - psc_div_max = ticks_min / 2UL; + psc_div_max = ticks_min / 2UL; /* ARR 至少 2 时,高频允许的最大分频 */ if (psc_div_max < 1UL) { - psc_div_max = 1UL;/* psc的最大值最小为1,最小值可以为0 */ + psc_div_max = 1UL; } if (psc_div_min > psc_div_max) { - /* - * 单一 PSC 无法同时覆盖 f_min~f_max(例如 1Hz~很高频)。 - * 不锁死,交由 SetFreq 按频率自适应 PSC,避免高频被算成平台方波。 - */ + /* 单一 PSC 盖不住跨度 → 不锁,交 SetFreq 自适应 */ s_psc_locked = 0U; s_locked_psc = 0U; return; } - div = psc_div_min;/*取最小的psc作为psc锁定,让arr尽可能大,提高分辨率*/ - s_locked_psc = div - 1UL; - s_psc_locked = 1U; + div = psc_div_min; /* 取最小分频,ARR 尽量大以提高分辨率 */ + s_locked_psc = div - 1UL; /* 分频倍数 → PSC 寄存器值 */ + s_psc_locked = 1U; /* 本段锁住:ISR/SetFreq 只改 ARR,不换 PSC */ } /** @brief 解除 PSC 锁 */ @@ -507,7 +514,7 @@ void PlsrPulseDriverUnlockPsc(void) /** @brief 停单路:Forced inactive 拉低,关 CEN/UPDATE */ static void PlsrPulseDriverStopHtim(TIM_HandleTypeDef *htim) { - PlsrPulseDriverOcHoldLow(htim); + PlsrPulseDriverOcHoldLow(htim); /* 完整停通道:关 CEN/OPM/IT + Forced 拉低 */ } /*============================================================================*/ @@ -515,21 +522,20 @@ static void PlsrPulseDriverStopHtim(TIM_HandleTypeDef *htim) /*============================================================================*/ /** - * 关预装载后直写 ARR/CCR 工作寄存器,再打开预装载并复写影子。 - * 仅 UG 不可靠时(首拍 CCR 工作值仍为 0):CNT=0 也会整拍无高电平, - * 示波器上与「CNT>CCR 空等近一周期」无法区分。 + * @brief 关预装载后直写 ARR/CCR 工作寄存器,再打开预装载并复写影子 + * @note 仅 UG 不可靠时(首拍 CCR 工作值仍为 0)使用:避免 CNT=0 整拍无高电平 */ static void PlsrPulseDriverForceArrCcr(TIM_HandleTypeDef *htim, uint32_t arr, uint32_t ccr) { - htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); - htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); - htim->Instance->ARR = arr; - htim->Instance->CCR1 = ccr; - htim->Instance->CR1 |= TIM_CR1_ARPE; - htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; - htim->Instance->ARR = arr; - htim->Instance->CCR1 = ccr; + htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); /* 清 ARPE:随后写 ARR 直达工作寄存器 */ + htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); /* 清 OC1PE:随后写 CCR1 直达工作寄存器 */ + htim->Instance->ARR = arr; /* 直写工作 ARR(本周期立刻用这套周期) */ + htim->Instance->CCR1 = ccr; /* 直写工作 CCR1(本周期立刻用这套占空) */ + htim->Instance->CR1 |= TIM_CR1_ARPE; /* 再开 ARPE:之后写 ARR 进影子 */ + htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; /* 再开 OC1PE:之后写 CCR 进影子 */ + htim->Instance->ARR = arr; /* 复写影子 ARR,与工作值一致,避免影子残留旧频 */ + htim->Instance->CCR1 = ccr; /* 复写影子 CCR1,与工作值一致 */ } /** @@ -541,44 +547,44 @@ static void PlsrPulseDriverLoadRegs(uint32_t freq_hz) uint32_t psc; uint32_t arr; uint32_t ccr; - uint8_t y = PlsrPulseDriverSelectY(); - TIM_HandleTypeDef *htim = PlsrPulseDriverHtimByY(y); + uint8_t y = PlsrPulseDriverSelectY(); /* 当前配置的 Y0/Y1/Y2 */ + TIM_HandleTypeDef *htim = PlsrPulseDriverHtimByY(y); /* 映射到 TIM10/13/11 */ uint32_t clk_hz; - s_req_pending = 0U; + s_req_pending = 0U; /* 重装寄存器时丢弃 ISR 挂起改频 */ if ((s_active_htim != (TIM_HandleTypeDef *)0) && (s_active_htim != htim)) { - PlsrPulseDriverStopHtim(s_active_htim); + PlsrPulseDriverStopHtim(s_active_htim); /* 换路:先停旧 TIM,避免两路同时出脉冲 */ } - s_active_htim = htim; - clk_hz = PlsrPulseDriverTimClkHz(htim); + s_active_htim = htim; /* 记下当前活动定时器 */ + clk_hz = PlsrPulseDriverTimClkHz(htim); /* TIM10/11→168M,TIM13→84M */ if (freq_hz == 0U) { - PlsrPulseDriverStopHtim(htim); + PlsrPulseDriverStopHtim(htim); /* freq=0:停表 + Forced 拉低 */ g_plsr_output_freq_hz = 0U; g_plsr_pwm_running = 0U; s_last_psc = 0xFFFFFFFFUL; s_last_arr = 0xFFFFFFFFUL; s_last_ccr = 0U; - s_regs_prepared = 0U; + s_regs_prepared = 0U; /* 未处于「已预装待 Commit」状态 */ return; } if (s_psc_locked != 0U) { - psc = s_locked_psc; + psc = s_locked_psc; /* 段内锁 PSC:只用锁定值算 ARR */ PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, psc, &arr, &ccr); } else { - PlsrPulseDriverCalcPscArr(clk_hz, freq_hz, &psc, &arr, &ccr); + PlsrPulseDriverCalcPscArr(clk_hz, freq_hz, &psc, &arr, &ccr); /* 未锁:自适应选 PSC+ARR */ } if (ccr < 1U) { - ccr = 1U; + ccr = 1U; /* CCR 最小 1,保证 PWM1 有高电平段 */ } g_plsr_output_freq_hz = freq_hz; @@ -586,22 +592,22 @@ static void PlsrPulseDriverLoadRegs(uint32_t freq_hz) s_last_arr = arr; s_last_ccr = ccr; - __HAL_TIM_DISABLE(htim); - __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); - htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_OPM); + __HAL_TIM_DISABLE(htim); /* CEN=0:关计数,DIR_WAIT 期间禁止空转 */ + __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); /* 关 UPDATE IT,装载过程不进 ISR */ + htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_OPM); /* 清 OPM:退出单脉冲,恢复连续可跑 */ - __HAL_TIM_SET_PRESCALER(htim, psc); - PlsrPulseDriverForceArrCcr(htim, arr, ccr); + __HAL_TIM_SET_PRESCALER(htim, psc); /* 写 PSC(预分频);真正生效要靠后面 UG */ + PlsrPulseDriverForceArrCcr(htim, arr, ccr); /* 直写工作+影子 ARR/CCR */ - PlsrPulseDriverOcHoldLow(htim); + PlsrPulseDriverOcHoldLow(htim); /* Forced inactive 拉低 + 关 CEN/OPM/IT */ /* UG:PSC 生效;随后再钉 ARR/CCR/CNT,避免只进影子 */ - htim->Instance->EGR = TIM_EGR_UG; - __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); + htim->Instance->EGR = TIM_EGR_UG; /* 软件触发 UPDATE:装入 PSC,并产生一次更新事件 */ + __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); /* 清 UG 带来的 UIF,避免误进 ISR */ __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); - PlsrPulseDriverForceArrCcr(htim, arr, ccr); - htim->Instance->CNT = 0U; + PlsrPulseDriverForceArrCcr(htim, arr, ccr); /* UG 可能改动工作值,再钉一次 ARR/CCR */ + htim->Instance->CNT = 0U; /* 计数归零;此时仍 CEN=0,等 Commit 再开 */ - s_regs_prepared = 1U; + s_regs_prepared = 1U; /* 标记:寄存器已预装,Commit 可直接开沿 */ } /** @@ -614,7 +620,7 @@ static void PlsrPulseDriverLoadRegs(uint32_t freq_hz) */ static void PlsrPulseDriverCommitOutput(void) { - TIM_HandleTypeDef *htim = s_active_htim; + TIM_HandleTypeDef *htim = s_active_htim; /* 当前活动路:TIM10/11/13 之一 */ uint32_t ccmr; uint32_t ccr; @@ -623,16 +629,16 @@ static void PlsrPulseDriverCommitOutput(void) return; } - ccr = (s_last_ccr < 1U) ? 1U : s_last_ccr; + ccr = (s_last_ccr < 1U) ? 1U : s_last_ccr; /* 用 LoadRegs 记下的 CCR,至少为 1 */ - __HAL_TIM_DISABLE(htim); - __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); + __HAL_TIM_DISABLE(htim); /* 开沿前先确保 CEN=0,寄存器改完再开 */ + __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); /* 改寄存器窗口先关 UPDATE IT */ /* 关预装载,直写工作寄存器 */ - htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); - htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); - htim->Instance->ARR = s_last_arr; - htim->Instance->CCR1 = ccr; + htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); /* 清 ARPE:ARR 直写工作寄存器 */ + htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); /* 清 OC1PE:CCR 直写工作寄存器 */ + htim->Instance->ARR = s_last_arr; /* 工作 ARR = 起跳频周期 */ + htim->Instance->CCR1 = ccr; /* 工作 CCR = 起跳占空 */ /* * 先把 CNT 放到周期末端,再切回 PWM 模式。 @@ -643,60 +649,60 @@ static void PlsrPulseDriverCommitOutput(void) * 先写 CNT=ARR 并保持 Forced inactive,再切 PWM1,模式切换期间 * 输出始终为低;真正的首个上升沿只会由后续 UPDATE 产生。 */ - htim->Instance->CNT = s_last_arr; + htim->Instance->CNT = s_last_arr; /* CNT=ARR:下一节拍溢出→UPDATE,产生首上升沿 */ - ccmr = htim->Instance->CCMR1; - ccmr &= (uint32_t)(~TIM_CCMR1_OC1M); - ccmr |= TIM_OCMODE_PWM1; - htim->Instance->CCMR1 = ccmr; - htim->Instance->CCER |= TIM_CCER_CC1E; + ccmr = htim->Instance->CCMR1; /* 读 CCMR1,准备改 OC1M */ + ccmr &= (uint32_t)(~TIM_CCMR1_OC1M); /* 清 OC1M[6:4] */ + ccmr |= TIM_OCMODE_PWM1; /* 写入 PWM1:CNTInstance->CCMR1 = ccmr; /* 从 Forced inactive 切回 PWM1 */ + htim->Instance->CCER |= TIM_CCER_CC1E; /* CC1E=1:CH1 输出到 GPIO */ /* * 先打开预装载并把影子钉成同一频率,再 ENABLE。 * 否则首拍 ISR 的 SetFreqIsr 可能落在 ARPE=0 窗口,直接改写工作 ARR。 */ - htim->Instance->CR1 |= TIM_CR1_ARPE; - htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; - htim->Instance->ARR = s_last_arr; - htim->Instance->CCR1 = ccr; + htim->Instance->CR1 |= TIM_CR1_ARPE; /* 开 ARPE:后续改频写影子 */ + htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; /* 开 OC1PE:CCR 同样走影子 */ + htim->Instance->ARR = s_last_arr; /* 影子 ARR = 起跳频(与工作一致) */ + htim->Instance->CCR1 = ccr; /* 影子 CCR 同步 */ /* CNT 已在切换 PWM 模式前归位,下面仅清状态并开表。 */ - __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); + __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); /* 清 UIF,避免一开 IT 就误进 */ __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); - __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); - __HAL_TIM_ENABLE(htim); + __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); /* 开 UPDATE IT:每周期末进脉冲 ISR 改频/计数 */ + __HAL_TIM_ENABLE(htim); /* CEN=1:开始计数,下一拍 UPDATE 出首沿 */ g_plsr_pwm_running = 1U; /* 记录起跳工作寄存器,供首拍 ISR 保护当前周期 */ s_protect_arr = s_last_arr; s_protect_ccr = ccr; - s_protect_start_period = 1U; + s_protect_start_period = 1U; /* 下一次 SetFreqIsr 须先钉住工作 ARR */ - s_regs_prepared = 0U; + s_regs_prepared = 0U; /* Commit 完成,预装标志清掉 */ } /** - * @brief Start 公共路径(每次开沿都走 Commit,不依赖 prepared 捷径) + * @brief Start 公共路径:必要时 LoadRegs,再 Commit 开沿 */ static void PlsrPulseDriverStartCommon(uint32_t freq_hz) { if ((s_regs_prepared == 0U) || (freq_hz != g_plsr_output_freq_hz) || (freq_hz == 0U)) { - PlsrPulseDriverLoadRegs(freq_hz); + PlsrPulseDriverLoadRegs(freq_hz); /* 未预装或频率变了 → 重装 */ } if (freq_hz != 0U) { - PlsrPulseDriverCommitOutput(); + PlsrPulseDriverCommitOutput(); /* 开 CEN + PWM1 */ } } -/** @brief 换向延时期间预装寄存器、CEN 保持关 */ +/** @brief 换向延时期间预装寄存器、CEN 保持关(DIR_WAIT) */ void PlsrPulseDriverPrepare(uint32_t freq_hz) { - PlsrPulseDriverLoadRegs(freq_hz); + PlsrPulseDriverLoadRegs(freq_hz); /* 只装 PSC/ARR/CCR,CEN 仍关;TIM5 延时到期再 Start */ } -/** @brief 任务上下文改频 */ +/** @brief 任务上下文改频(可换 PSC;同 PSC 只写影子) */ void PlsrPulseDriverSetFreq(uint32_t freq_hz) { uint32_t psc; @@ -707,17 +713,17 @@ void PlsrPulseDriverSetFreq(uint32_t freq_hz) if (freq_hz == g_plsr_output_freq_hz) { - return; + return; /* 频率未变 */ } htim = (s_active_htim != (TIM_HandleTypeDef *)0) ? - s_active_htim : PlsrPulseDriverHtimByY(PlsrPulseDriverSelectY()); + s_active_htim : PlsrPulseDriverHtimByY(PlsrPulseDriverSelectY()); /* 无活动句柄则按配置选 TIM */ s_active_htim = htim; - clk_hz = PlsrPulseDriverTimClkHz(htim); + clk_hz = PlsrPulseDriverTimClkHz(htim); /* 按 TIM10/11/13 取 168M 或 84M */ if (freq_hz == 0U) { - PlsrPulseDriverStopHtim(htim); + PlsrPulseDriverStopHtim(htim); /* 停表拉低 */ g_plsr_output_freq_hz = 0U; g_plsr_pwm_running = 0U; s_last_psc = 0xFFFFFFFFUL; @@ -728,39 +734,40 @@ void PlsrPulseDriverSetFreq(uint32_t freq_hz) if (s_psc_locked != 0U) { psc = s_locked_psc; - PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, psc, &arr, &ccr); + PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, psc, &arr, &ccr); /* 锁 PSC:只算 ARR/CCR */ } else { - PlsrPulseDriverCalcPscArr(clk_hz, freq_hz, &psc, &arr, &ccr); + PlsrPulseDriverCalcPscArr(clk_hz, freq_hz, &psc, &arr, &ccr); /* 未锁:可换 PSC */ } if ((psc == s_last_psc) && (arr == s_last_arr)) { - g_plsr_output_freq_hz = freq_hz; + g_plsr_output_freq_hz = freq_hz; /* 量化结果相同,只更新镜像 */ return; } if ((s_psc_locked != 0U) || (psc == s_last_psc)) { - /* 预装载:本拍写影子寄存器,下一 UPDATE 自然切换,无毛刺、不多计边沿 */ - __HAL_TIM_SET_AUTORELOAD(htim, arr); - __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); - __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); + /* 同 PSC:写影子,下一 UPDATE 切换 */ + __HAL_TIM_SET_AUTORELOAD(htim, arr); /* 写 ARR 影子(ARPE=1 时本周期不受影响) */ + __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); /* 写 CCR1 影子(OC1PE=1) */ + __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); /* 确保 UPDATE IT 开着,ISR 能继续改频 */ } else { - __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); - __HAL_TIM_DISABLE(htim); - __HAL_TIM_SET_PRESCALER(htim, psc); - __HAL_TIM_SET_AUTORELOAD(htim, arr); - __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); - __HAL_TIM_SET_COUNTER(htim, 0U); - htim->Instance->EGR = TIM_EGR_UG; - __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); + /* 换 PSC:须停表再装载 */ + __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); /* 先关 UPDATE IT */ + __HAL_TIM_DISABLE(htim); /* CEN=0:停计数才能安全换 PSC */ + __HAL_TIM_SET_PRESCALER(htim, psc); /* 写新 PSC */ + __HAL_TIM_SET_AUTORELOAD(htim, arr); /* 写新 ARR */ + __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); /* 写新 CCR */ + __HAL_TIM_SET_COUNTER(htim, 0U); /* CNT=0 */ + htim->Instance->EGR = TIM_EGR_UG; /* UG:让新 PSC 立即生效,并产生 UPDATE */ + __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); /* 清 UG 产生的 UIF */ __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); - __HAL_TIM_ENABLE(htim); - __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); + __HAL_TIM_ENABLE(htim); /* CEN=1:重新开跑 */ + __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); /* 再开 UPDATE IT */ } g_plsr_output_freq_hz = freq_hz; @@ -768,7 +775,7 @@ void PlsrPulseDriverSetFreq(uint32_t freq_hz) s_last_arr = arr; } -/** @brief ISR 改频 */ +/** @brief ISR 改频(禁止停表换 PSC;需换则挂起) */ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) { uint32_t psc; @@ -777,17 +784,17 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) uint32_t clk_hz; TIM_HandleTypeDef *htim; - htim = s_active_htim; + htim = s_active_htim; /* ISR 只改当前活动 TIM */ if (htim == (TIM_HandleTypeDef *)0) { if (freq_hz == 0U) { s_req_freq = 0U; - s_req_pending = 1U; + s_req_pending = 1U; /* 无句柄:停表请求挂起给任务 */ return; } s_req_freq = freq_hz; - s_req_pending = 1U; + s_req_pending = 1U; /* 无句柄:改频请求挂起给任务 */ return; } @@ -798,19 +805,19 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) */ if (s_protect_start_period != 0U) { - s_protect_start_period = 0U; - htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); - htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); - htim->Instance->ARR = s_protect_arr; + s_protect_start_period = 0U; /* 首拍保护只用一次 */ + htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); /* 临时关 ARPE,直写工作 ARR */ + htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); /* 临时关 OC1PE,直写工作 CCR */ + htim->Instance->ARR = s_protect_arr; /* 钉住本拍工作 ARR=起跳频,防止被下一频覆盖 */ htim->Instance->CCR1 = (s_protect_ccr < 1U) ? 1U : s_protect_ccr; - htim->Instance->CR1 |= TIM_CR1_ARPE; - htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; + htim->Instance->CR1 |= TIM_CR1_ARPE; /* 立刻再开 ARPE:后面写影子才安全 */ + htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; /* 再开 OC1PE */ } else { /* 常规路径:确保预装载开启,禁止直写工作寄存器 */ - htim->Instance->CR1 |= TIM_CR1_ARPE; - htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; + htim->Instance->CR1 |= TIM_CR1_ARPE; /* 保证 ARPE=1 */ + htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; /* 保证 OC1PE=1 */ } /* 匀速热路径:频率未变 → 不算量化、不写寄存器 */ @@ -822,7 +829,7 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) if (freq_hz == 0U) { s_req_freq = 0U; - s_req_pending = 1U; + s_req_pending = 1U; /* ISR 内不停表,停表留给任务 ApplyPending */ return; } @@ -831,7 +838,7 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) if (s_psc_locked != 0U) { psc = s_locked_psc; - PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, psc, &arr, &ccr); + PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, psc, &arr, &ccr); /* 锁 PSC:ISR 只改 ARR */ } else { @@ -847,7 +854,7 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) if ((psc == s_last_psc) && (arr == s_last_arr)) { - g_plsr_output_freq_hz = freq_hz; + g_plsr_output_freq_hz = freq_hz; /* 量化未变,只更新镜像 */ return; } @@ -857,8 +864,8 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) } /* 此时 ARPE 已开:只改影子,下一 UPDATE 才切换,当前起跳周期不受影响 */ - __HAL_TIM_SET_AUTORELOAD(htim, arr); - __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); + __HAL_TIM_SET_AUTORELOAD(htim, arr); /* 写 ARR 影子 */ + __HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); /* 写 CCR1 影子 */ g_plsr_output_freq_hz = freq_hz; s_last_psc = psc; @@ -869,13 +876,13 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) /** @brief 丢弃挂起 */ void PlsrPulseDriverClearPending(void) { - s_req_pending = 0U; + s_req_pending = 0U; /* 丢掉 ISR 挂起的改频请求 */ } /** @brief 取消冷启动首拍保护*/ void PlsrPulseDriverClearStartPeriodProtect(void) { - s_protect_start_period = 0U; + s_protect_start_period = 0U; /* 进入匀速后不再钉工作 ARR */ } /** @brief 消费挂起改频 */ @@ -885,22 +892,22 @@ void PlsrPulseDriverApplyPending(void) if (s_req_pending == 0U) { - return; + return; /* 无挂起 */ } s_req_pending = 0U; f = s_req_freq; if (f == 0U) { - PlsrPulseDriverStop(); + PlsrPulseDriverStop(); /* 挂起的是停表 */ return; } - PlsrPulseDriverSetFreq(f); + PlsrPulseDriverSetFreq(f); /* 任务上下文可换 PSC */ } /** @brief 开 PWM + UPDATE 中断 */ void PlsrPulseDriverStart(uint32_t freq_hz) { - PlsrPulseDriverStartCommon(freq_hz); + PlsrPulseDriverStartCommon(freq_hz); /* LoadRegs(必要时)→ Commit:PWM1 + CEN + UPDATE IT */ } /** @brief 停三路 */ @@ -909,9 +916,9 @@ void PlsrPulseDriverStop(void) s_req_pending = 0U; s_regs_prepared = 0U; s_protect_start_period = 0U; - PlsrPulseDriverStopHtim(&htim10); - PlsrPulseDriverStopHtim(&htim11); - PlsrPulseDriverStopHtim(&htim13); + PlsrPulseDriverStopHtim(&htim10); /* 停 TIM10=Y0:Forced + 关 CEN */ + PlsrPulseDriverStopHtim(&htim11); /* 停 TIM11=Y2 */ + PlsrPulseDriverStopHtim(&htim13); /* 停 TIM13=Y1 */ g_plsr_output_freq_hz = 0U; g_plsr_pwm_running = 0U; s_last_psc = 0xFFFFFFFFUL; @@ -933,34 +940,34 @@ void PlsrPulseDriverArmActStop(void) } /* OPM 先武装:当前周期结束的 UPDATE 到来时自动关 CEN。 */ - htim->Instance->CR1 |= TIM_CR1_OPM; + htim->Instance->CR1 |= TIM_CR1_OPM; /* OPM=1:单脉冲模式,下一次 UPDATE 后自动清 CEN */ - cnt = htim->Instance->CNT; - ccr = htim->Instance->CCR1; + cnt = htim->Instance->CNT; /* 读当前计数位置 */ + ccr = htim->Instance->CCR1; /* 读比较值:CNTInstance->CR1 & TIM_CR1_CEN) != 0U) && (cnt < ccr)) { /* 当前仍为高电平:等本拍 CC1 下降沿后再锁低。 */ - s_seg_end_fall_armed = 1U; - __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC1); - __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1); + s_seg_end_fall_armed = 1U; /* 武装:等 CC1 匹配(≈下降沿)回调里 Forced */ + __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC1); /* 清旧 CC1IF,避免立刻误触发 */ + __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1); /* 开 CC1 IT:高→低时进 PulseFinishedCallback */ /* * 读取到高电平后,CC1 可能恰好在开中断前已经过去。 * 再检查一次;若已进入低电平或 OPM 已停表,立即锁低。 */ - cnt = htim->Instance->CNT; + cnt = htim->Instance->CNT; /* 再读 CNT,防竞态漏边沿 */ if (((htim->Instance->CR1 & TIM_CR1_CEN) == 0U) || (cnt >= ccr)) { - PlsrPulseDriverClearSegEndFallArm(htim); - PlsrPulseDriverOcForceLowKeepRun(htim); + PlsrPulseDriverClearSegEndFallArm(htim); /* 撤 CC1 武装(关 CC1 IT),不是 Forced */ + PlsrPulseDriverOcForceLowKeepRun(htim); /* Forced inactive 拉低,CEN/OPM 继续跑到周期末 */ } } else { /* ACT 落在低电平阶段(或边界已停表):无需再等 CC1。 */ - PlsrPulseDriverClearSegEndFallArm(htim); - PlsrPulseDriverOcForceLowKeepRun(htim); + PlsrPulseDriverClearSegEndFallArm(htim); /* 撤 CC1 武装 */ + PlsrPulseDriverOcForceLowKeepRun(htim); /* 立刻 Forced 拉低,等 OPM 在周期末关 CEN */ } } @@ -976,10 +983,10 @@ void PlsrPulseDriverArmSegEndStop(void) 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); + htim->Instance->CR1 |= TIM_CR1_OPM; /* 周期末自动关 CEN */ + s_seg_end_fall_armed = 1U; /* 武装末拍下降沿拉低 */ + __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_CC1); /* 清 CC1IF */ + __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1); /* 末拍下降沿 → Forced 拉低 */ } /** @brief HAL PWM 脉宽结束(CC1 匹配 ≈ 下降沿) */ @@ -989,14 +996,14 @@ void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) (htim != s_active_htim) || (PlsrPulseDriverIsPulseTim(htim->Instance) == 0U)) { - return; + return; /* 未武装 / 非活动路 / 非脉冲 TIM(TIM10/11/13)→ 忽略 */ } - PlsrPulseDriverClearSegEndFallArm(htim); - PlsrPulseDriverOcForceLowKeepRun(htim); + PlsrPulseDriverClearSegEndFallArm(htim); /* 先撤 CC1 武装(关 IT),不是 Forced */ + PlsrPulseDriverOcForceLowKeepRun(htim); /* 再 Forced inactive 拉低;CEN 仍跑,等 OPM 关表 */ } -/** @brief 取消 OPM */ +/** @brief 取消 OPM,并撤 CC1 下降沿武装(不停表、不 Forced) */ void PlsrPulseDriverClearOnePulseStop(void) { TIM_HandleTypeDef *htim = s_active_htim; @@ -1005,8 +1012,8 @@ void PlsrPulseDriverClearOnePulseStop(void) { return; } - htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_OPM); - PlsrPulseDriverClearSegEndFallArm(htim);/*关掉末拍下降沿拉低标志*/ + htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_OPM); /* 清 OPM:恢复连续计数,段衔接时不停表 */ + PlsrPulseDriverClearSegEndFallArm(htim); /* 仅撤 CC1 武装 */ } /** @brief OPM 段末 UPDATE 后立刻拉低,消除 CNT 回零 PWM1 假上升沿 */ @@ -1018,6 +1025,6 @@ void PlsrPulseDriverHoldOutputLow(void) { return; } - PlsrPulseDriverStopHtim(htim); + PlsrPulseDriverStopHtim(htim); /* Forced + 关 CEN/OPM/IT,避免 CNT 回零时 PWM1 假上升沿 */ g_plsr_pwm_running = 0U; } diff --git a/plsr/pulse_driver/plsr_pulse_driver.h b/plsr/pulse_driver/plsr_pulse_driver.h index 22659d9..8a65b08 100644 --- a/plsr/pulse_driver/plsr_pulse_driver.h +++ b/plsr/pulse_driver/plsr_pulse_driver.h @@ -35,10 +35,10 @@ extern TIM_HandleTypeDef htim11; extern TIM_HandleTypeDef htim13; /* 驱动拥有的真实输出状态,run_control 直接读取,不再保存第二份。 */ -extern volatile uint32_t g_plsr_output_freq_hz; -extern volatile uint8_t g_plsr_pwm_running; -extern uint8_t g_plsr_direction_forward; -extern uint8_t g_plsr_direction_valid;/*方向脚有效*/ +extern volatile uint32_t g_plsr_output_freq_hz; /* 当前输出频率 Hz */ +extern volatile uint8_t g_plsr_pwm_running; /* 1=PWM 正在跑 */ +extern uint8_t g_plsr_direction_forward; /* 1=正转方向语义 */ +extern uint8_t g_plsr_direction_valid; /* 1=方向脚已有效写出 */ /** * @brief 初始化三路脉冲 TIM + 方向 GPIO diff --git a/plsr/run_control/plsr_run_control.c b/plsr/run_control/plsr_run_control.c index cddf38f..dc7a04b 100644 --- a/plsr/run_control/plsr_run_control.c +++ b/plsr/run_control/plsr_run_control.c @@ -20,10 +20,10 @@ * RC_WAIT_COND — 段后等待:TIM5 时间 或 WAIT/EXT 沿 */ typedef enum { - RC_IDLE = 0, - RC_DIR_WAIT, - RC_RUN, - RC_WAIT_COND + RC_IDLE = 0, /* 空闲 */ + RC_DIR_WAIT, /* 等换向延时 */ + RC_RUN, /* 正在发脉冲 */ + RC_WAIT_COND /* 段后等待 */ } RcState_e; /* @@ -33,9 +33,9 @@ typedef enum { * PH_DECEL — 段末过渡 → f_end(可升可降) */ typedef enum { - PH_APPROACH = 0, - PH_CONST, - PH_DECEL + PH_APPROACH = 0, /* 起速爬峰 */ + PH_CONST, /* 匀速 */ + PH_DECEL /* 段末过渡 */ } RunPhase_e; volatile uint8_t g_plsr_busy; /* 运行忙标志(上位机监控) */ @@ -153,9 +153,9 @@ void PlsrRunControlInit(void) */ void PlsrRunControlWakeInit(void) { - if (s_wake_sem == (OS_EVENT *)0) + if (s_wake_sem == (OS_EVENT *)0) /* 信号量还没建 */ { - s_wake_sem = OSSemCreate(0U); + s_wake_sem = OSSemCreate(0U); /* 建一个空信号量 */ } } @@ -166,17 +166,17 @@ void PlsrRunControlWakePend(uint16_t timeout_ticks) { INT8U err; - if (s_wake_sem == (OS_EVENT *)0) + if (s_wake_sem == (OS_EVENT *)0) /* 没信号量就退回延时 */ { - if (timeout_ticks < 1U) + if (timeout_ticks < 1U) /* 至少延 1 tick */ { - timeout_ticks = 1U; + timeout_ticks = 1U; /* 补成最短延时 */ } - OSTimeDly((INT32U)timeout_ticks); - return; + OSTimeDly((INT32U)timeout_ticks); /* 没有唤醒量就干等 */ + return; /* 直接回去 */ } - OSSemPend(s_wake_sem, timeout_ticks, &err); - (void)err; + OSSemPend(s_wake_sem, timeout_ticks, &err); /* 挂起等唤醒或超时 */ + (void)err; /* 忽略返回码 */ } /** @@ -184,15 +184,15 @@ void PlsrRunControlWakePend(uint16_t timeout_ticks) */ uint8_t PlsrRunControlIsPreciseWait(void) { - if (s_state == RC_DIR_WAIT) + if (s_state == RC_DIR_WAIT) /* 正在等换向延时 */ { - return 1U; + return 1U; /* 是精确等待 */ } - if ((s_state == RC_WAIT_COND) && (s_waiting_for_input_signal == 0U)) + if ((s_state == RC_WAIT_COND) && (s_waiting_for_input_signal == 0U)) /* 段后纯时间等待(不读沿) */ { - return 1U; + return 1U; /* 也是精确等待 */ } - return 0U; + return 0U; /* 其它不算精确等待 */ } /** @brief 启动多段序列 */ @@ -202,29 +202,29 @@ uint8_t PlsrStart(uint16_t start_seg) uint16_t first_seg; uint32_t f_chk;/* 解析后的首段目标频率;此处仅作合法性检查,结果不用 */ - if (g_plsr_busy != 0U) + if (g_plsr_busy != 0U) /* 已经在跑就拒绝再启 */ { - return 0U; + return 0U; /* 忙着,启不动 */ } n = PlsrParamGetSegCount();/*获取段的数量*/ - if (n < 1U) + if (n < 1U) /* 一段都没有 */ { - return 0U; + return 0U; /* 没段可跑 */ } - if ((start_seg < 1U) || (start_seg > n)) + if ((start_seg < 1U) || (start_seg > n)) /* 起始段号越界 */ { start_seg = PlsrParamGetStartSeg();/*获取起始段*/ } - first_seg = (uint16_t)(start_seg - 1U); + first_seg = (uint16_t)(start_seg - 1U); /* 改成 0 起算下标 */ /* 启动前先检查首段频率,非法时不置忙、不开定时器。 */ - if (PlsrRunControlGetSegTargetFreq(g_plsr_segs[first_seg].freq_hz, + if (PlsrRunControlGetSegTargetFreq(g_plsr_segs[first_seg].freq_hz, /* 首段频率合法性检查 */ g_plsr_config.default_speed, &f_chk) == 0U) { - PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); - return 0U; + PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); /* 频率不合法,报故障 */ + return 0U; /* 不置忙、不开表 */ } s_continue_without_stopping = 0U;/* 清段间不停表衔接标志 */ s_next_seg_start_freq_valid = 0U;/* 清段间衔接频率有效标志 */ @@ -233,145 +233,148 @@ uint8_t PlsrStart(uint16_t start_seg) * 绝对原点:仅在首次 Start(或 ClearAccPulse 之后的第一次)锁定。 * 相对跑完再切绝对,仍相对「第一次启动时刻」坐标,不以当前位置重定原点。 */ - if (s_absolute_origin_locked == 0U) + if (s_absolute_origin_locked == 0U) /* 原点还没锁过 */ { s_absolute_origin = g_plsr_accumulated_pulses;/*已经累计的脉冲*/ s_absolute_origin_locked = 1U;/*绝对原点锁定标志*/ } PlsrSignalIoClearEdges();/*清除io信号边沿*/ PlsrRunControlBeginSeg(first_seg);/*根据段号开一段*/ - return 1U; + return 1U; /* 启动成功 */ } -/** @brief 急停 */ +/** + * @brief 急停:停 PWM、解锁 PSC、清方向与 ACT/WAIT 运行标志 + */ void PlsrStop(void) { - PlsrSignalIoCancelDelay(); - PlsrPulseDriverStop(); - PlsrPulseDriverUnlockPsc(); - PlsrPulseDriverClearDir(); - g_plsr_busy = 0U; - s_state = RC_IDLE; - s_continue_without_stopping = 0U; /*连续运行标志*/ - s_next_seg_start_freq_valid = 0U;/*衔接频率是否有效*/ - s_next_seg_start_freq_hz = 0U; /*段间衔接频率*/ - s_act_timer_armed = 0U;/*ACT定时器是否已启动*/ - s_act_expired = 0U;/*ACT到期请求标志*/ - s_act_waiting_for_pulse_boundary = 0U;/*ACT 时间到,等待脉冲边界切段*/ - s_keep_freq_after_act = 0U;/*ACT 切段后是否保持当前频率衔接*/ - s_wait_time_expired = 0U;/*段后等待到期请求标志*/ - s_waiting_for_last_period = 0U; + PlsrSignalIoCancelDelay(); /* 取消 TIM5 方向/ACT/WAIT 延时 */ + PlsrPulseDriverStop(); /* 停掉脉冲输出 */ + PlsrPulseDriverUnlockPsc(); /* 解开 PSC 锁定 */ + PlsrPulseDriverClearDir(); /* 方向脚拉回默认 */ + g_plsr_busy = 0U; /* 清忙标志 */ + s_state = RC_IDLE; /* 回到空闲 */ + s_continue_without_stopping = 0U; /* 清不停表衔接 */ + s_next_seg_start_freq_valid = 0U; /* 清链式起速 */ + s_next_seg_start_freq_hz = 0U; /* 衔接频率清零 */ + s_act_timer_armed = 0U; /* 清「ACT 定时已开」标志 */ + s_act_expired = 0U; /* 清 ACT 到期请求 */ + s_act_waiting_for_pulse_boundary = 0U; /* 清脉冲边界切段 */ + s_keep_freq_after_act = 0U; /* 清 ACT 频率衔接 */ + s_wait_time_expired = 0U; /* 清 WAIT 时间到期 */ + s_waiting_for_last_period = 0U; /* 清末拍收尾等待 */ } /** @brief 运行中改频 */ uint8_t PlsrChangeFreq(uint32_t new_tgt_hz) { - uint32_t remain; - uint32_t f_end; + uint32_t remain; /* 本段剩余脉冲,作新规划总量 */ + uint32_t f_end; /* 保留原出口频率 */ - if (s_state != RC_RUN) + if (s_state != RC_RUN) /* 不在发脉冲就别改 */ { - return 0U; + return 0U; /* 拒收 */ } /* 0x04:动态改频目标非法则拒收,保持原规划 */ - if ((new_tgt_hz < 1U) || (new_tgt_hz > 100000U)) + if ((new_tgt_hz < 1U) || (new_tgt_hz > 100000U)) /* 新目标超出 1~100kHz */ { - PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); - return 0U; + PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); /* 频率越界报故障 */ + return 0U; /* 拒收新频率 */ } - if (s_seg_pulses_done >= s_seg_pulse_target) + if (s_seg_pulses_done >= s_seg_pulse_target) /* 本段脉冲已经发完 */ { - return 0U; + return 0U; /* 已发完,改频无意义 */ } - remain = (uint32_t)(s_seg_pulse_target - s_seg_pulses_done); - f_end = g_plsr_accel_plan.end_freq_hz; - PlsrRunControlPlanSeg(remain, g_plsr_output_freq_hz, new_tgt_hz, f_end, + remain = (uint32_t)(s_seg_pulse_target - s_seg_pulses_done); /* 算还剩多少脉冲 */ + f_end = g_plsr_accel_plan.end_freq_hz; /* 出口频率先留着 */ + /* 从当前输出频重规划到新目标,出口不变 */ + PlsrRunControlPlanSeg(remain, g_plsr_output_freq_hz, new_tgt_hz, f_end, /* 按剩余脉冲重规划加减速 */ g_plsr_config.accel_ms, g_plsr_config.decel_ms); - s_seg_pulse_target = (int32_t)remain; - s_seg_pulses_done = 0; - PlsrRunControlRefreshProfile(0U);/*刷新下一拍频率*/ - return 1U; + s_seg_pulse_target = (int32_t)remain; /* 剩余作新段目标 */ + s_seg_pulses_done = 0; /* 计数归零对齐新规划 */ + PlsrRunControlRefreshProfile(0U); /* 已在跑:只刷新下一拍频率 */ + return 1U; /* 改频成功 */ } /** @brief 清累计与绝对原点 */ void PlsrClearAccPulse(void) { - g_plsr_accumulated_pulses = 0; - s_absolute_origin = 0; + g_plsr_accumulated_pulses = 0; /* 累计脉冲清零 */ + s_absolute_origin = 0; /* 原点也清掉 */ s_absolute_origin_locked = 0U; /* 下次 Start 重新锁定原点 */ } /** @brief 上电恢复累计 */ void PlsrRunControlRestoreAccPulse(int32_t acc_pulse) { - g_plsr_accumulated_pulses = acc_pulse; - s_absolute_origin = 0; + g_plsr_accumulated_pulses = acc_pulse; /* 写回上电保存的累计 */ + s_absolute_origin = 0; /* 原点待下次 Start 再锁 */ s_absolute_origin_locked = 0U; /* 下次 Start 以当前累计为绝对原点 */ } /** @brief 毫秒任务节拍 */ void PlsrRunControlTickMs(void) { - /* act时间到期或者act切段后需要保持频率*/ - if (s_act_expired != 0U) + /* ACT 到期请求:切下一段(含 keep 频率衔接) */ + if (s_act_expired != 0U) /* 有 ACT 时间到请求 */ { - s_act_expired = 0U; - if ((s_state == RC_RUN) || (s_keep_freq_after_act != 0U)) + s_act_expired = 0U; /* 先把请求清掉 */ + if ((s_state == RC_RUN) || (s_keep_freq_after_act != 0U)) /* 正在跑或还要频率衔接 */ { - PlsrRunControlActExpire();/*act时间到期处理函数*/ + PlsrRunControlActExpire(); /* ACT 时间到期处理 */ } - return; + return; /* 本拍处理完就回 */ } - /*wait时间到期,清标志位,规划下一段*/ - if (s_wait_time_expired != 0U) + /* WAIT 时间到期:清标志,开下一段或结束 */ + if (s_wait_time_expired != 0U) /* 有段后 WAIT 时间到 */ { - s_wait_time_expired = 0U; - if (s_state == RC_WAIT_COND) + s_wait_time_expired = 0U; /* 清掉到期请求 */ + if (s_state == RC_WAIT_COND) /* 还在段后等待才认 */ { - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 时间到了,开下一段或收工 */ } - return; + return; /* 本拍处理完 */ } - /*方向延时直接等待*/ - if (s_state == RC_DIR_WAIT) + /* 方向延时:精确等待只靠 TIM5,此处不改状态 */ + if (s_state == RC_DIR_WAIT) /* 等换向延时中 */ { /* 精确延时只靠 TIM5;此处占位,避免任务空转改状态 */ - return; + return; /* 交给 TIM5,这里不动 */ } - /*运行态先处理改频请求,如果时EXT/EXT或脉冲发送完成,需要读取下降沿*/ - if (s_state == RC_RUN) + /* RUN:消费挂起改频;EXT/EXT_OR_DONE 读下降沿切段 */ + if (s_state == RC_RUN) /* 正在发脉冲 */ { - PlsrPulseDriverApplyPending();//消费挂起改频 + PlsrPulseDriverApplyPending(); /* 消费挂起改频 */ - if ((g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT) || + if ((g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT) || /* 本段要看外部 EXT 沿 */ (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT_OR_DONE)) { - if (PlsrSignalIoTakeExtFalling() != 0U) + if (PlsrSignalIoTakeExtFalling() != 0U) /* 等到外部下降沿 */ { - PlsrRunControlCutSegToNext();/*EXT信号触发切段*/ - return; + PlsrRunControlCutSegToNext(); /* EXT 沿触发中途切段 */ + return; /* 切段完回 */ } } - return; + return; /* 本拍没有别的事 */ } - /*等待条件状态要读取下降沿,去下一段或者结束*/ - if (s_state == RC_WAIT_COND) + /* WAIT_COND:等 WAIT/EXT 沿后开下一段 */ + if (s_state == RC_WAIT_COND) /* 段后等待里 */ { - if (s_waiting_for_input_signal != 0U) + if (s_waiting_for_input_signal != 0U) /* 在等输入沿 */ { - if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT) + if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT) /* 等的是 EXT 下降沿 */ { - if (PlsrSignalIoTakeExtFalling() != 0U) + if (PlsrSignalIoTakeExtFalling() != 0U) /* EXT 下降沿来了 */ { - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 开下一段或收工 */ } } else { - if (PlsrSignalIoTakeWaitFalling() != 0U) + if (PlsrSignalIoTakeWaitFalling() != 0U) /* 等的是 WAIT 口下降沿 */ { - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 开下一段或收工 */ } } } @@ -385,109 +388,115 @@ void PlsrRunControlTickMs(void) */ void PlsrRunControlOnDelayTimer(void) { - if (s_state == RC_DIR_WAIT) + if (s_state == RC_DIR_WAIT) /* 换向延时到了 */ { - s_state = RC_RUN; - PlsrRunControlRefreshProfile(1U);/*刷新频率*/ - PlsrRunControlArmActExtOnPulseStart();/*开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */ - PlsrRunControlWakePost();/*释放信号量,唤醒plsr任务*/ - return; + s_state = RC_RUN; /* 切成正在发脉冲 */ + PlsrRunControlRefreshProfile(1U); /* 方向延时到:开表写频 */ + PlsrRunControlArmActExtOnPulseStart(); /* EXT 清沿 / ACT 开定时 */ + PlsrRunControlWakePost(); /* 唤醒 PlsrTask */ + return; /* 换向开表流程做完 */ } - if ((s_state == RC_RUN) && (s_act_timer_armed != 0U)) + if ((s_state == RC_RUN) && (s_act_timer_armed != 0U)) /* 跑着且 ACT 定时已开着 */ { /* 到点:当前脉冲下降沿后锁低,周期结束时 OPM 停表。 */ - s_act_timer_armed = 0U; - s_act_waiting_for_pulse_boundary = 1U; - PlsrPulseDriverArmActStop(); - return; + s_act_timer_armed = 0U; /* ACT 定时用完,清掉 */ + s_act_waiting_for_pulse_boundary = 1U; /* 等脉冲边界再切段 */ + PlsrPulseDriverArmActStop(); /* 当前脉冲发完后锁低停表 */ + return; /* 等脉冲边界再切段 */ } - if ((s_state == RC_WAIT_COND) && (s_waiting_for_input_signal == 0U)) + if ((s_state == RC_WAIT_COND) && (s_waiting_for_input_signal == 0U)) /* 段后纯时间等待到期 */ { - s_wait_time_expired = 1U; - PlsrRunControlWakePost(); + s_wait_time_expired = 1U; /* 时间 WAIT/ACT 剩余到期 → TickMs 消费 */ + PlsrRunControlWakePost(); /* 叫醒任务去开下一段 */ } } /** @brief 脉冲 UPDATE ISR */ void PlsrOnPulseIsr(void) { - uint32_t remain; - uint32_t next; + uint32_t remain; /* 本段剩余脉冲 */ + uint32_t next; /* 本拍写出频率 */ - if (s_state != RC_RUN) + if (s_state != RC_RUN) /* 不是正在发脉冲就别管 */ { - return; + return; /* 直接退出 ISR */ } - if (s_waiting_for_last_period != 0U) + /* 完成模式:末拍 OPM 停表后再收尾 */ + if (s_waiting_for_last_period != 0U) /* 在等末拍那一下 */ { - s_waiting_for_last_period = 0U; - s_act_waiting_for_pulse_boundary = 0U; - - PlsrPulseDriverHoldOutputLow(); - PlsrRunControlAfterSegDone(); - return; + s_waiting_for_last_period = 0U; /* 末拍收尾标志清掉 */ + s_act_waiting_for_pulse_boundary = 0U; /* 顺带清 ACT 边界等待 */ + + PlsrPulseDriverHoldOutputLow(); /* 锁低输出 */ + PlsrRunControlAfterSegDone(); /* 进段后等待/下一段 */ + return; /* 末拍处理完 */ } - s_seg_pulses_done++; - if (s_forward != 0U) + s_seg_pulses_done++; /* 本段已发 +1 */ + if (s_forward != 0U) /* 正转:累计加一 */ { - g_plsr_accumulated_pulses++; + g_plsr_accumulated_pulses++; /* 正转累计 */ } else { - g_plsr_accumulated_pulses--; + g_plsr_accumulated_pulses--; /* 反转累计 */ } - if (s_act_waiting_for_pulse_boundary != 0U) + /* ACT 到期:等当前脉冲边界再切段 */ + if (s_act_waiting_for_pulse_boundary != 0U) /* ACT 时间到,卡在等当前脉冲边界 */ { - s_act_waiting_for_pulse_boundary = 0U; - s_keep_freq_after_act = 1U; + s_act_waiting_for_pulse_boundary = 0U; /* 边界到了,清等待 */ + s_keep_freq_after_act = 1U; /* 边界停表后仍可频率衔接 */ - PlsrPulseDriverHoldOutputLow(); - s_state = RC_IDLE; - s_act_expired = 1U; - PlsrRunControlWakePost(); - return; + PlsrPulseDriverHoldOutputLow(); /* 输出锁低 */ + s_state = RC_IDLE; /* 暂时回到空闲 */ + s_act_expired = 1U; /* 交给 TickMs 消费 */ + PlsrRunControlWakePost(); /* 唤醒任务处理 ACT 到期 */ + return; /* 交给 TickMs 去做 ACT 切段 */ } - if (s_seg_pulses_done >= s_seg_pulse_target) + /* 本段脉冲发完 */ + if (s_seg_pulses_done >= s_seg_pulse_target) /* 本段脉冲数发满了 */ { - if (s_stop_after_last_pulse != 0U) + if (s_stop_after_last_pulse != 0U) /* 需要末拍后再完整停表 */ { - PlsrPulseDriverArmSegEndStop(); - s_waiting_for_last_period = 1U; - return; + /* 完成模式:OPM 再跑一拍,下一 UPDATE 才 AfterSegDone */ + PlsrPulseDriverArmSegEndStop(); /* 装上末拍停表 */ + s_waiting_for_last_period = 1U; /* 下一拍 UPDATE 再收尾 */ + return; /* 先回去,别急着切段 */ } /* FOLLOW 不停表衔接:立刻切段,PWM 连续 */ - PlsrRunControlAfterSegDone(); - return; + PlsrRunControlAfterSegDone(); /* 立刻走段后/下一段 */ + return; /* 段间不停表接着跑:马上切段 */ } - remain = PlsrRunControlRemainPulses(); + remain = PlsrRunControlRemainPulses(); /* 算还剩几拍 */ - if (s_phase == PH_CONST) + if (s_phase == PH_CONST) /* 匀速相 */ { /* 匀速:不改频、不写 ARR,仅在 remain 进入减速窗口时切相并查表改频 */ - PlsrPulseDriverClearStartPeriodProtect(); - if (PlsrRunControlShouldEnterDecel(remain) != 0U) + PlsrPulseDriverClearStartPeriodProtect(); /* 匀速相清开表保护 */ + if (PlsrRunControlShouldEnterDecel(remain) != 0U) /* 该进段末过渡了 */ { - PlsrRunControlEnterDecel(g_plsr_accel_plan.target_freq_hz, + /* remain 落入减速预算 → 进 DECEL 并写本拍频率 */ + PlsrRunControlEnterDecel(g_plsr_accel_plan.target_freq_hz, /* 从峰值切入段末过渡 */ PlsrRunControlDecelEnterBudget(remain)); - next = PlsrAccelNextFreq(&g_plsr_accel_runtime); - next = PlsrRunControlDecelOutFreq(next, remain); - g_plsr_accel_runtime.cur_freq_hz = next; - PlsrRunControlApplyOutFreqIsr(next); + next = PlsrAccelNextFreq(&g_plsr_accel_runtime); /* 斜坡算出下一频 */ + next = PlsrRunControlDecelOutFreq(next, remain); /* 末拍钉止速 */ + g_plsr_accel_runtime.cur_freq_hz = next; /* 记下当前输出频 */ + PlsrRunControlApplyOutFreqIsr(next); /* ISR 里写 ARR */ } } - else if (s_phase == PH_APPROACH) + else if (s_phase == PH_APPROACH) /* 起速爬峰相 */ { /* 每拍 Step 得下一频;若加速相结束则进 CONST 或 DECEL */ - next = PlsrAccelNextFreq(&g_plsr_accel_runtime); + next = PlsrAccelNextFreq(&g_plsr_accel_runtime); /* 加速斜坡取下一频 */ - if ((g_plsr_accel_plan.accel_pulses == 0U) || + /* 加速结束:预算用尽 / 已达 f_tgt */ + if ((g_plsr_accel_plan.accel_pulses == 0U) || /* 加速是否该收尾(预算/到顶/到峰值) */ (g_plsr_accel_runtime.is_active == 0U) || (g_plsr_accel_runtime.completed_pulses >= g_plsr_accel_plan.accel_pulses) || ((g_plsr_accel_plan.target_freq_hz >= g_plsr_accel_plan.start_freq_hz) && @@ -495,42 +504,44 @@ void PlsrOnPulseIsr(void) ((g_plsr_accel_plan.target_freq_hz < g_plsr_accel_plan.start_freq_hz) && (next <= g_plsr_accel_plan.target_freq_hz))) { - next = g_plsr_accel_plan.target_freq_hz; - PlsrRunControlOnApproachDone(); - if (PlsrRunControlShouldEnterDecel(remain) != 0U) + next = g_plsr_accel_plan.target_freq_hz; /* 钉峰值 */ + PlsrRunControlOnApproachDone(); /* 0x03 加速诊断 */ + if (PlsrRunControlShouldEnterDecel(remain) != 0U) /* 剩脉冲已进减速窗口 */ { - PlsrRunControlEnterDecel(next, + /* 已进减速窗口:直接进 DECEL */ + PlsrRunControlEnterDecel(next, /* 直接进段末过渡 */ PlsrRunControlDecelEnterBudget(remain)); - next = PlsrAccelNextFreq(&g_plsr_accel_runtime); - next = PlsrRunControlDecelOutFreq(next, remain); - g_plsr_accel_runtime.cur_freq_hz = next; - PlsrRunControlApplyOutFreqIsr(next); + next = PlsrAccelNextFreq(&g_plsr_accel_runtime); /* 再取一拍斜坡频 */ + next = PlsrRunControlDecelOutFreq(next, remain); /* 末拍附近钉好止速 */ + g_plsr_accel_runtime.cur_freq_hz = next; /* 更新当前频 */ + PlsrRunControlApplyOutFreqIsr(next); /* 写到硬件 */ } else { - PlsrRunControlEnterConstHoldIsr(); + PlsrRunControlEnterConstHoldIsr(); /* 进匀速,ISR 侧写 f_tgt */ } } else { - PlsrRunControlApplyOutFreqIsr(next); + PlsrRunControlApplyOutFreqIsr(next); /* 加速中:写下一拍 */ } } - else /* PH_DECEL */ + else /* PH_DECEL:段末过渡 */ { - if ((remain <= 1U) && + /* 末拍且曲线步进已用尽 → 直接钉止速 */ + if ((remain <= 1U) && /* 末拍且斜坡步数用尽 */ (g_plsr_accel_runtime.total_pulses > 0U) && (g_plsr_accel_runtime.completed_pulses >= g_plsr_accel_runtime.total_pulses)) { - next = g_plsr_accel_plan.end_freq_hz; + next = g_plsr_accel_plan.end_freq_hz; /* 直接用出口频率 */ } else { - next = PlsrAccelNextFreq(&g_plsr_accel_runtime); + next = PlsrAccelNextFreq(&g_plsr_accel_runtime); /* 继续斜坡 */ } - next = PlsrRunControlDecelOutFreq(next, remain); - g_plsr_accel_runtime.cur_freq_hz = next; - PlsrRunControlApplyOutFreqIsr(next); + next = PlsrRunControlDecelOutFreq(next, remain); /* 按止速规则修一下 */ + g_plsr_accel_runtime.cur_freq_hz = next; /* 记下 */ + PlsrRunControlApplyOutFreqIsr(next); /* ISR 写出 */ } } @@ -543,20 +554,21 @@ void PlsrOnPulseIsr(void) */ static void PlsrRunControlWakeDrain(void) { - if (s_wake_sem != (OS_EVENT *)0) + if (s_wake_sem != (OS_EVENT *)0) /* 有信号量才排 */ { - while (OSSemAccept(s_wake_sem) > 0U) + while (OSSemAccept(s_wake_sem) > 0U) /* 有令牌就掏光 */ { /* 全部丢弃令牌 */ } } } +/* 投递一枚唤醒令牌给 PlsrTask */ static void PlsrRunControlWakePost(void) { - if (s_wake_sem != (OS_EVENT *)0) + if (s_wake_sem != (OS_EVENT *)0) /* 有信号量才投 */ { - (void)OSSemPost(s_wake_sem); + (void)OSSemPost(s_wake_sem); /* 投一枚叫醒 PlsrTask */ } } @@ -570,22 +582,22 @@ static void PlsrRunControlWakePost(void) */ static int16_t PlsrRunControlNextSeg(uint16_t cur_seg_idx) { - uint16_t n = PlsrParamGetSegCount(); - uint16_t jump = g_plsr_segs[cur_seg_idx].jump_seg; + uint16_t n = PlsrParamGetSegCount(); /* 总段数 */ + uint16_t jump = g_plsr_segs[cur_seg_idx].jump_seg; /* 本段跳转字段 */ - if (jump == 0U) + if (jump == 0U) /* jump=0:顺序走 */ { - if ((n >= 1U) && (cur_seg_idx + 1U < n)) + if ((n >= 1U) && (cur_seg_idx + 1U < n)) /* 后面还有段 */ { - return (int16_t)(cur_seg_idx + 1U); + return (int16_t)(cur_seg_idx + 1U); /* 下一段下标 */ } - return -1; + return -1; /* 已经是末段 → 结束 */ } - if ((jump >= 1U) && (jump <= n)) + if ((jump >= 1U) && (jump <= n)) /* jump 指向合法段号 */ { - return (int16_t)(jump - 1U); + return (int16_t)(jump - 1U); /* 跳到该段(改 0 起算) */ } - return -1; + return -1; /* 非法 jump → 当结束 */ } /** @@ -593,7 +605,7 @@ static int16_t PlsrRunControlNextSeg(uint16_t cur_seg_idx) */ static uint8_t PlsrRunControlIsEmptyPlaceholderSeg(uint16_t seg_idx) { - return ((g_plsr_segs[seg_idx].freq_hz == 0) && + return ((g_plsr_segs[seg_idx].freq_hz == 0) && /* 频率0且脉冲0:占位空段 */ (g_plsr_segs[seg_idx].pulse_cnt == 0)) ? 1U : 0U; } @@ -603,19 +615,19 @@ static uint8_t PlsrRunControlIsEmptyPlaceholderSeg(uint16_t seg_idx) */ static int16_t PlsrRunControlNextEffectiveSeg(uint16_t cur_seg_idx) { - int16_t next = PlsrRunControlNextSeg(cur_seg_idx); - uint16_t guard = 0U; + int16_t next = PlsrRunControlNextSeg(cur_seg_idx); /* 先取逻辑下一段 */ + uint16_t guard = 0U; /* 防死循环计数 */ - while ((next >= 0) && (guard < PLSR_SEG_MAX)) + while ((next >= 0) && (guard < PLSR_SEG_MAX)) /* 还有下一段且没转太久 */ { - guard++; - if (PlsrRunControlIsEmptyPlaceholderSeg((uint16_t)next) == 0U) + guard++; /* guard 加一 */ + if (PlsrRunControlIsEmptyPlaceholderSeg((uint16_t)next) == 0U) /* 不是空占位 */ { - return next; + return next; /* 找到有效段 */ } - next = PlsrRunControlNextSeg((uint16_t)next); + next = PlsrRunControlNextSeg((uint16_t)next); /* 空段就再跳一步 */ } - return -1; + return -1; /* 没有有效段了 */ } /** @@ -625,21 +637,21 @@ static uint8_t PlsrRunControlIsForward(uint16_t seg_idx, int32_t acc_pulse) { int32_t move; - if (g_plsr_config.run_mode == PLSR_POS_ABSOLUTE) + if (g_plsr_config.run_mode == PLSR_POS_ABSOLUTE) /* 绝对模式看目标减当前位置 */ { - move = g_plsr_segs[seg_idx].pulse_cnt - acc_pulse; + move = g_plsr_segs[seg_idx].pulse_cnt - acc_pulse; /* 还要走多少(有符号) */ } else { - move = g_plsr_segs[seg_idx].pulse_cnt; + move = g_plsr_segs[seg_idx].pulse_cnt; /* 相对模式直接看脉冲符号 */ } - return (move >= 0) ? 1U : 0U; + return (move >= 0) ? 1U : 0U; /* >=0 正转,否则反转 */ } /** 绝对模式:相对本次启动原点的位置 */ static int32_t PlsrRunControlAbsLocalPos(void) { - return g_plsr_accumulated_pulses - s_absolute_origin; + return g_plsr_accumulated_pulses - s_absolute_origin; /* 累计减去锁定原点 */ } /** @@ -647,15 +659,15 @@ static int32_t PlsrRunControlAbsLocalPos(void) */ static void PlsrRunControlGotoNextOrFinish(uint16_t cur_seg) { - int16_t next_seg_idx = PlsrRunControlNextSeg(cur_seg); + int16_t next_seg_idx = PlsrRunControlNextSeg(cur_seg); /* 解析下一段 */ - if (next_seg_idx < 0) + if (next_seg_idx < 0) /* 没有下一段 */ { - PlsrRunControlFinishAll(); + PlsrRunControlFinishAll(); /* 全部收工 */ } else { - PlsrRunControlBeginSeg((uint16_t)next_seg_idx); + PlsrRunControlBeginSeg((uint16_t)next_seg_idx); /* 开下一段 */ } } @@ -664,67 +676,69 @@ static void PlsrRunControlGotoNextOrFinish(uint16_t cur_seg) */ static void PlsrRunControlFinishAll(void) { - PlsrSignalIoCancelDelay(); - PlsrPulseDriverStop(); - PlsrPulseDriverUnlockPsc(); - PlsrPulseDriverClearDir(); - g_plsr_busy = 0U; - s_state = RC_IDLE; - s_continue_without_stopping = 0U; - s_next_seg_start_freq_valid = 0U; - s_next_seg_start_freq_hz = 0U; - s_act_timer_armed = 0U; - s_act_expired = 0U; - s_act_waiting_for_pulse_boundary = 0U; - s_keep_freq_after_act = 0U; - s_wait_time_expired = 0U; - s_waiting_for_last_period = 0U; + PlsrSignalIoCancelDelay(); /* 取消未到期定时 */ + PlsrPulseDriverStop(); /* 停脉冲 */ + PlsrPulseDriverUnlockPsc(); /* 解锁 PSC */ + PlsrPulseDriverClearDir(); /* 清方向脚 */ + g_plsr_busy = 0U; /* 不忙了 */ + s_state = RC_IDLE; /* 回到空闲 */ + s_continue_without_stopping = 0U; /* 清段间不停表标志 */ + s_next_seg_start_freq_valid = 0U; /* 清衔接频率有效 */ + s_next_seg_start_freq_hz = 0U; /* 衔接频率清零 */ + s_act_timer_armed = 0U; /* 清 ACT 定时已开标志 */ + s_act_expired = 0U; /* 清 ACT 时间到请求 */ + s_act_waiting_for_pulse_boundary = 0U; /* 清等脉冲边界 */ + s_keep_freq_after_act = 0U; /* 清 ACT 后频率衔接 */ + s_wait_time_expired = 0U; /* 清 WAIT 时间到 */ + s_waiting_for_last_period = 0U; /* 清末拍收尾等待 */ } -/* 开一段:算位移/方向 → PlanSeg → 选无缝/同向直开/换向延时 */ +/** + * @brief 开一段:算位移/方向 → ResolveEndpoints → PlanSeg → 无缝/同向直开/换向延时 + */ static void PlsrRunControlBeginSeg(uint16_t seg_idx) { - int32_t cnt; - int32_t move; - uint32_t f_tgt; - uint32_t total; - PlsrSegPlanEndpoints_t endpoints; - /*如果段号大于总段数,直接结束输出*/ - if (seg_idx >= PlsrParamGetSegCount()) + int32_t cnt; /* 段表 pulse_cnt */ + int32_t move; /* 本段实际位移(有符号) */ + uint32_t f_tgt; /* 本段目标频率 */ + uint32_t total; /* 本段目标脉冲绝对值 */ + PlsrSegPlanEndpoints_t endpoints; /* 策略层解析的起/止速与加减速 ms */ + /* 如果段号大于总段数,直接结束输出 */ + if (seg_idx >= PlsrParamGetSegCount()) /* 段号越界 */ { - PlsrRunControlFinishAll(); - return; + PlsrRunControlFinishAll(); /* 直接全收工 */ + return; /* 回去 */ } - g_plsr_cur_seg_idx = seg_idx; - s_waiting_for_last_period = 0U;/* 等末拍 UPDATE 再收尾标志 */ - cnt = g_plsr_segs[seg_idx].pulse_cnt;/*读取总脉冲数*/ + g_plsr_cur_seg_idx = seg_idx; /* 记下当前段 */ + s_waiting_for_last_period = 0U; /* 等末拍 UPDATE 再收尾标志 */ + cnt = g_plsr_segs[seg_idx].pulse_cnt; /* 读取段表脉冲数 */ - /*读取运行模式,绝对模式以启动位置为绝对原点*/ - if (g_plsr_config.run_mode == PLSR_POS_ABSOLUTE) + /* 读取运行模式,绝对模式以启动位置为绝对原点 */ + if (g_plsr_config.run_mode == PLSR_POS_ABSOLUTE) /* 读运行模式 */ { /* 以首次启动锁定原点:move = 段目标 − 相对原点位置 */ - move = cnt - PlsrRunControlAbsLocalPos(); + move = cnt - PlsrRunControlAbsLocalPos(); /* 目标减当前位置 */ } else { - move = cnt;/*行对模式下位移量=脉冲数*/ + move = cnt; /* 相对模式:位移量 = 脉冲数 */ } - if (move == 0) + if (move == 0) /* 不用动了 */ { /* 相对 0 脉冲 / 无效占位(频率0且脉冲0) / 绝对已在目标:立刻段后逻辑 */ - g_plsr_busy = 1U; - s_seg_pulse_target = 0; - s_seg_pulses_done = 0; - PlsrRunControlAfterSegDone();/*段正常结束*/ - return; + g_plsr_busy = 1U; /* 仍置忙,方便段后逻辑 */ + s_seg_pulse_target = 0; /* 目标脉冲 0 */ + s_seg_pulses_done = 0; /* 已发也 0 */ + PlsrRunControlAfterSegDone(); /* 段正常结束 */ + return; /* 直接走段后 */ } - if (move >= 0) + if (move >= 0) /* 正方向位移 */ { - s_forward = 1U;/*设置方向标志,正向1,反向0*/ - s_seg_pulse_target = move;/*脉冲目标数=移动量*/ + s_forward = 1U; /* 正向 */ + s_seg_pulse_target = move; /* 目标脉冲 = 位移 */ } else { @@ -733,111 +747,112 @@ static void PlsrRunControlBeginSeg(uint16_t seg_idx) * 被解读为 -2147483648)时取反溢出,s_seg_pulse_target 仍为负数, * 首拍后 s_seg_pulses_done>=s_seg_pulse_target 恒真,会误判段结束且累计每启一次减 1。 */ - if (move == (int32_t)(-2147483647L - 1L)) + if (move == (int32_t)(-2147483647L - 1L)) /* 反向极端值,取反会炸 */ { - PlsrCommandSetFault(PLSR_ERR_PULSE_RANGE); - PlsrRunControlFinishAll();/*全段结束*/ - return; + PlsrCommandSetFault(PLSR_ERR_PULSE_RANGE); /* 脉冲范围故障 */ + PlsrRunControlFinishAll(); /* 全段结束 */ + return; /* 回去 */ } - s_forward = 0U;/* 反向移动 */ - s_seg_pulse_target = -move;/* 移动量负脉冲个数 */ + s_forward = 0U; /* 反向 */ + s_seg_pulse_target = -move; /* 目标脉冲 = |位移| */ } - + /* 0x04:本段(或默认速度)频率非法 */ - if (PlsrRunControlGetSegTargetFreq(g_plsr_segs[seg_idx].freq_hz, + if (PlsrRunControlGetSegTargetFreq(g_plsr_segs[seg_idx].freq_hz, /* 本段目标频率合法性检查 */ g_plsr_config.default_speed, &f_tgt) == 0U) { - PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); - PlsrRunControlFinishAll(); - return; + PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); /* 频率非法报故障 */ + PlsrRunControlFinishAll(); /* 收工 */ + return; /* 回去 */ } /* 策略层解析起/止速与加减速;段内只跑 PlanSeg */ - (void)PlsrRunControlResolveSegPlanEndpoints(seg_idx, f_tgt, &endpoints); + (void)PlsrRunControlResolveSegPlanEndpoints(seg_idx, f_tgt, &endpoints); /* 解析入口/出口/加减速时间 */ + + total = (uint32_t)s_seg_pulse_target; /* 本段要发的脉冲总数 */ - total = (uint32_t)s_seg_pulse_target; - - /*规划本段并锁 PSC / 进初始相*/ - PlsrRunControlPlanSeg(total, endpoints.freq_start_hz, f_tgt, endpoints.freq_end_hz, + /* 规划本段并锁 PSC / 进初始相 */ + PlsrRunControlPlanSeg(total, endpoints.freq_start_hz, f_tgt, endpoints.freq_end_hz, /* 按端点规划本段曲线 */ endpoints.accel_ms, endpoints.decel_ms); - - s_seg_pulses_done = 0;/*已发脉冲数清零*/ - g_plsr_busy = 1U;/*运行状态置1*/ + + s_seg_pulses_done = 0; /* 已发脉冲数清零 */ + g_plsr_busy = 1U; /* 置忙 */ { /* 用本段结束后的坐标判 keep,与 AfterSegDone 一致;结果锁进 s_stop_after_last_pulse */ - int32_t end_pos = PlsrRunControlAbsLocalPos(); + int32_t end_pos = PlsrRunControlAbsLocalPos(); /* 预估段末局部坐标 */ - if (s_forward != 0U) + if (s_forward != 0U) /* 正转估段末位置 */ { - end_pos += s_seg_pulse_target; + end_pos += s_seg_pulse_target; /* 正转:末位 = 现在 + 目标 */ } else { - end_pos -= s_seg_pulse_target; + end_pos -= s_seg_pulse_target; /* 反转:末位 = 现在 − 目标 */ } - s_stop_after_last_pulse = + /* 1=末拍完整停表;0=FOLLOW 不停表衔接 */ + s_stop_after_last_pulse = /* 接得上就不停表;接不上末拍停表 */ (PlsrRunControlWillFollowKeepAt(seg_idx, end_pos) == 0U) ? 1U : 0U; } - if (total == 0U) + if (total == 0U) /* 总数为 0(理论上少见) */ { - PlsrRunControlAfterSegDone();/*单段正常结束*/ - return; + PlsrRunControlAfterSegDone(); /* 零脉冲:直接段后 */ + return; /* 回去 */ } - - /*段间不停表衔接(后续模式/ACT切段)*/ - if (s_continue_without_stopping != 0U) + + /* 段间不停表衔接(后续模式/ACT 切段) */ + if (s_continue_without_stopping != 0U) /* 上一段留下「不停表接着跑」 */ { - /* 分支 A:段间无缝(后续模式或 ACT切段) */ - PlsrPulseDriverClearOnePulseStop();/*清掉单脉冲停止*/ + /* 分支 A:段间无缝(后续模式或 ACT 切段) */ + PlsrPulseDriverClearOnePulseStop(); /* 清掉单脉冲停止 */ /* * 必须先 RC_RUN 再 RefreshProfile/Start:否则冷启动首拍 UPDATE 时 * OnPulseIsr 仍见非 RUN 直接 return,影子停在起跳频,第 1、2 拍同频。 */ - s_state = RC_RUN; - s_continue_without_stopping = 0U;/*段间不停表标志置0*/ + s_state = RC_RUN; /* 先标成正在发脉冲 */ + s_continue_without_stopping = 0U; /* 用过即清 */ /* * FOLLOW 真不停表:do_start=0 只改频。 * ACT 经 OPM 边界停表后 g_plsr_pwm_running 已为 0:须 Start 重开,否则无脉冲卡死。 - * 1需要开始pwm输出,0已经在运行。只刷新下一拍频率*/ - PlsrRunControlRefreshProfile((g_plsr_pwm_running == 0U) ? 1U : 0U); - /*开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */ - PlsrRunControlArmActExtOnPulseStart(); + * 1=需开 PWM;0=已在跑只刷新下一拍频率 + */ + PlsrRunControlRefreshProfile((g_plsr_pwm_running == 0U) ? 1U : 0U); /* 停过就真正开表,否则只改频 */ + /* 开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */ + PlsrRunControlArmActExtOnPulseStart(); /* EXT 清沿 / ACT 开定时 */ } - else if ((g_plsr_direction_valid != 0U) && (s_forward == g_plsr_direction_forward)) + else if ((g_plsr_direction_valid != 0U) && (s_forward == g_plsr_direction_forward)) /* 同向且方向脚已对 */ { - /* 分支 B:真换向但本段与上一段同向,方向脚已正确,跳过延时 */ - PlsrPulseDriverSetDir(s_forward);/*跳过方向延时*/ - s_state = RC_RUN; - PlsrRunControlRefreshProfile(1U);/*传1,已运行,只刷新频率*/ - /*开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */ - PlsrRunControlArmActExtOnPulseStart(); + /* 分支 B:本段与上一段同向,方向脚已正确,跳过延时 */ + PlsrPulseDriverSetDir(s_forward); /* 再确认写一次方向 */ + s_state = RC_RUN; /* 直接进入正在发脉冲 */ + PlsrRunControlRefreshProfile(1U); /* 冷开:Start + 写频 */ + /* 开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */ + PlsrRunControlArmActExtOnPulseStart(); /* EXT 清沿 / ACT 开定时 */ } - else + else /* 要换向或第一次开跑 */ { /* 分支 C:需要换向或首次开跑 — 先打方向,再决定立刻开或 DIR_WAIT */ - PlsrPulseDriverSetDir(s_forward);/*设置方向*/ - if (g_plsr_config.dir_delay_ms == 0U) + PlsrPulseDriverSetDir(s_forward); /* 设置方向脚 */ + if (g_plsr_config.dir_delay_ms == 0U) /* 换向延时配成 0 */ { - s_state = RC_RUN; - /*传1,已运行,只刷新频率*/ - PlsrRunControlRefreshProfile(1U); - /*开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */ - PlsrRunControlArmActExtOnPulseStart(); + s_state = RC_RUN; /* 不等,直接正在发脉冲 */ + PlsrRunControlRefreshProfile(1U); /* 无延时:立刻开表 */ + /* 开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */ + PlsrRunControlArmActExtOnPulseStart(); /* EXT 清沿 / ACT 开定时 */ } else { /* * 先置 DIR_WAIT 再开 TIM5,避免极短延时下 IRQ 早于状态切换。 */ - s_state = RC_DIR_WAIT; - PlsrRunControlWakeDrain(); - /*设置方向延时*/ - PlsrSignalIoScheduleDelayMs((uint32_t)g_plsr_config.dir_delay_ms); - if (g_plsr_accel_runtime.cur_freq_hz >= 1U) + s_state = RC_DIR_WAIT; /* 先标成等换向延时 */ + PlsrRunControlWakeDrain(); /* 排空残留唤醒令牌 */ + /* 设置方向延时 */ + PlsrSignalIoScheduleDelayMs((uint32_t)g_plsr_config.dir_delay_ms); /* 开 TIM5 换向延时 */ + if (g_plsr_accel_runtime.cur_freq_hz >= 1U) /* 起跳频有效 */ { - /*换向延时期间预装寄存器、CEN 保持关 */ - PlsrPulseDriverPrepare(g_plsr_accel_runtime.cur_freq_hz); + /* 换向延时期间预装寄存器、CEN 保持关 */ + PlsrPulseDriverPrepare(g_plsr_accel_runtime.cur_freq_hz); /* 延时期间预装定时器,先不开 CEN */ } } } @@ -852,10 +867,10 @@ static void PlsrRunControlBeginSeg(uint16_t seg_idx) */ static void PlsrRunControlClearChainAndStop(void) { - PlsrPulseDriverStop(); - s_continue_without_stopping = 0U; - s_next_seg_start_freq_valid = 0U; - s_next_seg_start_freq_hz = 0U; + PlsrPulseDriverStop(); /* 停脉冲输出 */ + s_continue_without_stopping = 0U; /* 清不停表衔接 */ + s_next_seg_start_freq_valid = 0U; /* 清衔接频率有效 */ + s_next_seg_start_freq_hz = 0U; /* 衔接频率清零 */ } /** @@ -864,32 +879,33 @@ static void PlsrRunControlClearChainAndStop(void) */ static void PlsrRunControlApplyKeepOrStop(uint8_t allow_act_handoff) { - int16_t next_seg_idx; - uint8_t keep; - uint8_t pwm_ok; + int16_t next_seg_idx; /* 下一段索引;<0 无下一段 */ + uint8_t keep; /* 1=不停表衔接 */ + uint8_t pwm_ok; /* PWM 还在跑,或 ACT 时间到先停表后仍允许接着开下一段 */ - next_seg_idx = PlsrRunControlNextSeg(g_plsr_cur_seg_idx); - pwm_ok = (g_plsr_pwm_running != 0U) || + next_seg_idx = PlsrRunControlNextSeg(g_plsr_cur_seg_idx); /* 看看有没有下一段 */ + pwm_ok = (g_plsr_pwm_running != 0U) || /* PWM 在跑,或允许 ACT 切段衔接 */ ((allow_act_handoff != 0U) && (s_keep_freq_after_act != 0U)); - keep = 0U; - if ((next_seg_idx >= 0) && (pwm_ok != 0U) && (g_plsr_output_freq_hz >= 1U) && + keep = 0U; /* 默认先当要停表 */ + /* 有下一段 + PWM 可用 + 当前频有效 + 同向 → keep */ + if ((next_seg_idx >= 0) && (pwm_ok != 0U) && (g_plsr_output_freq_hz >= 1U) && /* 下一段在、能跑、频有效、同向 */ (PlsrRunControlIsForward((uint16_t)next_seg_idx, PlsrRunControlAbsLocalPos()) == s_forward)) { - keep = 1U; + keep = 1U; /* 可以段间不停表接着跑 */ } - if (keep != 0U) + if (keep != 0U) /* 决定不停表衔接 */ { - PlsrPulseDriverClearOnePulseStop(); - s_continue_without_stopping = 1U; - s_next_seg_start_freq_valid = 1U; - s_next_seg_start_freq_hz = g_plsr_output_freq_hz; + PlsrPulseDriverClearOnePulseStop(); /* 清掉单脉冲停表残留 */ + s_continue_without_stopping = 1U; /* 下一段无缝开 */ + s_next_seg_start_freq_valid = 1U; /* 入口频率有效 */ + s_next_seg_start_freq_hz = g_plsr_output_freq_hz; /* 入口=当前频 */ } else { - PlsrRunControlClearChainAndStop(); - PlsrPulseDriverClearOnePulseStop(); + PlsrRunControlClearChainAndStop(); /* 停表并清频率链 */ + PlsrPulseDriverClearOnePulseStop(); /* 顺带清单脉冲停 */ } } @@ -899,14 +915,14 @@ static void PlsrRunControlApplyKeepOrStop(uint8_t allow_act_handoff) */ static uint8_t PlsrRunControlBlocksFollowKeep(uint16_t cur_seg) { - if ((g_plsr_segs[cur_seg].wait_type == PLSR_WAIT_TIME) || + if ((g_plsr_segs[cur_seg].wait_type == PLSR_WAIT_TIME) || /* 这些等待类型必须停表再等 */ (g_plsr_segs[cur_seg].wait_type == PLSR_WAIT_SIGNAL) || (g_plsr_segs[cur_seg].wait_type == PLSR_WAIT_ACT) || (g_plsr_segs[cur_seg].wait_type == PLSR_WAIT_EXT)) { - return 1U; + return 1U; /* 禁止段间不停表接着跑 */ } - return 0U; + return 0U; /* 其它类型允许(含 EXT_OR_DONE) */ } /** @@ -918,63 +934,65 @@ static uint8_t PlsrRunControlWillFollowKeepAt(uint16_t cur_seg, int32_t local_po { int16_t next_eff; - if (g_plsr_config.send_mode != PLSR_SEND_FOLLOW) + if (g_plsr_config.send_mode != PLSR_SEND_FOLLOW) /* 不是后续模式 */ { - return 0U; + return 0U; /* 不能不停表衔接 */ } - if (PlsrRunControlNextSeg(cur_seg) < 0) + if (PlsrRunControlNextSeg(cur_seg) < 0) /* 没有逻辑下一段 */ { - return 0U; + return 0U; /* 接不了 */ } - next_eff = PlsrRunControlNextEffectiveSeg(cur_seg); - if (next_eff < 0) + next_eff = PlsrRunControlNextEffectiveSeg(cur_seg); /* 找下一有效段 */ + if (next_eff < 0) /* 有效段也没有 */ { - return 0U; + return 0U; /* 接不了 */ } /* * 直接下一段为无效占位时不能「跳过」该段,但仍可与下一有效段同向 keep * (EXT_OR_DONE 同向不应因中间占位而强制停到 0 再爬)。 */ - if (PlsrRunControlIsForward((uint16_t)next_eff, local_pos) != s_forward) + if (PlsrRunControlIsForward((uint16_t)next_eff, local_pos) != s_forward) /* 和下一段方向不一致 */ { - return 0U; + return 0U; /* 换向必须停表 */ } - if (PlsrRunControlBlocksFollowKeep(cur_seg) != 0U) + if (PlsrRunControlBlocksFollowKeep(cur_seg) != 0U) /* 本段等待类型要求停表等条件 */ { - return 0U; + return 0U; /* 必须停表 */ } - return 1U; + return 1U; /* 可以段间不停表接着跑 */ } /*============================================================================*/ /* ACT / EXT / 段后等待 */ /*============================================================================*/ -/* @brief 开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */ +/** + * @brief 开始输出时:EXT 类清旧沿;ACT 类启动段内定时 + */ static void PlsrRunControlArmActExtOnPulseStart(void) { uint16_t act_time_ms; - - /*EXT信号/EXT或脉冲发送完成,清掉X4,X5信号的边沿,防止误触*/ - if ((g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT) || + + /* EXT / EXT_OR_DONE:清 X4/X5 旧沿,防止开跑立刻误切段 */ + if ((g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT) || /* EXT / 外部或发完:先清旧沿 */ (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT_OR_DONE)) { - PlsrSignalIoClearEdges(); + PlsrSignalIoClearEdges(); /* 免得一开跑就误切段 */ } - - /*清掉ACT定时的相关标志*/ - s_act_timer_armed = 0U;/*启用定时器*/ - s_act_expired = 0U;/*act定时到期*/ - s_act_waiting_for_pulse_boundary = 0U;/*等待脉冲边界*/ - s_keep_freq_after_act = 0U;/*act切断后保持频率*/ - s_wait_time_expired = 0U;/*wait时间到期标志*/ - - /*act时间切段置标志位,开定时*/ - if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_ACT) + + /* 开跑前清 ACT/WAIT 残留,避免上一段标志串进来 */ + s_act_timer_armed = 0U; /* 清「ACT 定时已开」标志 */ + s_act_expired = 0U; /* 清 ACT 到期请求 */ + s_act_waiting_for_pulse_boundary = 0U; /* 清脉冲边界切段等待 */ + s_keep_freq_after_act = 0U; /* 清 ACT 频率衔接 */ + s_wait_time_expired = 0U; /* 清 WAIT 时间到期 */ + + /* WAIT_ACT:开 TIM5 计 ACT 时间,到点后等当前这拍发完再切段 */ + if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_ACT) /* 本段是 ACT 时间等待 */ { - act_time_ms = g_plsr_segs[g_plsr_cur_seg_idx].act_ms; - s_act_timer_armed = 1U; - PlsrSignalIoScheduleDelayMs((uint32_t)act_time_ms); + act_time_ms = g_plsr_segs[g_plsr_cur_seg_idx].act_ms; /* 读段表 ACT 毫秒 */ + s_act_timer_armed = 1U; /* 记下:ACT 定时已经开了 */ + PlsrSignalIoScheduleDelayMs((uint32_t)act_time_ms); /* 开 TIM5 倒计时 */ } } @@ -986,16 +1004,16 @@ static void PlsrRunControlArmActExtOnPulseStart(void) */ static void PlsrRunControlCutSegToNext(void) { - PlsrSignalIoCancelDelay(); - s_state = RC_IDLE; - s_act_timer_armed = 0U; - s_act_expired = 0U; - s_act_waiting_for_pulse_boundary = 0U; - s_keep_freq_after_act = 0U; - s_wait_time_expired = 0U; - - PlsrRunControlApplyKeepOrStop(0U); - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); + PlsrSignalIoCancelDelay(); /* 取消 ACT/方向等未到期定时 */ + s_state = RC_IDLE; /* 暂时回到空闲 */ + s_act_timer_armed = 0U; /* 清 ACT 定时已开 */ + s_act_expired = 0U; /* 清 ACT 时间到请求 */ + s_act_waiting_for_pulse_boundary = 0U; /* 清等脉冲边界 */ + s_keep_freq_after_act = 0U; /* 清 ACT 频率衔接 */ + s_wait_time_expired = 0U; /* 清 WAIT 时间到 */ + + PlsrRunControlApplyKeepOrStop(0U); /* EXT 切段:不允许「停表后还接着跑」那种衔接 */ + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 去开下一段或收工 */ } /** @@ -1007,15 +1025,15 @@ static void PlsrRunControlCutSegToNext(void) */ static void PlsrRunControlActExpire(void) { - s_act_timer_armed = 0U; - s_act_expired = 0U; - s_wait_time_expired = 0U; - s_state = RC_IDLE; - /*同向且有有效频率则不停表衔接,否则停表清链,传入1需要频率衔接*/ - PlsrRunControlApplyKeepOrStop(1U); - s_keep_freq_after_act = 0U;/*保持频率衔接标志位置0*/ - - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); + s_act_timer_armed = 0U; /* 清 ACT 定时已开 */ + s_act_expired = 0U; /* 清到期请求(已在消费) */ + s_wait_time_expired = 0U; /* 顺带清 WAIT 到期 */ + s_state = RC_IDLE; /* 先回到空闲再切段 */ + /* 同向且有有效频率就段间不停表接着开;否则停表清链。传 1=允许 ACT 时间到后停表再接着跑 */ + PlsrRunControlApplyKeepOrStop(1U); /* 允许 ACT 边界后仍频率衔接 */ + s_keep_freq_after_act = 0U; /* 用过即清 */ + + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 丢掉本段剩余,开下一段 */ } /** @@ -1026,57 +1044,58 @@ static void PlsrRunControlActExpire(void) */ static void PlsrRunControlEnterPostWaitOrNext(void) { - uint16_t wms; + uint16_t wms; /* WAIT 时间 ms */ - if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_TIME) + if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_TIME) /* 段后等一段时间 */ { - wms = g_plsr_segs[g_plsr_cur_seg_idx].wait_ms; - if (wms == 0U) + wms = g_plsr_segs[g_plsr_cur_seg_idx].wait_ms; /* 读等待毫秒 */ + if (wms == 0U) /* 等待时间写成 0 */ { - wms = 1U; + wms = 1U; /* 0 视为最短 1ms */ } - PlsrRunControlClearChainAndStop(); - s_waiting_for_input_signal = 0U; - PlsrRunControlWakeDrain();/*清理过期令牌*/ - s_state = RC_WAIT_COND; - PlsrSignalIoScheduleDelayMs((uint32_t)wms); - return; + PlsrRunControlClearChainAndStop(); /* 先停表清频率链 */ + s_waiting_for_input_signal = 0U; /* 纯时间等,不读沿 */ + PlsrRunControlWakeDrain(); /* 清理过期令牌 */ + s_state = RC_WAIT_COND; /* 进入段后等待 */ + PlsrSignalIoScheduleDelayMs((uint32_t)wms); /* TIM5 到期后 TickMs 开下一段 */ + return; /* TIM5 到期后由 TickMs 接下一段 */ } - if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_SIGNAL) + if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_SIGNAL) /* 段后等 WAIT 口信号 */ { /* 与 WAIT 时间相同:本段发完停表,再等 EXTI 确认后的下降沿 */ - PlsrRunControlClearChainAndStop(); - if (PlsrSignalIoTakeWaitFalling() != 0U) + PlsrRunControlClearChainAndStop(); /* 停表清链 */ + if (PlsrSignalIoTakeWaitFalling() != 0U) /* 沿已经在了 */ { - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); - return; + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 沿已到:立刻下一段 */ + return; /* 沿已消费,回去 */ } - s_waiting_for_input_signal = 1U; - s_state = RC_WAIT_COND; - return; + s_waiting_for_input_signal = 1U; /* TickMs 轮询 WAIT 沿 */ + s_state = RC_WAIT_COND; /* 进入段后等待 */ + return; /* 回去等 TickMs 轮询 */ } - if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT) + if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_EXT) /* 段后还要等外部下降沿 */ { /* EXT信号:脉冲发完后仍要等 EXT 沿才跳转 */ - PlsrRunControlClearChainAndStop(); + PlsrRunControlClearChainAndStop(); /* 停表清链 */ /* 只清消抖中的假沿;已确认的 fell 保留,供下面 TakeExtFalling 消费 */ - PlsrSignalIoClearPending(); - if (PlsrSignalIoTakeExtFalling() != 0U) + PlsrSignalIoClearPending(); /* 清消抖里还没确认的假沿 */ + if (PlsrSignalIoTakeExtFalling() != 0U) /* EXT 沿已经确认到了 */ { - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); - return; + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 沿已到:立刻下一段 */ + return; /* 沿已消费,回去 */ } - s_waiting_for_input_signal = 1U; - s_state = RC_WAIT_COND; - return; + s_waiting_for_input_signal = 1U; /* TickMs 轮询 EXT 沿 */ + s_state = RC_WAIT_COND; /* 进入段后等待 */ + return; /* 回去等 TickMs 看 EXT */ } /* * EXT_OR_DONE:脉冲先发完 = 条件已满足,立刻下一段。 * EXT 先到:RUN 里已 CutSegToNext,走不到这里。 + * 其它无等待类型:同样直接 GotoNext。 */ - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 没额外等待:直接下一段或收工 */ } /** @@ -1084,78 +1103,79 @@ static void PlsrRunControlEnterPostWaitOrNext(void) */ static void PlsrRunControlAfterSegDone(void) { - uint8_t keep_pwm; + uint8_t keep_pwm; /* 1=不停表衔接下一段 */ /* 段末诊断:0x01 脉冲个数;若在减速相再核 0x03 */ - PlsrRunControlCheckPulseCntFault(); - PlsrRunControlCheckDecelCurveFault(); + PlsrRunControlCheckPulseCntFault(); /* 核对脉冲个数 */ + PlsrRunControlCheckDecelCurveFault(); /* 若在减速相再核曲线 */ /* 先脱离 RUN,避免脉冲 ISR 重入 */ - s_state = RC_IDLE; + s_state = RC_IDLE; /* 先脱离正在发脉冲,防 ISR 重入 */ /* 脉冲已发完但 ACT 时间未到 → 停表,等到到期再开下一段 */ - if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_ACT) - { - PlsrPulseDriverStop(); - PlsrPulseDriverClearOnePulseStop(); - s_continue_without_stopping = 0U; - s_next_seg_start_freq_valid = 0U; - s_next_seg_start_freq_hz = 0U; - s_act_expired = 0U; - if (s_act_timer_armed != 0U) + if (g_plsr_segs[g_plsr_cur_seg_idx].wait_type == PLSR_WAIT_ACT) /* 本段是 ACT:脉冲完了时间可能还没到 */ + { + PlsrPulseDriverStop(); /* 先停表 */ + PlsrPulseDriverClearOnePulseStop(); /* 清单脉冲停残留 */ + s_continue_without_stopping = 0U; /* 不许不停表衔接 */ + s_next_seg_start_freq_valid = 0U; /* 清衔接频率有效 */ + s_next_seg_start_freq_hz = 0U; /* 衔接频率清零 */ + s_act_expired = 0U; /* 清 ACT 到期请求 */ + if (s_act_timer_armed != 0U) /* ACT 定时还在走 */ { - uint32_t remain_ms = PlsrSignalIoDelayRemainMs(); + uint32_t remain_ms = PlsrSignalIoDelayRemainMs(); /* ACT 剩余时间 */ - PlsrSignalIoCancelDelay();//段发完后,wait时间取消旧定时器,重新计算剩余wait时间 - s_act_timer_armed = 0U; - if (remain_ms >= 1U) + PlsrSignalIoCancelDelay(); /* 取消旧定时,改用剩余时间重开 */ + s_act_timer_armed = 0U; /* 旧定时卸掉 */ + if (remain_ms >= 1U) /* 还剩至少 1ms */ { - s_waiting_for_input_signal = 0U; - PlsrRunControlWakeDrain(); - s_state = RC_WAIT_COND; - PlsrSignalIoScheduleDelayMs(remain_ms); - return; + s_waiting_for_input_signal = 0U; /* 纯时间等,不读沿 */ + PlsrRunControlWakeDrain(); /* 排空唤醒令牌 */ + s_state = RC_WAIT_COND; /* 等剩余 ACT 时间 */ + PlsrSignalIoScheduleDelayMs(remain_ms); /* 用剩余时间重开 TIM5 */ + return; /* 等 ACT 剩余时间到 */ } } else { - PlsrSignalIoCancelDelay();//计时已到,取消定时 + PlsrSignalIoCancelDelay(); /* 计时已到,取消定时 */ } - s_act_timer_armed = 0U; - PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); - return; + s_act_timer_armed = 0U; /* 确保 ACT 定时标志清掉 */ + PlsrRunControlGotoNextOrFinish(g_plsr_cur_seg_idx); /* 剩余为 0:立刻下一段 */ + return; /* ACT 剩余为 0:下一段开跑 */ } - s_act_timer_armed = 0U; - s_act_expired = 0U; - s_wait_time_expired = 0U; - /*硬件脉冲是否关闭,1不关,0关闭*/ - keep_pwm = (s_stop_after_last_pulse == 0U) ? 1U : 0U; + s_act_timer_armed = 0U; /* 非 ACT:清 ACT 定时标志 */ + s_act_expired = 0U; /* 清 ACT 时间到请求 */ + s_wait_time_expired = 0U; /* 清 WAIT 时间到 */ + /* 段初已判:0=末拍停表;1=FOLLOW keep 不停表 */ + keep_pwm = (s_stop_after_last_pulse == 0U) ? 1U : 0U; /* 0=可不停表接着跑;1=末拍已停 */ - if (g_plsr_config.send_mode == PLSR_SEND_COMPLETE) + if (g_plsr_config.send_mode == PLSR_SEND_COMPLETE) /* 完成模式 */ { /* 段正常结束:下一段起速优先用本段落地频(EXT_OR_DONE 完成时常为峰值) */ - s_next_seg_start_freq_hz = g_plsr_accel_plan.end_freq_hz; - s_next_seg_start_freq_valid = 1U; + s_next_seg_start_freq_hz = g_plsr_accel_plan.end_freq_hz; /* 下一段起速用本段落地频 */ + s_next_seg_start_freq_valid = 1U; /* 标记衔接频率有效 */ } - if (keep_pwm != 0U) + if (keep_pwm != 0U) /* 可以段间不停表接着跑 */ { - /* 后续同向且无门禁:不停表直接 BeginSeg */ - s_continue_without_stopping = 1U; + /* 后续同向且不用停下来等条件:不停表直接 BeginSeg */ + s_continue_without_stopping = 1U; /* 告诉 BeginSeg:别停表接着开 */ } else { - PlsrPulseDriverStop(); - PlsrPulseDriverClearOnePulseStop(); - s_continue_without_stopping = 0U; - if (g_plsr_config.send_mode == PLSR_SEND_FOLLOW) + PlsrPulseDriverStop(); /* 必须停表 */ + PlsrPulseDriverClearOnePulseStop(); /* 清单脉冲停 */ + s_continue_without_stopping = 0U; /* 清不停表标志 */ + if (g_plsr_config.send_mode == PLSR_SEND_FOLLOW) /* 后续模式但这次接不上 */ { - s_next_seg_start_freq_valid = 0U; + /* FOLLOW 但必须停表(换向/要等条件):清掉「接着用上一频」的标记 */ + s_next_seg_start_freq_valid = 0U; /* 清掉链式起速,下一段冷爬 */ } } - PlsrRunControlEnterPostWaitOrNext(); + PlsrRunControlEnterPostWaitOrNext(); /* 按 wait_type 进等待或下一段 */ } /*============================================================================*/ @@ -1170,39 +1190,39 @@ static void PlsrRunControlAfterSegDone(void) */ static void PlsrRunControlCheckPulseCntFault(void) { - if ((s_seg_pulse_target > 0) && (s_seg_pulses_done != s_seg_pulse_target)) + if ((s_seg_pulse_target > 0) && (s_seg_pulses_done != s_seg_pulse_target)) /* 目标>0 且实发对不上 */ { - PlsrCommandSetFault(PLSR_ERR_PULSE_CNT); + PlsrCommandSetFault(PLSR_ERR_PULSE_CNT); /* 报脉冲个数故障(不打断切段) */ } } /* 0x03 加速曲线诊断 */ static void PlsrRunControlCheckApproachCurveFault(uint8_t by_pulse_budget) { - if (g_plsr_accel_plan.accel_pulses == 0U) + if (g_plsr_accel_plan.accel_pulses == 0U) /* 没加速预算就不用查 */ { - return; + return; /* 直接过 */ } - if (by_pulse_budget != 0U) + if (by_pulse_budget != 0U) /* 按预算精确比对 */ { - if (g_plsr_accel_runtime.completed_pulses != g_plsr_accel_plan.accel_pulses) + if (g_plsr_accel_runtime.completed_pulses != g_plsr_accel_plan.accel_pulses) /* 走完的步数 ≠ 预算 */ { - PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH); + PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH); /* 加速曲线对不上 */ } } - else if (g_plsr_accel_runtime.completed_pulses > g_plsr_accel_plan.accel_pulses) + else if (g_plsr_accel_runtime.completed_pulses > g_plsr_accel_plan.accel_pulses) /* 提前到频:只查有没有超额 */ { - PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH); + PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH); /* 多走了,报曲线故障 */ } } /* 0x03 减速曲线诊断 */ static void PlsrRunControlCheckDecelCurveFault(void) { - if ((s_phase == PH_DECEL) && (g_plsr_accel_runtime.total_pulses > 0U) && + if ((s_phase == PH_DECEL) && (g_plsr_accel_runtime.total_pulses > 0U) && /* 减速相还没走完预算就结束了 */ (g_plsr_accel_runtime.completed_pulses < g_plsr_accel_runtime.total_pulses)) { - PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH); + PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH); /* 减速曲线对不上 */ } } @@ -1211,14 +1231,14 @@ static void PlsrRunControlOnApproachDone(void) { uint8_t by_budget; - if (s_phase != PH_APPROACH) + if (s_phase != PH_APPROACH) /* 本来就不在加速相 */ { - return; + return; /* 没事做 */ } /* n 已走到预算 → 按预算收尾精确比对;否则按提前到频只查超额 */ - by_budget = ((g_plsr_accel_plan.accel_pulses > 0U) + by_budget = ((g_plsr_accel_plan.accel_pulses > 0U) /* 是否按加速预算精确比对 */ && (g_plsr_accel_runtime.completed_pulses >= g_plsr_accel_plan.accel_pulses)) ? 1U : 0U; - PlsrRunControlCheckApproachCurveFault(by_budget); + PlsrRunControlCheckApproachCurveFault(by_budget); /* 按规则做加速诊断 */ } /*============================================================================*/ @@ -1226,20 +1246,21 @@ static void PlsrRunControlOnApproachDone(void) /*============================================================================*/ /** - * 解析段目标频率。 - * freq_hz==0 用返回default_freq;结果须落在 [1, 100000],否则返回 0(调用方写 0x04)。 - * 返回1/0表示频率能不能用,能用返回1,不能用返回0*/ + * @brief 解析段目标频率 + * @note freq_hz==0 用 default_spd;结果须落在 [1, 100000],否则返回 0(调用方写 0x04) + * @return 1=可用(*out_hz 已填);0=非法 + */ static uint8_t PlsrRunControlGetSegTargetFreq(int32_t freq_hz, uint32_t default_spd, uint32_t *out_hz) { uint32_t f; - if (freq_hz < 0) + if (freq_hz < 0) /* 频率写成负数 */ { return 0U;/*频率小于0,直接结束*/ } - if (freq_hz == 0) + if (freq_hz == 0) /* 频率写 0:改用默认速度 */ { f = default_spd;/*频率为零,替换为默认速度*/ } @@ -1248,88 +1269,91 @@ static uint8_t PlsrRunControlGetSegTargetFreq(int32_t freq_hz, f = (uint32_t)freq_hz;/*频率不为零,替换为传入的频率*/ } /* 合法范围:1Hz ~ 100kHz(含) */ - if ((f < 1U) || (f > 100000U)) + if ((f < 1U) || (f > 100000U)) /* 最终频率越界 */ { return 0U;/*频率范围不合法直接结束*/ } *out_hz = f;/*将最终的频率传回去*/ - return 1U; + return 1U; /* 频率可用 */ } /** 任务侧运行输出:0=停表;任务上下文 SetFreq / Start */ static void PlsrRunControlApplyOutFreq(uint32_t freq, uint8_t do_start) { - if (freq == 0U) + if (freq == 0U) /* 频率 0:直接停表 */ { - PlsrPulseDriverStop(); - return; + PlsrPulseDriverStop(); /* 停掉 PWM */ + return; /* 回去 */ } - if ((do_start != 0U) || (g_plsr_pwm_running == 0U)) + if ((do_start != 0U) || (g_plsr_pwm_running == 0U)) /* 要开表,或当前根本没在跑 */ { - PlsrPulseDriverStart(freq); + PlsrPulseDriverStart(freq); /* 真正开表写频 */ } - else if (freq != g_plsr_output_freq_hz) + else if (freq != g_plsr_output_freq_hz) /* 已在跑且频率有变 */ { - PlsrPulseDriverSetFreq(freq); + PlsrPulseDriverSetFreq(freq); /* 只改频率 */ } } /** 脉冲 ISR:只走 ARR 预装载路径 */ static void PlsrRunControlApplyOutFreqIsr(uint32_t freq) { - if (freq < 1U) + if (freq < 1U) /* ISR 里频率至少 1Hz */ { - freq = 1U; + freq = 1U; /* 兜底成 1 */ } - PlsrPulseDriverSetFreqIsr(freq); + PlsrPulseDriverSetFreqIsr(freq); /* 预装下一拍 ARR */ } +/** @brief 是否有第二相(减速/谷底回升)脉冲预算 */ static uint8_t PlsrRunControlHasDecel(void) { /* * 第二相脉冲预算 >0 即需要收尾斜坡。 * 谷底形(起/止速 > 目标):第二相是从目标再加速回止速,f_end > f_tgt。 */ - return (g_plsr_accel_plan.decel_pulses > 0U) ? 1U : 0U; + return (g_plsr_accel_plan.decel_pulses > 0U) ? 1U : 0U; /* 有第二相预算就返回 1 */ } +/* 本段剩余脉冲数(目标 − 已发);已发完返回 0 */ static uint32_t PlsrRunControlRemainPulses(void) { - if (s_seg_pulse_target > s_seg_pulses_done) + if (s_seg_pulse_target > s_seg_pulses_done) /* 还没发完 */ { - return (uint32_t)(s_seg_pulse_target - s_seg_pulses_done); + return (uint32_t)(s_seg_pulse_target - s_seg_pulses_done); /* 剩余 = 目标 − 已发 */ } - return 0U; + return 0U; /* 发完了当 0 */ } -/* remain==dec_n 时进入减速 */ +/* remain 落入减速预算窗口则应进 DECEL */ static uint8_t PlsrRunControlShouldEnterDecel(uint32_t remain) { - if (PlsrRunControlHasDecel() == 0U) + if (PlsrRunControlHasDecel() == 0U) /* 没有第二相 */ { - return 0U; + return 0U; /* 无第二相 */ } - return (remain <= g_plsr_accel_plan.decel_pulses) ? 1U : 0U; + return (remain <= g_plsr_accel_plan.decel_pulses) ? 1U : 0U; /* 剩余落入减速窗口 */ } +/* 进减速时的曲线步进预算:取 min(规划, remain),至少 1 */ static uint32_t PlsrRunControlDecelEnterBudget(uint32_t remain) { - uint32_t planned = g_plsr_accel_plan.decel_pulses; + uint32_t planned = g_plsr_accel_plan.decel_pulses; /* 规划减速脉冲数 */ - if (planned < 1U) + if (planned < 1U) /* 规划里没有减速?至少按 1 */ { - planned = 1U; + planned = 1U; /* 兜底 1 */ } - if (remain >= planned) + if (remain >= planned) /* 剩余够跑完整减速 */ { - return planned; + return planned; /* 剩余够跑完整减速 */ } - if (remain < 1U) + if (remain < 1U) /* 剩余已经没了 */ { - return 1U; + return 1U; /* 最少给 1 */ } - return remain; + return remain; /* 剩余不足:压缩预算 */ } /** @@ -1338,30 +1362,32 @@ static uint32_t PlsrRunControlDecelEnterBudget(uint32_t remain) */ static uint32_t PlsrRunControlDecelOutFreq(uint32_t freq, uint32_t remain) { - uint32_t end_hz = g_plsr_accel_plan.end_freq_hz; + uint32_t end_hz = g_plsr_accel_plan.end_freq_hz; /* 本段止速 */ - if (end_hz < 1U) + if (end_hz < 1U) /* 止速非法就当 1 */ { - end_hz = 1U; + end_hz = 1U; /* 兜底 */ } - if (remain <= 1U) + if (remain <= 1U) /* 最后一拍 */ { - return end_hz; + return end_hz; /* 末拍钉止速 */ } - if (g_plsr_accel_runtime.freq_rising == 0U) + /* 降频:提前碰到 end 则让出 +1Hz */ + if (g_plsr_accel_runtime.freq_rising == 0U) /* 正在降频 */ { - if ((freq <= end_hz) && (end_hz < 100000U)) + if ((freq <= end_hz) && (end_hz < 100000U)) /* 提前撞到止速 */ { - return end_hz + 1U; + return end_hz + 1U; /* 让出 1Hz,留给末拍 */ } } - else if ((freq >= end_hz) && (end_hz > 1U)) + /* 升频(谷底回升):提前碰到 end 则让出 −1Hz */ + else if ((freq >= end_hz) && (end_hz > 1U)) /* 正在升频回止速 */ { - return end_hz - 1U; + return end_hz - 1U; /* 提前撞到就让出 −1Hz */ } - return freq; + return freq; /* 正常斜坡值原样回 */ } /** @@ -1369,60 +1395,61 @@ static uint32_t PlsrRunControlDecelOutFreq(uint32_t freq, uint32_t remain) */ static void PlsrRunControlEnterDecel(uint32_t from_hz, uint32_t budget) { - PlsrAccelPlan_t decel_plan = g_plsr_accel_plan; + PlsrAccelPlan_t decel_plan = g_plsr_accel_plan; /* 局部副本,只改第二相字段 */ - if (budget < 1U) + if (budget < 1U) /* 预算至少 1 */ { - budget = 1U; + budget = 1U; /* 兜底 */ } - s_phase = PH_DECEL; + s_phase = PH_DECEL; /* 切到段末过渡相 */ - decel_plan.accel_pulses = 0U; - decel_plan.const_pulses = 0U; - decel_plan.decel_pulses = budget; - decel_plan.target_freq_hz = from_hz; - PlsrAccelBeginDecel(&g_plsr_accel_runtime, &decel_plan); - g_plsr_accel_runtime.cur_freq_hz = from_hz; + decel_plan.accel_pulses = 0U; /* 第二相不用加速预算 */ + decel_plan.const_pulses = 0U; /* 第二相不用匀速预算 */ + decel_plan.decel_pulses = budget; /* 本段第二相步进数 */ + decel_plan.target_freq_hz = from_hz; /* 减速起点频 */ + PlsrAccelBeginDecel(&g_plsr_accel_runtime, &decel_plan); /* 按副本启动减速斜坡 */ + g_plsr_accel_runtime.cur_freq_hz = from_hz; /* 当前频记成减速起点 */ } /* 开表纯减速:只 Start(f1)。下一拍起由 ISR NextFreq 写入 f2…f_end */ static void PlsrRunControlPrimeDecelOnStart(void) { - uint32_t next; + uint32_t next; /* 局部暂存 f1 */ - next = PlsrAccelNextFreq(&g_plsr_accel_runtime); - PlsrRunControlApplyOutFreq(next, 1U); + next = PlsrAccelNextFreq(&g_plsr_accel_runtime); /* 取 f1 */ + PlsrRunControlApplyOutFreq(next, 1U); /* Start PWM */ } /* 进匀速:写一次 f_tgt,之后 ISR 不改 ARR(复用缓存)*/ static void PlsrRunControlEnterConstHold(uint8_t do_start) { - uint32_t f_hold = g_plsr_accel_plan.target_freq_hz; + uint32_t f_hold = g_plsr_accel_plan.target_freq_hz; /* 匀速保持频 */ - if (f_hold < 1U) + if (f_hold < 1U) /* 峰值非法兜底 */ { - f_hold = 1U; + f_hold = 1U; /* 至少 1Hz */ } - s_phase = PH_CONST; - PlsrAccelBeginConstSpeed(&g_plsr_accel_runtime, &g_plsr_accel_plan); - PlsrPulseDriverClearPending(); - PlsrPulseDriverClearStartPeriodProtect(); - PlsrRunControlApplyOutFreq(f_hold, do_start); + s_phase = PH_CONST; /* 标成匀速相 */ + PlsrAccelBeginConstSpeed(&g_plsr_accel_runtime, &g_plsr_accel_plan); /* 曲线侧进匀速 */ + PlsrPulseDriverClearPending(); /* 清挂起改频 */ + PlsrPulseDriverClearStartPeriodProtect(); /* 清开表保护 */ + PlsrRunControlApplyOutFreq(f_hold, do_start); /* 写出匀速频率 */ } +/* ISR 侧进匀速:写 f_tgt,不走任务侧 Start */ static void PlsrRunControlEnterConstHoldIsr(void) { - uint32_t f_hold = g_plsr_accel_plan.target_freq_hz; + uint32_t f_hold = g_plsr_accel_plan.target_freq_hz; /* 匀速保持频 */ - if (f_hold < 1U) + if (f_hold < 1U) /* 峰值非法兜底 */ { - f_hold = 1U; + f_hold = 1U; /* 至少 1Hz */ } - s_phase = PH_CONST; - PlsrAccelBeginConstSpeed(&g_plsr_accel_runtime, &g_plsr_accel_plan); - PlsrPulseDriverClearPending(); - PlsrPulseDriverClearStartPeriodProtect(); - PlsrRunControlApplyOutFreqIsr(f_hold); + s_phase = PH_CONST; /* 标成匀速相 */ + PlsrAccelBeginConstSpeed(&g_plsr_accel_runtime, &g_plsr_accel_plan); /* 曲线侧进匀速 */ + PlsrPulseDriverClearPending(); /* 清挂起改频 */ + PlsrPulseDriverClearStartPeriodProtect(); /* 清开表保护 */ + PlsrRunControlApplyOutFreqIsr(f_hold); /* ISR 写 f_tgt */ } /** @@ -1431,56 +1458,58 @@ static void PlsrRunControlEnterConstHoldIsr(void) */ static void PlsrRunControlRefreshProfile(uint8_t do_start) { - uint32_t next; - uint32_t done_n; - uint32_t remain; + uint32_t next; /* 本拍应写频率 */ + uint32_t done_n; /* 已发脉冲(查表用) */ + uint32_t remain; /* 剩余脉冲 */ - done_n = 0U; - if (s_seg_pulses_done > 0) + done_n = 0U; /* 默认已发 0 */ + if (s_seg_pulses_done > 0) /* 有已发脉冲 */ { - done_n = (uint32_t)s_seg_pulses_done; + done_n = (uint32_t)s_seg_pulses_done; /* 转成无符号给查表 */ } - remain = PlsrRunControlRemainPulses(); + remain = PlsrRunControlRemainPulses(); /* 算剩余 */ - if ((s_phase == PH_CONST) && + /* 匀速但已进减速窗口:先切相再往下写频 */ + if ((s_phase == PH_CONST) && /* 匀速但剩余已进减速窗 */ (PlsrRunControlShouldEnterDecel(remain) != 0U)) { - PlsrRunControlEnterDecel(g_plsr_accel_plan.target_freq_hz, + PlsrRunControlEnterDecel(g_plsr_accel_plan.target_freq_hz, /* 先切到段末过渡 */ PlsrRunControlDecelEnterBudget(remain)); } - if (s_phase == PH_CONST) + if (s_phase == PH_CONST) /* 仍是匀速相 */ { - if ((do_start != 0U) || (g_plsr_pwm_running == 0U)) + /* 匀速:仅冷启动/未跑时写 f_tgt,跑着则复用 ARR */ + if ((do_start != 0U) || (g_plsr_pwm_running == 0U)) /* 冷启动或还没跑 */ { - PlsrRunControlApplyOutFreq(g_plsr_accel_plan.target_freq_hz, do_start); + PlsrRunControlApplyOutFreq(g_plsr_accel_plan.target_freq_hz, do_start); /* 写峰值(真正开表或改频) */ } - return; + return; /* 跑着匀速:ARR 复用,不写 */ } /* 纯减速开表:Start(f1),f2…f_end 由后续 UPDATE ISR 写入 */ - if ((s_phase == PH_DECEL) && + if ((s_phase == PH_DECEL) && /* 纯减速且刚开表、还没发过 */ (do_start != 0U) && (s_seg_pulses_done == 0) && (g_plsr_accel_runtime.completed_pulses == 0U)) { - PlsrRunControlPrimeDecelOnStart(); - return; + PlsrRunControlPrimeDecelOnStart(); /* Start(f1),后面 ISR 接着写 */ + return; /* 这拍处理完 */ } - next = PlsrAccelCurveFreqAtPulse(&g_plsr_accel_plan, done_n); - if (next < 1U) + next = PlsrAccelCurveFreqAtPulse(&g_plsr_accel_plan, done_n); /* 按已发拍查频 */ + if (next < 1U) /* 查表得到的频无效 */ { - next = 1U; + next = 1U; /* 兜底 1Hz */ } - g_plsr_accel_runtime.cur_freq_hz = next; + g_plsr_accel_runtime.cur_freq_hz = next; /* 同步运行时当前频 */ - if (s_phase == PH_APPROACH) + if (s_phase == PH_APPROACH) /* 还在起速爬峰 */ { /* * 加速相结束条件(任一满足即进 CONST 或 DECEL): * acc_n==0 规划无加速(纯匀速/纯减) - * active==0 曲线认为已到 f1 + * active==0 曲线认为已到 f1,当前相不在运行了。 * n >= acc_n 脉冲预算用尽 * next >= f_tgt 升频且下一拍频率已达/超过目标 * next <= f_tgt 降频且下一拍频率已达/低于目标 @@ -1492,24 +1521,25 @@ static void PlsrRunControlRefreshProfile(uint8_t do_start) ((g_plsr_accel_plan.target_freq_hz < g_plsr_accel_plan.start_freq_hz) && (next <= g_plsr_accel_plan.target_freq_hz))) { - next = g_plsr_accel_plan.target_freq_hz; - PlsrRunControlOnApproachDone();/* 加速结束诊断曲线 */ - if (PlsrRunControlShouldEnterDecel(remain) != 0U) + next = g_plsr_accel_plan.target_freq_hz; /* 钉峰值 */ + PlsrRunControlOnApproachDone(); /* 加速结束诊断曲线 */ + if (PlsrRunControlShouldEnterDecel(remain) != 0U) /* 该进减速 */ { - PlsrRunControlEnterDecel(next, + PlsrRunControlEnterDecel(next, /* 切入段末过渡 */ PlsrRunControlDecelEnterBudget(remain)); } else { - PlsrRunControlEnterConstHold(do_start); - return; + PlsrRunControlEnterConstHold(do_start); /* 进匀速并写表 */ + return; /* 匀速路径写完即回 */ } } } - if ((next != g_plsr_output_freq_hz) || (do_start != 0U) || (g_plsr_pwm_running == 0U)) + /* 频率有变 / 需开表 / 未在跑 → 写出 */ + if ((next != g_plsr_output_freq_hz) || (do_start != 0U) || (g_plsr_pwm_running == 0U)) /* 频变了 / 要开表 / 当前没跑 */ { - PlsrRunControlApplyOutFreq(next, do_start); + PlsrRunControlApplyOutFreq(next, do_start); /* 任务侧写出频率 */ } } @@ -1517,86 +1547,91 @@ static void PlsrRunControlRefreshProfile(uint8_t do_start) /* 规划 / 开段 */ /*============================================================================*/ -/* 解析本段规划端点:freq_start / freq_end / accel_ms / decel_ms */ +/** + * @brief 策略层解析本段端点:freq_start / freq_end / accel_ms / decel_ms + * @note 起速看 keep/链式落地/冷启动;止速看 EXT_OR_DONE 同向衔接或配置止速 + */ static uint8_t PlsrRunControlResolveSegPlanEndpoints(uint16_t seg_idx, uint32_t f_tgt, PlsrSegPlanEndpoints_t *endpoints) { - endpoints->accel_ms = g_plsr_config.accel_ms; - endpoints->decel_ms = g_plsr_config.decel_ms; + endpoints->accel_ms = g_plsr_config.accel_ms; /* 加速参考 ms */ + endpoints->decel_ms = g_plsr_config.decel_ms; /* 减速参考 ms */ - /*不停表衔接且输出频率>1或者下一段运行中,下一段的起始频率为当前输出频率*/ - if (((s_continue_without_stopping != 0U) || (g_plsr_pwm_running != 0U)) + /* —— 起速:不停表衔接 / 链式落地频 / 冷启动起速 —— */ + if (((s_continue_without_stopping != 0U) || (g_plsr_pwm_running != 0U)) /* 还在跑或要不停表接着跑,且当前频有效 */ && (g_plsr_output_freq_hz >= 1U)) { - endpoints->freq_start_hz = g_plsr_output_freq_hz; + /* FOLLOW/ACT keep:入口 = 当前输出频率 */ + endpoints->freq_start_hz = g_plsr_output_freq_hz; /* 入口就用现在的输出频 */ } - - /*如果下一段的起始频率有效且>1,下一段的起始频率为起始频率 */ - else if ((s_next_seg_start_freq_valid != 0U) && (s_next_seg_start_freq_hz >= 1U)) + else if ((s_next_seg_start_freq_valid != 0U) && (s_next_seg_start_freq_hz >= 1U)) /* 有上一段留下的落地起速 */ { /* 完成模式段末停表后:用本段落地频作起速(如 EXT_OR_DONE 的匀速峰值) */ - endpoints->freq_start_hz = s_next_seg_start_freq_hz; - s_next_seg_start_freq_valid = 0U; - s_next_seg_start_freq_hz = 0U; + endpoints->freq_start_hz = s_next_seg_start_freq_hz; /* 用链式落地频 */ + s_next_seg_start_freq_valid = 0U; /* 用过即清 */ + s_next_seg_start_freq_hz = 0U; /* 用过清掉数值 */ } else { - /* 停表后冷启动 */ - endpoints->freq_start_hz = PlsrAccelCurveResolveStartHz(g_plsr_config.start_speed, + /* 停表后冷启动:按起速参数解析 */ + endpoints->freq_start_hz = PlsrAccelCurveResolveStartHz(g_plsr_config.start_speed, /* 按起速参数算出入口频率 */ f_tgt, g_plsr_config.default_speed, endpoints->accel_ms, endpoints->decel_ms); } - /* 终止频率 */ + /* —— 止速:EXT_OR_DONE 同向衔接 vs 配置止速 —— */ { - int16_t next_eff = PlsrRunControlNextEffectiveSeg(seg_idx); + int16_t next_eff = PlsrRunControlNextEffectiveSeg(seg_idx); /* 跳过占位后的下一段 */ - if ((g_plsr_segs[seg_idx].wait_type == PLSR_WAIT_EXT_OR_DONE) && + if ((g_plsr_segs[seg_idx].wait_type == PLSR_WAIT_EXT_OR_DONE) && /* EXT_OR_DONE 且后面还有有效段 */ (next_eff >= 0)) { - int32_t end_pos = PlsrRunControlAbsLocalPos(); - uint8_t next_fwd; + int32_t end_pos = PlsrRunControlAbsLocalPos(); /* 本段结束时局部坐标 */ + uint8_t next_fwd; /* 下一段方向暂存 */ - if (s_forward != 0U) + if (s_forward != 0U) /* 正转:末位往上加 */ { - end_pos += s_seg_pulse_target; + end_pos += s_seg_pulse_target; /* 估段末坐标 */ } else { - end_pos -= s_seg_pulse_target; + end_pos -= s_seg_pulse_target; /* 反转:末位往下减 */ } - next_fwd = PlsrRunControlIsForward((uint16_t)next_eff, end_pos); + next_fwd = PlsrRunControlIsForward((uint16_t)next_eff, end_pos); /* 下一段在段末坐标下的方向 */ /* 与下一有效段同向 → 后续/完成衔接(换向才落到下方止速) */ - if (next_fwd == s_forward) + if (next_fwd == s_forward) /* 同向,可以谈衔接止速 */ { - if (g_plsr_config.send_mode == PLSR_SEND_FOLLOW) + if (g_plsr_config.send_mode == PLSR_SEND_FOLLOW) /* 后续模式 */ { - if (PlsrRunControlGetSegTargetFreq( + /* FOLLOW:出口钉下一段目标频,便于无缝衔接 */ + if (PlsrRunControlGetSegTargetFreq( /* 读下一段目标频当出口 */ g_plsr_segs[(uint16_t)next_eff].freq_hz, g_plsr_config.default_speed, &endpoints->freq_end_hz) != 0U) { - return 1U; + return 1U; /* 成功:出口已是下一段目标 */ } - endpoints->freq_end_hz = f_tgt; - return 1U; + endpoints->freq_end_hz = f_tgt; /* 下一段频非法则退回本段峰值 */ + return 1U; /* 返回(端点填好) */ } - endpoints->freq_end_hz = f_tgt; - return 1U; + /* 完成模式同向:出口钉本段峰值(段末停表后作下一段起速) */ + endpoints->freq_end_hz = f_tgt; /* 完成模式同向:出口钉本段峰值 */ + return 1U; /* 端点填好 */ } /* 与下一有效段反向:落入下方规划到止速 */ } } - endpoints->freq_end_hz = PlsrAccelCurveResolveEndHz(g_plsr_config.end_speed, + /* 默认:按配置止速参数解析出口频率 */ + endpoints->freq_end_hz = PlsrAccelCurveResolveEndHz(g_plsr_config.end_speed, /* 默认按配置止速解析出口 */ f_tgt, g_plsr_config.default_speed, endpoints->accel_ms, endpoints->decel_ms); - return 1U; + return 1U; /* 端点解析完成 */ } /** @@ -1609,12 +1644,12 @@ static void PlsrRunControlPlanSeg(uint32_t total, uint32_t f_from, uint32_t f_tgt, uint32_t f_end, uint16_t accel_ms, uint16_t decel_ms) { - uint32_t f_start; - uint32_t f_min; - uint32_t f_max; + uint32_t f_start; /* 规划后实际入口频率 */ + uint32_t f_min; /* 本段最低频(锁 PSC) */ + uint32_t f_max; /* 本段最高频(锁 PSC) */ - /*传给曲线规划模块进行曲线规划*/ - PlsrAccelCurvePlan(&g_plsr_accel_plan, + /* 传给曲线规划模块进行曲线规划 */ + PlsrAccelCurvePlan(&g_plsr_accel_plan, /* 丢给曲线模块做规划 */ total, f_from, f_tgt, @@ -1624,98 +1659,98 @@ static void PlsrRunControlPlanSeg(uint32_t total, uint32_t f_from, decel_ms, g_plsr_config.accel_mode); - /* 0x02 频率是否与设定一致诊断/\或\/ */ - if ((f_tgt > f_from) && (g_plsr_accel_plan.target_freq_hz < f_tgt)) + /* 0x02:规划峰值达不到设定 → 三角波压峰告警 */ + if ((f_tgt > f_from) && (g_plsr_accel_plan.target_freq_hz < f_tgt)) /* 要爬升但规划峰够不着 */ { - PlsrCommandSetFault(PLSR_ERR_FREQ_UNREACH); + PlsrCommandSetFault(PLSR_ERR_FREQ_UNREACH); /* 报频率达不到 */ } - else if ((f_tgt < f_from) && (g_plsr_accel_plan.target_freq_hz > f_tgt)) + else if ((f_tgt < f_from) && (g_plsr_accel_plan.target_freq_hz > f_tgt)) /* 要下降但规划峰压不下去 */ { - PlsrCommandSetFault(PLSR_ERR_FREQ_UNREACH); + PlsrCommandSetFault(PLSR_ERR_FREQ_UNREACH); /* 同样报达不到 */ } - g_plsr_accel_runtime.total_pulses = 0U;/*开始运行前当前相计划步进的脉冲数清零*/ + g_plsr_accel_runtime.total_pulses = 0U; /* 开跑前清当前相步进计数 */ /* S/正弦:在任务上下文预建频率表,ISR 只查表 */ - PlsrAccelPrebuildFreqTables(&g_plsr_accel_plan); + PlsrAccelPrebuildFreqTables(&g_plsr_accel_plan); /* S/正弦表预建好 */ - /* 运行层使用规划后的实际起始频率。 */ - f_start = g_plsr_accel_plan.start_freq_hz; + /* 运行层使用规划后的实际起始频率 */ + f_start = g_plsr_accel_plan.start_freq_hz; /* 规划后的实际入口 */ /* 脉冲域:ISR 用 PlsrAccelNextFreq(直线现场算 / S·正弦查预建表)*/ /* 本段频率范围锁 PSC,升降只改 ARR;跨度过大则 LockPscRange 自动不锁 */ /* 本段可能出现的最低/最高频率,取 入口、目标、出口 三者的 min/max */ - f_min = g_plsr_accel_plan.target_freq_hz; - f_max = g_plsr_accel_plan.target_freq_hz; - /*先找入口的最大最小频率*/ - if (f_start > f_max) + f_min = g_plsr_accel_plan.target_freq_hz; /* 先用目标频当上下限种子 */ + f_max = g_plsr_accel_plan.target_freq_hz; /* 最高频种子 */ + /* 纳入入口频 */ + if (f_start > f_max) /* 入口比现在最高还高 */ { - f_max = f_start;/*起始频率大于目标频率时,最大频率用起始频率*/ + f_max = f_start; /* 抬高上限 */ } - if (f_start >= 1U) + if (f_start >= 1U) /* 入口频率合法 */ { - if (f_start < f_min) + if (f_start < f_min) /* 入口更低 */ { - f_min = f_start;/*起始频率小于目标频率,最小频率使用起始频率*/ + f_min = f_start; /* 压低下限 */ } } else { - f_min = 1U;/* 否则最小频率为1 */ + f_min = 1U; /* 入口无效:下限至少 1 */ } - - /*找出口的最大最小频率*/ - if (g_plsr_accel_plan.end_freq_hz > f_max) + + /* 纳入出口频 */ + if (g_plsr_accel_plan.end_freq_hz > f_max) /* 出口比上限高 */ { - f_max = g_plsr_accel_plan.end_freq_hz;/*出口频率大于最大值,则成为最大值*/ + f_max = g_plsr_accel_plan.end_freq_hz; /* 抬高上限 */ } - if (g_plsr_accel_plan.end_freq_hz >= 1U) + if (g_plsr_accel_plan.end_freq_hz >= 1U) /* 出口频率合法 */ { - if (g_plsr_accel_plan.end_freq_hz < f_min) + if (g_plsr_accel_plan.end_freq_hz < f_min) /* 出口更低 */ { - f_min = g_plsr_accel_plan.end_freq_hz;/*出口频率小于小值,则成为最小值*/ + f_min = g_plsr_accel_plan.end_freq_hz; /* 压低下限 */ } } else { - if (f_min > 1U) + if (f_min > 1U) /* 出口无效时看下限 */ { - f_min = 1U;/* 否则,最小值为1 */ + f_min = 1U; /* 下限收到 1 */ } } - - if (f_min < 1U) + + if (f_min < 1U) /* 下限再兜底 */ { - f_min = 1U;/*如果最小值小于1,则最小值改为1*/ + f_min = 1U; /* 至少 1Hz */ } - if (f_max < f_min) + if (f_max < f_min) /* 上限反比下限还小 */ { - f_max = f_min;/*如果找出来的最大值小于最小值,让最大值等于最小值*/ + f_max = f_min; /* 兜底:保证 f_max >= f_min */ } /* 后续同向不停表时 PWM 仍在跑:禁止重锁 PSC */ - if (g_plsr_pwm_running == 0U) + if (g_plsr_pwm_running == 0U) /* 当前没在跑才许锁 PSC */ { - PlsrPulseDriverLockPscRange(f_min, f_max); + PlsrPulseDriverLockPscRange(f_min, f_max); /* 按本段频宽锁分频 */ } - /* 保持 AccelCurvePlan 算出的脉冲预算;运行时逐拍计算下一频率 */ - if ((g_plsr_accel_plan.decel_pulses >= total) && + /* 据规划选初始相:纯减 / 匀速 / 加速 */ + if ((g_plsr_accel_plan.decel_pulses >= total) && /* 全程几乎都是减速且入口已在峰上/之上 */ (total > 0U) && (g_plsr_accel_plan.end_freq_hz != g_plsr_accel_plan.target_freq_hz) && (f_start >= g_plsr_accel_plan.target_freq_hz)) { - /*纯减开段,脉冲数不足以减速到目标频率 */ - PlsrRunControlEnterDecel(f_start, g_plsr_accel_plan.decel_pulses); + /* 纯减开段:全程不够爬峰,直接从入口进减速 */ + PlsrRunControlEnterDecel(f_start, g_plsr_accel_plan.decel_pulses); /* 直接从入口进段末过渡 */ } - else if (f_start == g_plsr_accel_plan.target_freq_hz) + else if (f_start == g_plsr_accel_plan.target_freq_hz) /* 入口正好等于峰值 */ { - s_phase = PH_CONST;/*匀速段*/ - PlsrAccelBeginConstSpeed(&g_plsr_accel_runtime, &g_plsr_accel_plan); + s_phase = PH_CONST; /* 入口已是峰值 → 匀速 */ + PlsrAccelBeginConstSpeed(&g_plsr_accel_runtime, &g_plsr_accel_plan); /* 曲线侧进匀速 */ } - else + else /* 入口和峰值不同 */ { - s_phase = PH_APPROACH;/*加速段*/ - PlsrAccelBeginAccel(&g_plsr_accel_runtime, &g_plsr_accel_plan); + s_phase = PH_APPROACH; /* 入口 ≠ 峰值 → 加速相 */ + PlsrAccelBeginAccel(&g_plsr_accel_runtime, &g_plsr_accel_plan); /* 曲线侧开始加速 */ } } diff --git a/plsr/signal_io/plsr_signal_io.c b/plsr/signal_io/plsr_signal_io.c index f53afaf..c6020a9 100644 --- a/plsr/signal_io/plsr_signal_io.c +++ b/plsr/signal_io/plsr_signal_io.c @@ -164,19 +164,20 @@ static void PlsrSignalIoTim5Init(void) { __HAL_RCC_TIM5_CLK_ENABLE(); - TIM5->CR1 = 0U;//定时器停止、向上计数、关闭单脉冲、普通边沿对齐 - TIM5->DIER = 0U;//DMA/中断使能寄存器 - TIM5->SR = 0U;//状态寄存器,清除所有中断标志位 - TIM5->PSC = PLSR_TIM5_PSC_100US;//8399,1Mhz - TIM5->ARR = 0xFFFFFFFFUL;//自动重装载寄存器 - TIM5->CNT = 0U;//计数值清零 - TIM5->EGR = TIM_EGR_UG;//事件产生寄存器,软件产生一次中断,不产生中断写的psc不会生效 - TIM5->SR = 0U;//EGR 的 UG 动作会把SR.UIF置 1,这里再次清零中断标志 + TIM5->CR1 = 0U; /* 停表:向上计、关 OPM */ + TIM5->DIER = 0U; /* 关 UPDATE 中断 */ + TIM5->SR = 0U; /* 清状态标志 */ + TIM5->PSC = PLSR_TIM5_PSC_100US; /* PSC=8399 → 10kHz(100µs/格),非 1MHz */ + TIM5->ARR = 0xFFFFFFFFUL; /* 预装最大 ARR,真正延时在 Schedule 重写 */ + TIM5->CNT = 0U; + TIM5->EGR = TIM_EGR_UG; /* UG:PSC 立刻生效(会置 UIF) */ + TIM5->SR = 0U; /* 清 UG 带来的 UIF */ HAL_NVIC_SetPriority(TIM5_IRQn, 7, 0); HAL_NVIC_EnableIRQ(TIM5_IRQn); } +/** @brief 信号 IO 初始化:消抖状态 + EXTI + TIM5 */ void PlsrSignalIoInit(void) { s_delay_armed = 0U; @@ -197,8 +198,7 @@ void PlsrSignalIoInit(void) PlsrSignalIoGpioExtiInit(); PlsrSignalIoTim5Init(); - //中断初始化时可能会进入中断,读取时需要结构体合法 - //为了防止初始化终端后意外触发,需要再次清除标志位 + /* 配完 NVIC 后再清一次,避免配置期误沿 */ __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN); __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN); s_debounce_x4.fell = 0U; @@ -207,6 +207,7 @@ void PlsrSignalIoInit(void) s_debounce_x5.pending = 0U; } +/** @brief 装 TIM5 单次延时(ms),OPM 到期进 OnTim5Irq */ void PlsrSignalIoScheduleDelayMs(uint32_t delay_ms) { uint32_t ticks; @@ -221,22 +222,23 @@ void PlsrSignalIoScheduleDelayMs(uint32_t delay_ms) } /* N ms → N×10 个 100µs 格;OPM 计满一次 UPDATE 即到期 */ - ticks = delay_ms * PLSR_TIM5_TICKS_PER_MS;//乘10得到us - - TIM5->CR1 = 0U;//控制寄存器 1 清零 - TIM5->DIER = 0U;//DMA / 中断使能寄存器清零 - TIM5->SR = 0U;//状态寄存器清零 - TIM5->PSC = PLSR_TIM5_PSC_100US;//8399得到10KHZ即100us - TIM5->ARR = ticks - 1U;//自动重装载寄存器 - TIM5->CR1 = TIM_CR1_URS;//仅更新事件产生更新中断 - TIM5->EGR = TIM_EGR_UG;//软件生成更新事件写 UG=1:立刻把CNT寄存器加载 ARR 影子寄存器的值;PSC 预分频值生效 - TIM5->SR = 0U;//再次清除状态寄存器,清除 UG 带来的各种标志。 - TIM5->CNT = 0U;//计数器清零,从 0 开始计数。 - TIM5->DIER = TIM_DIER_UIE;//使能更新中断。 + ticks = delay_ms * PLSR_TIM5_TICKS_PER_MS; + + TIM5->CR1 = 0U; + TIM5->DIER = 0U; + TIM5->SR = 0U; + TIM5->PSC = PLSR_TIM5_PSC_100US; + TIM5->ARR = ticks - 1U; + TIM5->CR1 = TIM_CR1_URS; /* 仅溢出产生 UPDATE */ + TIM5->EGR = TIM_EGR_UG; /* PSC/ARR 立刻生效 */ + TIM5->SR = 0U; /* 清 UG 带来的 UIF */ + TIM5->CNT = 0U; + TIM5->DIER = TIM_DIER_UIE; s_delay_armed = 1U; - TIM5->CR1 = (uint32_t)(TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS); + TIM5->CR1 = (uint32_t)(TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS); /* 开表单次 */ } +/** @brief 取消 TIM5 延时并清武装 */ void PlsrSignalIoCancelDelay(void) { TIM5->CR1 = 0U; @@ -245,6 +247,7 @@ void PlsrSignalIoCancelDelay(void) s_delay_armed = 0U; } +/** @brief 查询 TIM5 剩余延时 ms(未武装或已停返回 0) */ uint32_t PlsrSignalIoDelayRemainMs(void) { uint32_t arr; @@ -272,12 +275,14 @@ uint32_t PlsrSignalIoDelayRemainMs(void) return left_ticks / PLSR_TIM5_TICKS_PER_MS; } +/** @brief OS 节拍消抖:确认 X4/X5 有效下降沿 */ void PlsrSignalIoDebouncePoll(void) { PlsrSignalIoDebounceConfirm(&s_debounce_x4); PlsrSignalIoDebounceConfirm(&s_debounce_x5); } +/** @brief 丢弃两侧沿与 pending(EXT 段开跑前) */ void PlsrSignalIoClearEdges(void) { s_debounce_x4.fell = 0U; @@ -288,6 +293,7 @@ void PlsrSignalIoClearEdges(void) s_debounce_x5.stamp_ok = 0U; } +/** @brief 仅清 pending,保留已确认 fell(纯 EXT 段末) */ void PlsrSignalIoClearPending(void) { s_debounce_x4.pending = 0U; @@ -296,9 +302,10 @@ void PlsrSignalIoClearPending(void) s_debounce_x5.stamp_ok = 0U; } +/** @brief 取 WAIT 口有效下降沿(读后清) */ uint8_t PlsrSignalIoTakeWaitFalling(void) { - /* wait_x_sel:0 代表 X4,1 代表 X5。读取后立即清掉该下降沿。 */ + /* wait_x_sel:0=X4,1=X5 */ if (g_plsr_config.wait_x_sel == 0U) { if (s_debounce_x4.fell != 0U) @@ -315,9 +322,10 @@ uint8_t PlsrSignalIoTakeWaitFalling(void) return 0U; } +/** @brief 取 EXT 口有效下降沿(读后清) */ uint8_t PlsrSignalIoTakeExtFalling(void) { - /* ext_x_sel:0 代表 X4,1 代表 X5。读取后立即清掉该下降沿。 */ + /* ext_x_sel:0=X4,1=X5 */ if (g_plsr_config.ext_x_sel == 0U) { if (s_debounce_x4.fell != 0U) @@ -334,6 +342,7 @@ uint8_t PlsrSignalIoTakeExtFalling(void) return 0U; } +/** @brief TIM5 UPDATE:到期回调 run_control */ void PlsrSignalIoOnTim5Irq(void) { if ((TIM5->SR & TIM_SR_UIF) != 0U) @@ -344,11 +353,12 @@ void PlsrSignalIoOnTim5Irq(void) if (s_delay_armed != 0U) { s_delay_armed = 0U; - PlsrRunControlOnDelayTimer(); + PlsrRunControlOnDelayTimer(); /* 方向/WAIT/ACT 到期 */ } } } +/** @brief EXTI9_5:X4 下降沿 → pending */ void PlsrSignalIoOnExti9_5(void) { if (__HAL_GPIO_EXTI_GET_IT(PLSR_X4_PIN) != 0U) @@ -358,6 +368,7 @@ void PlsrSignalIoOnExti9_5(void) } } +/** @brief EXTI15_10:X5 下降沿 → pending */ void PlsrSignalIoOnExti15_10(void) { if (__HAL_GPIO_EXTI_GET_IT(PLSR_X5_PIN) != 0U)