diff --git a/.gitignore b/.gitignore index 242a603..4aef573 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ build-plsr_host-Desktop_Qt_5_6_3_MinGW_32bit-Debug/ plsr/test/ tools/ .cursor/ +PLSR测试大纲.html +_gen_outline_p1.py +run_control_full.txt \ No newline at end of file diff --git a/app/main.c b/app/main.c index f78592c..e481422 100644 --- a/app/main.c +++ b/app/main.c @@ -97,7 +97,7 @@ int main(void) OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR | OS_TASK_OPT_SAVE_FP); /* - * 参数块任务:Pend → ApplyFromHold → SaveParamsFromHold → ExportToHold。 + * 参数块任务:Pend → ApplyFromHold(校验)→ 通过则 SaveParamsFromHold。 * 分帧写完后由 OnHoldWrite Post;Save 落 BKP,Export 仅供读回钳位结果。 */ OSTaskCreateExt(PlsrParamBlockTask, @@ -118,7 +118,7 @@ int main(void) } /** - * @brief 系统时钟:HSE(12MHz) → PLL → 168MHz SYSCLK(APM32F407 / STM32F4 类) + * @brief 系统时钟:HSE(12MHz) → PLL → 168MHz SYSCLK * @note 须与 OS_CPU_SysTickInit、pulse_driver 使用的主频常量一致 * @note PLLM 须等于晶振 MHz:12MHz 用 12;误用 8 会使 SYSCLK=252MHz,脉冲频率偏 1.5 倍 */ diff --git a/modbus/modbus_rtu.c b/modbus/modbus_rtu.c index ca86275..18f9c9b 100644 --- a/modbus/modbus_rtu.c +++ b/modbus/modbus_rtu.c @@ -14,6 +14,7 @@ #include "gpio.h" #include "plsr_param.h" #include "plsr_command.h" +#include "plsr_persist.h" static uint8_t g_modbus_proc_buf[MODBUS_RX_BUF_LEN]; @@ -68,12 +69,11 @@ void ModbusSlaveTask(void *pArg) (void)pArg; /* - * ModbusDataInit 会 memset 整个 g_hold_reg,冲掉 PlsrInit 里 PersistLoad/Export 的结果。 - * 须立刻 Export:用已 Apply 的 s_cfg/s_seg 填回公共+段参数,供 FC03 读与后续 START。 - * (监控区另由 PlsrPersistTickMonitor 每节拍从运行态回填。) + * ModbusDataInit 会清零 g_hold_reg;上电后仅从 BKP 恢复参数/监控到 hold, + * 不再把运行结构体 Export 回寄存器(非法参数保留在上位机写入值 + 0x2006)。 */ ModbusDataInit(); - PlsrParamBlockExportToHold(); + PlsrPersistLoad(); ModbusPortInit(); while (1) diff --git a/plsr/command/plsr_command.c b/plsr/command/plsr_command.c index 2f1a462..291da61 100644 --- a/plsr/command/plsr_command.c +++ b/plsr/command/plsr_command.c @@ -79,6 +79,17 @@ uint16_t PlsrCommandGetFault(void) return s_fault; } +/** @brief 参数/重复启动类故障是否禁止 START(见 plsr_command.h) */ +uint8_t PlsrCommandIsStartBlocked(void) +{ + if ((s_fault >= PLSR_ERR_PARAM_BLOCK_MIN) && + (s_fault <= PLSR_ERR_PARAM_BLOCK_MAX)) + { + return 1U; + } + return 0U; +} + /** @brief 指令模块初始化(见 plsr_command.h) */ void PlsrCommandInit(void) { @@ -160,7 +171,7 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity) * 1. 读 ctrl 后立即写 0(避免重复触发) * 2. STOP — 急停 * 3. CLR — 清累计 + ClearFault - * 4. START — 仅当无 STOP 位:Apply → ClearFault → Stop → Start + * 4. START — 忙则 0x0C;否则 Apply 校验 → 0x04~0x0C 门禁则拒启 → Stop+Start * 动态改频在控制位之后、PublishMonitor 之前执行。 */ void PlsrCommandPoll(void) @@ -187,15 +198,27 @@ void PlsrCommandPoll(void) if (((ctrl & PLSR_CTRL_BIT_START) != 0U) && ((ctrl & PLSR_CTRL_BIT_STOP) == 0U)) { - (void)PlsrParamBlockApplyFromHold(); - /* 启动视为正常入口:先写故障码 0,再 Stop+Start;非法频率由 Start 改写为 4 */ - PlsrCommandClearFault(); - PlsrStop(); - (void)PlsrStart(PlsrParamGetStartSeg()); - /* 已进换向/WAIT 精确等待:本周期勿再 PublishMonitor,尽快 Pend */ - if (PlsrRunControlIsPreciseWait() != 0U) + if (PlsrIsBusy() != 0U) + { + /* 0x0C:运行中重复 START,启动无效 */ + PlsrCommandSetFault(PLSR_ERR_DUP_START); + } + else if (PlsrParamBlockApplyFromHold() == 0U) + { + /* Apply 失败:故障码已由参数块写入 0x2006,不落 BKP */ + } + else if (PlsrCommandIsStartBlocked() != 0U) + { + /* 0x04~0x0B 等门禁故障:禁止启动 */ + } + else { - skip_monitor = 1U; + PlsrStop(); + (void)PlsrStart(PlsrParamGetStartSeg()); + if (PlsrRunControlIsPreciseWait() != 0U) + { + skip_monitor = 1U; + } } } } diff --git a/plsr/command/plsr_command.h b/plsr/command/plsr_command.h index 9d0183e..12f35f6 100644 --- a/plsr/command/plsr_command.h +++ b/plsr/command/plsr_command.h @@ -51,13 +51,34 @@ * 1 | PLSR_ERR_PULSE_CNT | 实际脉冲数与段目标不一致 | 告警 | 继续跑,不中断 * 2 | PLSR_ERR_FREQ_UNREACH | 规划峰值达不到设定目标(三角) | 告警 | 按压后规划继续 * 3 | PLSR_ERR_CURVE_MISMATCH | 加减速相内脉冲与规划预算不符 | 告警 | 继续跑 - * 4 | PLSR_ERR_FREQ_ILLEGAL | 频率 ∉ [1, 100000] Hz | 门禁 | 禁止启动/改频 + * 4 | PLSR_ERR_FREQ_ILLEGAL | 段频率 ∉ [1, 100000] Hz(非 0) | 门禁 | 禁止启动/改频 + * 5 | PLSR_ERR_PULSE_RANGE | 脉冲个数 ∉ int32 合法范围 | 门禁 | 禁止启动 + * 6 | PLSR_ERR_SEG_COUNT | 总段数 ∉ [1, 10] | 门禁 | 禁止启动 + * 7 | PLSR_ERR_START_SEG | 起始段 ∉ [1, 总段数] | 门禁 | 禁止启动 + * 8 | PLSR_ERR_START_END_SPD | 起/止速非0且 ∉ [1, 100000] Hz | 门禁 | 禁止启动(0=合法) + * 9 | PLSR_ERR_PULSE_Y | 脉冲端子 ∉ {Y0,Y1,Y2} | 门禁 | 禁止启动 + * 10 | PLSR_ERR_DIR_Y | 方向端子 ≠ Y3 | 门禁 | 禁止启动 + * 11 | PLSR_ERR_DEFAULT_SPD | 默认速度 ∉ [1, 100000] Hz | 门禁 | 禁止启动 + * 12 | PLSR_ERR_DUP_START | 运行中重复 START | 告警 | 启动无效 */ #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 +#define PLSR_ERR_PULSE_RANGE 0x05U +#define PLSR_ERR_SEG_COUNT 0x06U +#define PLSR_ERR_START_SEG 0x07U +#define PLSR_ERR_START_END_SPD 0x08U +#define PLSR_ERR_PULSE_Y 0x09U +#define PLSR_ERR_DIR_Y 0x0AU +#define PLSR_ERR_DEFAULT_SPD 0x0BU +#define PLSR_ERR_DUP_START 0x0CU + +/** 参数类门禁故障码下限(含) */ +#define PLSR_ERR_PARAM_BLOCK_MIN PLSR_ERR_FREQ_ILLEGAL +/** 参数类门禁故障码上限(含 0x0C 重复启动) */ +#define PLSR_ERR_PARAM_BLOCK_MAX PLSR_ERR_DUP_START /** * @brief 指令模块初始化 @@ -90,6 +111,12 @@ void PlsrCommandClearFault(void); /** @return 当前故障码镜像(与 0x2006 一致) */ uint16_t PlsrCommandGetFault(void); +/** + * @brief 是否因参数/重复启动类故障禁止 START + * @return 1=0x2006 为 0x04~0x0C(门禁/重复启动);0=可尝试启动 + */ +uint8_t PlsrCommandIsStartBlocked(void); + /** * @brief FC10 写段频率双字后的钩子 * @param start_addr 写入起始保持寄存器地址 diff --git a/plsr/param/plsr_param.c b/plsr/param/plsr_param.c index e00cae6..3ee12dc 100644 --- a/plsr/param/plsr_param.c +++ b/plsr/param/plsr_param.c @@ -15,11 +15,12 @@ * * 与其它模块关系 * Modbus FC10 应答路径调用 OnHoldWrite;Command START 也会同步 ApplyFromHold; - * Persist:Apply 成功后 SaveParamsFromHold 整包落 BKP;运行中改频单独落频率双字; - * ExportToHold 只把钳位后的结构体摊回 hold(读回 / 抗 ModbusDataInit 清零),不负责写 BKP。 + * Persist:校验全部通过才 SaveParamsFromHold;失败只写故障码,不落 BKP; + * 非上电不再 ExportToHold(hold 保留上位机写入值,由故障码提示修正)。 */ #include "plsr_param.h" #include "plsr_persist.h" +#include "plsr_command.h" #include "modbus_rtu.h" #include "ucos_ii.h" #include @@ -194,37 +195,95 @@ static void PlsrParamSetXferStatus(uint16_t st, uint16_t fail_frame) WriteHoldReg(PLSR_PARAM_XFER_RECV_REG, s_recv_frames); } +/*============================================================================*/ +/* 参数校验辅助 */ +/*============================================================================*/ + +#define PLSR_PARAM_SPD_MIN_HZ 1U +#define PLSR_PARAM_SPD_MAX_HZ 100000U + +/** 记录「最后一个」故障码(校验顺序决定多错时保留末项) */ +static void PlsrParamFaultLast(uint16_t *fault, uint16_t code) +{ + *fault = code; +} + +static uint8_t PlsrParamIsSpeedHzValid(uint32_t hz) +{ + return ((hz >= PLSR_PARAM_SPD_MIN_HZ) && (hz <= PLSR_PARAM_SPD_MAX_HZ)) ? 1U : 0U; +} + +/** + * 起速/止速:0 合法(运行层 ResolveStartHz / ResolveEndHz 处理); + * 非 0 须在 1~100kHz。 + */ +static uint8_t PlsrParamIsStartEndSpeedValid(uint32_t hz) +{ + if (hz == 0U) + { + return 1U; + } + return PlsrParamIsSpeedHzValid(hz); +} + +/** 段频率:0=用默认速度;非 0 须在 1~100kHz */ +static uint8_t PlsrParamIsSegFreqValid(int32_t freq_hz) +{ + if (freq_hz == 0) + { + return 1U; + } + if (freq_hz < 0) + { + return 0U; + } + return PlsrParamIsSpeedHzValid((uint32_t)freq_hz); +} + +/** 脉冲个数 SDW:须在 int32 有符号范围内 */ +static uint8_t PlsrParamIsPulseCntValid(int32_t pulse_cnt) +{ + if (pulse_cnt < (int32_t)(-2147483647L - 1L)) + { + return 0U; + } + if (pulse_cnt > (int32_t)2147483647L) + { + return 0U; + } + return 1U; +} + /*============================================================================*/ /* 分帧导入 / 导出 */ /*============================================================================*/ /** - * @brief 保持寄存器 → 运行映像(见 plsr_param.h) + * @brief 保持寄存器 → 运行映像,边拷贝边校验(见 plsr_param.h) * - * 字段裁剪策略(当前不做故障码,仅钳制到合法枚举/范围): - * pulse_y>2 → 0;dir 强制 3;accel_mode>2 → LINEAR;seg_count 上限 10; - * start_seg 钳到 [1,n];wait_type>4 → TIME。 - * 频率合法性由 run_control 启动/开段时查 0x04,此处不拒绝写入。 + * @details 校验失败时仍完成拷贝(保留上位机原始值),故障码写入 0x2006; + * 多项非法时仅保留校验过程中「最后一个」故障码。 + * @return 1=全部通过;0=存在门禁故障(不落 BKP) */ uint8_t PlsrParamBlockApplyFromHold(void) { uint16_t i; uint16_t n; uint16_t base; - uint16_t m; + uint16_t fault = PLSR_ERR_NONE; PlsrSeg_t *seg; - /* - * 从保持寄存器组装运行映像。 - * TODO:段数/频率/脉冲/端子冲突/跳转非法 → 故障码(当前仅裁剪) - */ s_cfg.pulse_y = ReadHoldReg(PLSR_REG_PULSE_Y); if (s_cfg.pulse_y > 2U) { - s_cfg.pulse_y = 0U; + PlsrParamFaultLast(&fault, PLSR_ERR_PULSE_Y); + } + + s_cfg.dir_y = ReadHoldReg(PLSR_REG_DIR_Y); + if (s_cfg.dir_y != 3U) + { + PlsrParamFaultLast(&fault, PLSR_ERR_DIR_Y); } - s_cfg.dir_y = 3U; /* 方向固定 Y3,忽略上位机其它值 */ - WriteHoldReg(PLSR_REG_DIR_Y, 3U); s_cfg.wait_x_sel = ReadHoldReg(PLSR_REG_WAIT_X) ? 1U : 0U; s_cfg.ext_x_sel = ReadHoldReg(PLSR_REG_EXT_X) ? 1U : 0U; @@ -232,59 +291,83 @@ uint8_t PlsrParamBlockApplyFromHold(void) s_cfg.dir_delay_ms = ReadHoldReg(PLSR_REG_DIR_DELAY); s_cfg.dir_logic = (ReadHoldReg(PLSR_REG_DIR_LOGIC) != 0U) ? PLSR_DIR_LOGIC_NEG : PLSR_DIR_LOGIC_POS; - - m = ReadHoldReg(PLSR_REG_ACCEL_MODE); - if (m > (uint16_t)PLSR_ACCEL_SINE) - { - m = (uint16_t)PLSR_ACCEL_LINEAR; - } - s_cfg.accel_mode = (PlsrAccelMode_e)m; + s_cfg.accel_mode = (PlsrAccelMode_e)ReadHoldReg(PLSR_REG_ACCEL_MODE); s_cfg.run_mode = (ReadHoldReg(PLSR_REG_RUN_MODE) != 0U) ? PLSR_POS_ABSOLUTE : PLSR_POS_RELATIVE; n = ReadHoldReg(PLSR_REG_SEG_COUNT); - if (n > PLSR_SEG_MAX) + s_cfg.seg_count = n; + if ((n < 1U) || (n > PLSR_SEG_MAX)) { - n = (uint16_t)PLSR_SEG_MAX; + PlsrParamFaultLast(&fault, PLSR_ERR_SEG_COUNT); } - s_cfg.seg_count = n; s_cfg.start_seg = ReadHoldReg(PLSR_REG_START_SEG); - if (s_cfg.start_seg < 1U) + if ((n >= 1U) && (n <= PLSR_SEG_MAX)) { - s_cfg.start_seg = 1U; + if ((s_cfg.start_seg < 1U) || (s_cfg.start_seg > n)) + { + PlsrParamFaultLast(&fault, PLSR_ERR_START_SEG); + } } - if ((n >= 1U) && (s_cfg.start_seg > n)) + else if (s_cfg.start_seg < 1U) { - s_cfg.start_seg = n; + PlsrParamFaultLast(&fault, PLSR_ERR_START_SEG); } s_cfg.default_speed = PlsrParamReadDWord(PLSR_REG_DEFAULT_SPD_L); + if (PlsrParamIsSpeedHzValid(s_cfg.default_speed) == 0U) + { + PlsrParamFaultLast(&fault, PLSR_ERR_DEFAULT_SPD); + } + s_cfg.start_speed = PlsrParamReadDWord(PLSR_REG_START_SPD_L); + if (PlsrParamIsStartEndSpeedValid(s_cfg.start_speed) == 0U) + { + PlsrParamFaultLast(&fault, PLSR_ERR_START_END_SPD); + } + s_cfg.end_speed = PlsrParamReadDWord(PLSR_REG_END_SPD_L); + if (PlsrParamIsStartEndSpeedValid(s_cfg.end_speed) == 0U) + { + PlsrParamFaultLast(&fault, PLSR_ERR_START_END_SPD); + } + s_cfg.accel_ms = ReadHoldReg(PLSR_REG_ACCEL_MS); s_cfg.decel_ms = ReadHoldReg(PLSR_REG_DECEL_MS); - for (i = 0U; i < n; i++) + if ((n >= 1U) && (n <= PLSR_SEG_MAX)) { - seg = &s_seg[i]; - base = (uint16_t)(PLSR_REG_SEG1_BASE + i * PLSR_SEG_STRIDE); - seg->freq_hz = PlsrParamReadSignedDWord((uint16_t)(base + PLSR_SEG_OFF_FREQ_L)); - seg->pulse_cnt = PlsrParamReadSignedDWord((uint16_t)(base + PLSR_SEG_OFF_PULSE_L)); + for (i = 0U; i < n; i++) { - uint16_t w = ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT)); - if (w > 4U) + seg = &s_seg[i]; + base = (uint16_t)(PLSR_REG_SEG1_BASE + i * PLSR_SEG_STRIDE); + seg->freq_hz = PlsrParamReadSignedDWord((uint16_t)(base + PLSR_SEG_OFF_FREQ_L)); + if (PlsrParamIsSegFreqValid(seg->freq_hz) == 0U) { - w = 0U; + PlsrParamFaultLast(&fault, PLSR_ERR_FREQ_ILLEGAL); } - seg->wait_type = (PlsrWaitType_e)w; + + seg->pulse_cnt = PlsrParamReadSignedDWord((uint16_t)(base + PLSR_SEG_OFF_PULSE_L)); + if (PlsrParamIsPulseCntValid(seg->pulse_cnt) == 0U) + { + PlsrParamFaultLast(&fault, PLSR_ERR_PULSE_RANGE); + } + + seg->wait_type = (PlsrWaitType_e)ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT)); + seg->wait_ms = ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT_MS)); + seg->act_ms = ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_ACT_MS)); + seg->jump_seg = ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_JUMP)); } - seg->wait_ms = ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT_MS)); - seg->act_ms = ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_ACT_MS)); - seg->jump_seg = ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_JUMP)); } - return 1U; + PlsrCommandSetFault(fault); + + if (fault == PLSR_ERR_NONE) + { + return 1U; + } + return 0U; } /** @@ -412,10 +495,8 @@ void PlsrParamBlockInit(void) /** * @brief 参数块任务(见 plsr_param.h) * - * for(;;) 为 uC/OS 任务标准死循环: - * OSSemPend → ApplyFromHold → SaveParamsFromHold → ExportToHold - * Save 用 hold 中上位机刚写入的值落 BKP;Export 仅把钳位结果摊回 hold 供读回。 - * Apply 失败则写 XFER_FAIL 与当前 recv 帧号。 + * for(;;):OSSemPend → ApplyFromHold(校验+写 0x2006)→ 通过则 SaveParamsFromHold。 + * 校验失败:不落 BKP,hold 保留上位机原值,由故障码提示修正。 */ void PlsrParamBlockTask(void *pArg) { @@ -434,8 +515,7 @@ void PlsrParamBlockTask(void *pArg) if (PlsrParamBlockApplyFromHold() != 0U) { PlsrParamSetXferStatus(PLSR_PARAM_XFER_OK, 0U); - PlsrPersistSaveParamsFromHold(); /* hold 原值 → BKP(不依赖 Export) */ - PlsrParamBlockExportToHold(); /* 钳位后映像 → hold,供 Modbus 读回 */ + PlsrPersistSaveParamsFromHold(); /* 仅全部校验通过才落 BKP */ } else { diff --git a/plsr/param/plsr_param.h b/plsr/param/plsr_param.h index 646312b..e42f443 100644 --- a/plsr/param/plsr_param.h +++ b/plsr/param/plsr_param.h @@ -6,7 +6,7 @@ * 1. 定义公共参数区 0x1000~0x1013、段表区 0x1100+i*0x10 的地址与字段语义; * 2. 维护运行侧唯一映像 s_cfg / s_seg[](运动规划只读此映像,不直接啃寄存器); * 3. 支持上位机「1 公共帧 + N 段帧」分帧 FC10 写入:收齐后 ApplyFromHold; - * 4. 支持 ExportToHold:上电默认或读回时把映像摊到保持寄存器。 + * 4. 上电由 PersistLoad 填 hold;ExportToHold 仅保留作调试接口。 * * 与其它模块关系 * - modbus_rtu / modbus_data :ReadHoldReg / WriteHoldReg @@ -18,9 +18,8 @@ * 关键数据流 * 上位机写公共帧@0x1000 → OnHoldWrite 开传输 expect=1+N * 上位机写段帧@0x1100+ → recv++;收齐 → OSSemPost - * ParamBlockTask → ApplyFromHold → SaveParamsFromHold → ExportToHold → 状态 OK - * 上电:PersistLoad → ApplyFromHold → … ModbusDataInit 清 hold … - * → ExportToHold(填回参数)+ TickMonitor(填回监控) + * ParamBlockTask → ApplyFromHold(校验)→ 通过则 SaveParamsFromHold → 状态 OK/FAIL + * 上电:PersistLoad(BKP→hold) → ApplyFromHold(hold→结构体) * * 协议概要 * - 公共帧:0x1000~0x1013(20 字),0x1009=段数 N,预期总帧=1+N @@ -195,7 +194,8 @@ uint16_t PlsrParamGetStartSeg(void); void PlsrParamBlockInit(void); /** - * @brief 参数块任务:阻塞等信号量 → ApplyFromHold → SaveParamsFromHold → ExportToHold +/** + * @brief 参数块任务:阻塞等信号量 → ApplyFromHold(校验)→ 通过则 SaveParamsFromHold * @param pArg 未使用 * @note for(;;) 死循环为 RTOS 任务常态;空循环体是错觉(花括号内有 Pend/Apply) */ @@ -210,19 +210,14 @@ void PlsrParamBlockTask(void *pArg); void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity); /** - * @brief 保持寄存器 → s_cfg / s_seg - * @return 1=成功(当前恒为 1;完整校验/故障码待扩展) - * @note 成功后由 ParamBlockTask 调用 SaveParamsFromHold 整包落 BKP + * @brief 保持寄存器 → s_cfg / s_seg,边拷贝边校验 + * @return 1=全部通过(写 0x2006=0);0=存在门禁故障(写对应码,不落 BKP) */ uint8_t PlsrParamBlockApplyFromHold(void); /** - * @brief s_cfg / s_seg → 保持寄存器(供 FC03 读回 / START 前 hold 有效) - * @note 调用时机: - * - ParamBlockTask:Apply+Save 之后,把钳位结果摊回 hold - * - ModbusDataInit 清 hold 之后立刻 Export - * - PlsrTask 首次延时后再 Export(双保险) - * @note 本函数不写 BKP;落盘用 SaveParamsFromHold + * @brief s_cfg / s_seg → 保持寄存器(调试/特殊用途;正常运行路径不再调用) + * @note 上电参数由 BKP→hold(PersistLoad);非法参数保留 hold 原值供上位机读回修正 */ void PlsrParamBlockExportToHold(void); diff --git a/plsr/plsr.c b/plsr/plsr.c index f4e5670..bf6cc5e 100644 --- a/plsr/plsr.c +++ b/plsr/plsr.c @@ -10,10 +10,8 @@ * 本文件仅依赖 plsr.h 及各子模块头文件,不被其它 plsr 模块反向引用。 * * 关键数据流 - * PlsrInit 顺序:PersistLoad(BKP→hold) → ApplyFromHold → - * PulseDriver → RunControl → RestoreRuntime → ExportToHold → - * CommandInit → RestoreMonitor → TickMonitor - * (随后 ModbusDataInit 可能清 hold,须再 Export + TickMonitor) + * PlsrInit 顺序:PersistLoad(BKP→hold) → ApplyFromHold(hold→结构体) → … + * ModbusDataInit 清 hold 后:再次 PersistLoad(BKP→hold),不再 ExportToHold * PlsrTask 循环:TickMs → DebouncePoll → CommandPoll → TickMonitor → WakePend */ #include "plsr.h" @@ -29,20 +27,18 @@ * @brief 子系统初始化(见 plsr.h) * * 顺序要点 - * PersistLoad → Apply:BKP 进结构体; - * Export:先填 hold(随后 ModbusDataInit 仍可能清零,故任务里再 Export); - * RestoreRuntime / TickMonitor:累计脉冲进运行态并与 BKP 对齐。 + * PersistLoad → Apply:BKP → hold → 结构体(BKP 内参数应已合法); + * 非上电不再把结构体 Export 回 hold;Modbus 清零后由 BKP 再填 hold。 */ void PlsrInit(void) { //PlsrParamInitDefault(); - PlsrPersistLoad(); /* BKPSRAM 稀疏映像 → g_hold_reg */ - (void)PlsrParamBlockApplyFromHold(); /* hold → s_cfg / s_seg[] */ + PlsrPersistLoad(); /* BKPSRAM → g_hold_reg */ + (void)PlsrParamBlockApplyFromHold(); /* hold → s_cfg / s_seg[] + 校验 */ PlsrPulseDriverInit(); PlsrSignalIoInit(); PlsrRunControlInit(); - PlsrPersistRestoreRuntime(); /* hold 0x2000 累计 → run_control(须在 DataInit 清 hold 前) */ - PlsrParamBlockExportToHold(); /* 结构体 → hold;Modbus 清零后须再 Export */ + PlsrPersistRestoreRuntime(); /* hold 0x2000 累计 → run_control */ PlsrCommandInit(); PlsrPersistRestoreMonitor(); /* 恢复故障码;0x3000/运行态强制空闲 */ PlsrPersistTickMonitor(); /* 监控区 hold+BKP 与运行态对齐 */ @@ -116,18 +112,15 @@ void PlsrTask(void *pArg) while(1) { /* - * 首次进入:ModbusSlaveTask 启动时 ModbusDataInit 会 memset(g_hold_reg)。 - * 延迟让出 CPU 后再次 Export:把已从 BKP Apply 的运行映像摊回 hold, - * 否则读 PLC 公共/段为 0,START 的 ApplyFromHold 也会用空 hold 覆盖结构体。 - * TickMonitor:清 hold 后立刻把累计等监控量刷回 hold+BKP。 + * 首次进入:ModbusSlaveTask 已 DataInit 清 hold 并 PersistLoad 填回 BKP 参数。 + * 此处仅恢复监控/指令侧,不再 Export 结构体到 hold。 */ if (s_booted == 0U) { - OSTimeDly(3U); /* ~30ms @ 100Hz tick;让出 CPU 给 Modbus 完成 DataInit */ - PlsrParamBlockExportToHold(); /* 参数区 hold ← s_cfg/s_seg */ + OSTimeDly(3U); /* ~30ms @ 100Hz tick;让出 CPU 给 Modbus 完成初始化 */ PlsrCommandInit(); PlsrPersistRestoreMonitor(); - PlsrPersistTickMonitor(); /* 监控区 hold+BKP ← 运行态 */ + PlsrPersistTickMonitor(); s_booted = 1U; } diff --git a/plsr/plsr.h b/plsr/plsr.h index 02649b2..c37208b 100644 --- a/plsr/plsr.h +++ b/plsr/plsr.h @@ -16,13 +16,9 @@ * - plsr_signal_io :WAIT/EXT 外部输入、TIM5 延时 * * 关键数据流 - * 上电:PlsrInit → PersistLoad(BKP→hold) → ApplyFromHold → 驱动/IO/RunControl - * → RestoreRuntime → ExportToHold → CommandInit → RestoreMonitor → TickMonitor - * →(ModbusDataInit 清 hold 后再次 Export + TickMonitor) - * 周期:PlsrTask → TickMs → Debounce → CommandPoll → TickMonitor → WakePend - * 脉冲:TIM UPDATE 中断 → PlsrOnPulseIsr → RunControl 计数 + 逐拍改频 - * 启动:PlsrStart → RunControlStart → 段序/方向 + 曲线规划 + PWM 输出 - * 写参:分帧收齐 → ParamBlockTask Apply → SaveParamsFromHold → ExportToHold + * 上电:PlsrInit → PersistLoad(BKP→hold) → ApplyFromHold → … + * →(ModbusDataInit 后再次 PersistLoad 填 hold) + * 写参:分帧收齐 → ParamBlockTask Apply(校验)→ 通过则 SaveParamsFromHold */ #ifndef PLSR_H #define PLSR_H