From cda1eac2af3bba7789a60381680526b4ba19e9c9 Mon Sep 17 00:00:00 2001
From: hanyongwei <2043702190@qq.com>
Date: Thu, 20 Aug 2026 17:36:01 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=95=85=E9=9A=9C=E8=AF=8A?=
=?UTF-8?q?=E6=96=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
iar/plsr.dep | 4 -
plsr/command/plsr_command.c | 1 +
plsr/command/plsr_command.h | 7 +-
plsr/run_control/plsr_run_control.c | 131 ++++++++++++++++++++++++----
4 files changed, 121 insertions(+), 22 deletions(-)
diff --git a/iar/plsr.dep b/iar/plsr.dep
index 3f68f93..f3b7632 100644
--- a/iar/plsr.dep
+++ b/iar/plsr.dep
@@ -3092,10 +3092,6 @@
BICOMP
283
-
- ICCARM
- 33
-
__cstat
268
diff --git a/plsr/command/plsr_command.c b/plsr/command/plsr_command.c
index bb0b118..d5bc00b 100644
--- a/plsr/command/plsr_command.c
+++ b/plsr/command/plsr_command.c
@@ -99,6 +99,7 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity)
((uint32_t)ReadHoldReg((uint16_t)(start_addr + 1U)) << 16);
if ((f < 1U) || (f > 100000U))
{
+ PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL);
return;
}
diff --git a/plsr/command/plsr_command.h b/plsr/command/plsr_command.h
index 958b3f8..37cfdb0 100644
--- a/plsr/command/plsr_command.h
+++ b/plsr/command/plsr_command.h
@@ -25,8 +25,11 @@
#define PLSR_CTRL_BIT_STOP (1U << 1) /* 停止脉冲 */
#define PLSR_CTRL_BIT_CLR (1U << 2) /* 清除状态信息 */
-#define PLSR_ERR_NONE 0U
-#define PLSR_ERR_SEG_FREQ 1U /* 段频率非法(非 0 且越界,或解析后不在 1~100k) */
+#define PLSR_ERR_NONE 0x00U /* 无故障 */
+#define PLSR_ERR_PULSE_CNT 0x01U /* 脉冲输出个数与设置不一致(告警,继续) */
+#define PLSR_ERR_FREQ_UNREACH 0x02U /* 输出频率与设置不一致/三角达不到(告警,继续) */
+#define PLSR_ERR_CURVE_MISMATCH 0x03U /* 加减速曲线与设置不一致(告警,继续) */
+#define PLSR_ERR_FREQ_ILLEGAL 0x04U /* 脉冲频率非法(1~100k)(告警,禁止启动) */
void PlsrCommandInit(void);
void PlsrCommandPoll(void);
diff --git a/plsr/run_control/plsr_run_control.c b/plsr/run_control/plsr_run_control.c
index 34c026e..2991a99 100644
--- a/plsr/run_control/plsr_run_control.c
+++ b/plsr/run_control/plsr_run_control.c
@@ -77,6 +77,11 @@ static uint8_t s_pwm_on;
static uint16_t s_run_accel_ms;
static uint16_t s_run_decel_ms;
+/* 规划锁定的加/减速脉冲预算(EnterDecel 会改写 plan.dec_n,故另存) */
+static uint32_t s_plan_acc_n;
+static uint32_t s_plan_dec_n;
+static uint32_t s_decel_budget; /* 进入减速时的 remain,用于 0x03 */
+
/** 策略层交给段处理的接口参数 */
typedef struct {
uint32_t f_from;
@@ -102,6 +107,10 @@ static uint16_t PlsrRunControlWaitTimeMs(const PlsrSeg_t *seg);
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);
+static void PlsrRunControlCheckPulseCntFault(void);
+static void PlsrRunControlCheckApproachCurveFault(uint8_t by_pulse_budget);
+static void PlsrRunControlOnApproachDone(void);
+static void PlsrRunControlCheckDecelCurveFault(void);
static int32_t PlsrRunControlAbsLocalPos(void);
static uint32_t PlsrRunControlClampSpeed(uint32_t spd);
static uint8_t PlsrRunControlGetSegTargetFreq(int32_t freq_hz,
@@ -320,12 +329,57 @@ static void PlsrRunControlGotoNextOrFinish(uint16_t cur_seg)
}
}
+/** 0x01:段正常结束时实际脉冲 ≠ 本段目标(告警,不停) */
+static void PlsrRunControlCheckPulseCntFault(void)
+{
+ if ((s_target > 0) && (s_done != s_target))
+ {
+ PlsrCommandSetFault(PLSR_ERR_PULSE_CNT);
+ }
+}
+
+/**
+ * 0x03:加速段结束时,相内脉冲与规划 acc_n 不一致。
+ * by_pulse_budget:因 n 走到预算而收尾,须精确相等;因频率提前到位则仅超额时报。
+ */
+static void PlsrRunControlCheckApproachCurveFault(uint8_t by_pulse_budget)
+{
+ if (s_plan_acc_n == 0U)
+ {
+ return;
+ }
+ if (by_pulse_budget != 0U)
+ {
+ if (s_pulse_rt.n != s_plan_acc_n)
+ {
+ PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH);
+ }
+ }
+ else if (s_pulse_rt.n > s_plan_acc_n)
+ {
+ PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH);
+ }
+}
+
+/** 0x03:减速段在段末核对相内脉冲与进入减速时的预算 */
+static void PlsrRunControlCheckDecelCurveFault(void)
+{
+ if ((s_phase == PH_DECEL) && (s_decel_budget > 0U) &&
+ (s_pulse_rt.n != s_decel_budget))
+ {
+ PlsrCommandSetFault(PLSR_ERR_CURVE_MISMATCH);
+ }
+}
+
static void PlsrRunControlAfterSegDone(void)
{
PlsrCfg_t *cfg = PlsrParamGetCfg();
PlsrSeg_t *seg = PlsrParamGetSeg(s_cur_seg);
uint8_t keep_pwm;
+ PlsrRunControlCheckPulseCntFault();
+ PlsrRunControlCheckDecelCurveFault();
+
/* 先脱离 RUN,避免脉冲 ISR 重入 */
s_state = RC_IDLE;
@@ -421,7 +475,7 @@ static uint8_t PlsrRunControlBlocksFollowKeep(uint16_t cur_seg)
* 调用/等待策略:根据发送模式、等待条件、衔接状态,解析本段
* f_from / f_end / accel_ms / decel_ms。段内处理不读 wait_type。
*
- * @return 1 成功;0 下一段目标频非法(仅后续无缝衔接时)
+ * @return 1 成功
*/
static uint8_t PlsrRunControlResolveSegCallIo(uint16_t seg_0, uint32_t f_tgt,
PlsrSegCallIo_t *io)
@@ -498,7 +552,14 @@ static uint8_t PlsrRunControlResolveSegCallIo(uint16_t seg_0, uint32_t f_tgt,
cfg->default_speed,
&io->f_end) == 0U)
{
- return 0U;
+ /* 下一段频率非法:本段先止速收尾,下一段 Begin 再报 0x04 */
+ io->f_end = PlsrAccelCurveResolveEndHz(cfg->end_speed,
+ f_tgt,
+ cfg->default_speed,
+ cfg->start_speed,
+ cfg->end_speed,
+ io->accel_ms,
+ io->decel_ms);
}
}
return 1U;
@@ -686,6 +747,7 @@ static void PlsrRunControlEnterDecel(uint32_t from_hz, uint32_t remain_pulses)
{
PlsrRunControlEnterPhase(PH_DECEL, from_hz);
+ s_decel_budget = remain_pulses;
s_accel_plan.acc_n = 0U;
s_accel_plan.const_n = 0U;
s_accel_plan.dec_n = remain_pulses;
@@ -712,6 +774,19 @@ static void PlsrRunControlEnterDecel(uint32_t from_hz, uint32_t remain_pulses)
}
}
+/** 离开加速相时做 0x03 诊断 */
+static void PlsrRunControlOnApproachDone(void)
+{
+ uint8_t by_budget;
+
+ if (s_phase != PH_APPROACH)
+ {
+ return;
+ }
+ by_budget = ((s_plan_acc_n > 0U) && (s_pulse_rt.n >= s_plan_acc_n)) ? 1U : 0U;
+ PlsrRunControlCheckApproachCurveFault(by_budget);
+}
+
/**
* 进匀速:写一次 f_tgt,之后 ISR 不改 ARR(复用缓存)。
*/
@@ -789,6 +864,7 @@ static void PlsrRunControlRefreshProfile(uint8_t do_start)
(next <= s_accel_plan.f_tgt)))
{
next = s_accel_plan.f_tgt;
+ PlsrRunControlOnApproachDone();
if ((PlsrRunControlHasDecel() != 0U) &&
(remain <= s_accel_plan.dec_n))
{
@@ -837,6 +913,24 @@ static void PlsrRunControlPlanSeg(uint32_t total, uint32_t f_from,
decel_ms,
cfg->accel_mode);
+ /*
+ * 0x02:规划后峰值低于设定目标 → 脉冲不够爬到目标频(三角等)
+ * 告警,仍按当前规划继续跑。
+ */
+ if ((f_tgt > f_from) && (s_accel_plan.f_tgt < f_tgt))
+ {
+ PlsrCommandSetFault(PLSR_ERR_FREQ_UNREACH);
+ }
+ else if ((f_tgt < f_from) && (s_accel_plan.f_tgt > f_tgt))
+ {
+ PlsrCommandSetFault(PLSR_ERR_FREQ_UNREACH);
+ }
+
+ /* 0x03 对照用:规划预算(运行中 s_accel_plan.acc_n 可能被改写) */
+ s_plan_acc_n = s_accel_plan.acc_n;
+ s_plan_dec_n = s_accel_plan.dec_n;
+ s_decel_budget = 0U;
+
/* 运行层使用规划后的实际起始频率。 */
f_start = s_accel_plan.f_cur;
@@ -1003,24 +1097,14 @@ static void PlsrRunControlBeginSeg(uint16_t seg_0)
if (PlsrRunControlGetSegTargetFreq(seg->freq_hz, cfg->default_speed, &f_tgt) == 0U)
{
- PlsrCommandSetFault(PLSR_ERR_SEG_FREQ);
- s_busy = 1U;
- s_target = 0;
- s_done = 0;
- PlsrRunControlAfterSegDone();
+ /* 0x04:频率非法,禁止启动/切段 */
+ PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL);
+ PlsrRunControlFinishAll();
return;
}
/* 策略层解析起/止速与加减速;段内只跑 PlanSeg */
- if (PlsrRunControlResolveSegCallIo(seg_0, f_tgt, &io) == 0U)
- {
- PlsrCommandSetFault(PLSR_ERR_SEG_FREQ);
- s_busy = 1U;
- s_target = 0;
- s_done = 0;
- PlsrRunControlAfterSegDone();
- return;
- }
+ (void)PlsrRunControlResolveSegCallIo(seg_0, f_tgt, &io);
total = (uint32_t)s_target;
PlsrRunControlPlanSeg(total, io.f_from, f_tgt, io.f_end,
@@ -1102,6 +1186,19 @@ uint8_t PlsrRunControlStart(uint16_t start_seg_1based)
}
cfg = PlsrParamGetCfg();
+ {
+ PlsrSeg_t *seg = PlsrParamGetSeg((uint16_t)(start_seg_1based - 1U));
+ uint32_t f_chk;
+
+ /* 启动前校验首段频率;非法则写 0x04 且不进入运行 */
+ if (PlsrRunControlGetSegTargetFreq(seg->freq_hz,
+ cfg->default_speed,
+ &f_chk) == 0U)
+ {
+ PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL);
+ return 0U;
+ }
+ }
s_follow_cont = 0U;
s_chain_valid = 0U;
s_chain_freq = 0U;
@@ -1145,6 +1242,7 @@ uint8_t PlsrRunControlChangeFreq(uint32_t new_tgt_hz)
}
if ((new_tgt_hz < 1U) || (new_tgt_hz > 100000U))
{
+ PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL);
return 0U;
}
if (s_done >= s_target)
@@ -1342,6 +1440,7 @@ void PlsrRunControlOnPulseIsr(void)
(next <= s_accel_plan.f_tgt)))
{
next = s_accel_plan.f_tgt;
+ PlsrRunControlOnApproachDone();
if ((PlsrRunControlHasDecel() != 0U) &&
(remain <= s_accel_plan.dec_n))
{