| @@ -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 | |||
| @@ -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 倍 | |||
| */ | |||
| @@ -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) | |||
| @@ -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; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -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 写入起始保持寄存器地址 | |||
| @@ -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 <string.h> | |||
| @@ -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 | |||
| { | |||
| @@ -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); | |||
| @@ -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; | |||
| } | |||
| @@ -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 | |||