| @@ -75,15 +75,16 @@ int main(void) | |||
| PlsrParamBlockInit(); | |||
| /* Modbus 从站任务:解析 FC03/06/10,维护保持寄存器映像 */ | |||
| OSTaskCreateExt(ModbusSlaveTask, | |||
| NULL, | |||
| &ModbusTaskStk[MODBUS_TASK_STACK_SIZE - 1], | |||
| MODBUS_TASK_PRIO, | |||
| MODBUS_TASK_PRIO, | |||
| &ModbusTaskStk[0], | |||
| MODBUS_TASK_STACK_SIZE, | |||
| NULL, | |||
| OSTaskCreateExt(ModbusSlaveTask,//任务函数入口,任务实体函数 | |||
| NULL,//传递给任务函数的入口参数 | |||
| &ModbusTaskStk[MODBUS_TASK_STACK_SIZE - 1],//栈向下增长,栈从高地址往低地址生长 | |||
| MODBUS_TASK_PRIO,//任务优先级 | |||
| MODBUS_TASK_PRIO,//任务id,一般直接等于优先级;可以不等于优先级,但不能冲突 | |||
| &ModbusTaskStk[0],//栈数组的起始地址,数组下标 0 的地址 | |||
| MODBUS_TASK_STACK_SIZE,//栈的元素数量,不是字节数 | |||
| NULL,//TCB 扩展指针 | |||
| OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR | OS_TASK_OPT_SAVE_FP); | |||
| //开启栈用量统计;任务创建的时候,把整个栈内存全部清零;保存 FPU 浮点寄存器 | |||
| /* PLSR 主任务:TickMs / CommandPoll / 监控发布 */ | |||
| OSTaskCreateExt(PlsrTask, | |||
| @@ -95,7 +96,7 @@ int main(void) | |||
| PLSR_TASK_STACK_SIZE, | |||
| NULL, | |||
| OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR | OS_TASK_OPT_SAVE_FP); | |||
| //开启栈用量统计;任务创建的时候,把整个栈内存全部清零;保存 FPU 浮点寄存器 | |||
| /* | |||
| * 参数块任务:Pend → ApplyFromHold(校验)→ 通过则 SaveParamsFromHold。 | |||
| * 分帧写完后由 OnHoldWrite Post;Save 落 BKP,Export 仅供读回钳位结果。 | |||
| @@ -47,7 +47,7 @@ static void FlushUartRx(void); | |||
| static void RestartReceive(void); | |||
| static uint16_t ModbusCrc16(uint8_t *data, uint16_t len); | |||
| static void SendData(uint8_t *buf, uint16_t len); | |||
| static void ModbusDataInit(void); | |||
| //static void ModbusDataInit(void); | |||
| static uint16_t ModbusMapRegAddr(uint16_t addr); | |||
| static uint8_t ModbusIsRegRangeValid(uint16_t addr, uint16_t qty); | |||
| static uint16_t ReadU16Be(const uint8_t *data); | |||
| @@ -70,10 +70,10 @@ void ModbusSlaveTask(void *pArg) | |||
| /* | |||
| * ModbusDataInit 会清零 g_hold_reg;上电后仅从 BKP 恢复参数/监控到 hold, | |||
| * 不再把运行结构体 Export 回寄存器(非法参数保留在上位机写入值 + 0x2006)。 | |||
| * 不有点多此一举,直接不初始化g_hold_reg。 | |||
| */ | |||
| ModbusDataInit(); | |||
| PlsrPersistLoad(); | |||
| // ModbusDataInit(); | |||
| // PlsrPersistLoad(); | |||
| ModbusPortInit(); | |||
| while (1) | |||
| @@ -129,10 +129,10 @@ void ModbusSlaveTask(void *pArg) | |||
| * @brief 初始化保持寄存器映像 | |||
| * @retval None | |||
| */ | |||
| void ModbusDataInit(void) | |||
| { | |||
| memset(g_hold_reg, 0, sizeof(g_hold_reg)); | |||
| } | |||
| //void ModbusDataInit(void) | |||
| //{ | |||
| // memset(g_hold_reg, 0, sizeof(g_hold_reg)); | |||
| //} | |||
| /*============================================================================*/ | |||
| /* 地址映射与区间校验 */ | |||
| @@ -35,10 +35,9 @@ static volatile uint8_t s_live_freq_req; | |||
| static volatile uint32_t s_live_freq_hz; | |||
| /** | |||
| * @brief 写 32 位值到相邻两个保持寄存器(低字在前) | |||
| * @brief 写 32 位值到相邻两个modbus保持寄存器 | |||
| * @param addr 低字寄存器地址 | |||
| * @param value 32 位值 | |||
| * @note 副作用:WriteHoldReg 两次 | |||
| */ | |||
| static void PlsrCommandWriteDWord(uint16_t addr, uint32_t value) | |||
| { | |||
| @@ -47,9 +46,9 @@ static void PlsrCommandWriteDWord(uint16_t addr, uint32_t value) | |||
| } | |||
| /** | |||
| * @brief 刷新全部监控寄存器 0x2000~0x2006 | |||
| * @brief 刷新全部监控寄存器 0x2000~0x2006到modbus保持寄存器 | |||
| * @note 调用时机:Init 末、Poll 每周期末 | |||
| * @note 数据源:RunControl / Plsr 门面 API + s_fault 镜像 | |||
| * @note 数据源:RunControl / Plsr 任务 + s_fault 镜像 | |||
| */ | |||
| static void PlsrCommandPublishMonitor(void) | |||
| { | |||
| @@ -71,27 +70,27 @@ static void PlsrCommandPublishMonitor(void) | |||
| } | |||
| } | |||
| /** @brief 置故障(见 plsr_command.h) */ | |||
| /** @brief 置故障码 */ | |||
| void PlsrCommandSetFault(uint16_t code) | |||
| { | |||
| s_fault = code; | |||
| WriteHoldReg(PLSR_MON_ERR, code); | |||
| } | |||
| /** @brief 清故障(见 plsr_command.h) */ | |||
| /** @brief 清故障码 */ | |||
| void PlsrCommandClearFault(void) | |||
| { | |||
| s_fault = PLSR_ERR_NONE; | |||
| WriteHoldReg(PLSR_MON_ERR, PLSR_ERR_NONE); | |||
| } | |||
| /** @brief 读故障镜像(见 plsr_command.h) */ | |||
| /** @brief persist模块读故障码 */ | |||
| uint16_t PlsrCommandGetFault(void) | |||
| { | |||
| return s_fault; | |||
| } | |||
| /** @brief 参数/重复启动类故障是否禁止 START(见 plsr_command.h) */ | |||
| /** @brief 参数/重复启动类故障是否禁止 START */ | |||
| uint8_t PlsrCommandIsStartBlocked(void) | |||
| { | |||
| if ((s_fault >= PLSR_ERR_PARAM_BLOCK_MIN) && | |||
| @@ -102,7 +101,7 @@ uint8_t PlsrCommandIsStartBlocked(void) | |||
| return 0U; | |||
| } | |||
| /** @brief 指令模块初始化(见 plsr_command.h) */ | |||
| /** @brief 指令模块初始化 */ | |||
| void PlsrCommandInit(void) | |||
| { | |||
| WriteHoldReg(PLSR_CTRL_REG, 0U); | |||
| @@ -113,16 +112,16 @@ void PlsrCommandInit(void) | |||
| } | |||
| /** | |||
| * @brief 运行中 FC10 写段频率钩子(见 plsr_command.h) | |||
| * @note 门禁:quantity==2、Busy、地址对齐 FREQ_L、seg0==当前段 | |||
| * @brief 运行中 FC10 写段频率 | |||
| * @note 限制:quantity==2、Busy、地址对齐 FREQ_L、当前改频段,当前运行段 | |||
| * @note 频率非法写 0x04 且不更新段表、不请求 ChangeFreq | |||
| */ | |||
| void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity) | |||
| { | |||
| uint16_t cur1; | |||
| uint16_t seg0; | |||
| uint16_t off; | |||
| uint32_t f; | |||
| uint16_t current_seg;//当前运行段 | |||
| uint16_t seg;//当前改频段 | |||
| uint16_t offset;//偏移量 | |||
| uint32_t freqency; | |||
| if (quantity != 2U) | |||
| { | |||
| @@ -137,48 +136,48 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity) | |||
| return; | |||
| } | |||
| off = (uint16_t)(start_addr - PLSR_REG_SEG1_BASE); | |||
| if ((off % PLSR_SEG_STRIDE) != PLSR_SEG_OFF_FREQ_L) | |||
| offset = (uint16_t)(start_addr - PLSR_REG_SEG1_BASE); | |||
| if ((offset % PLSR_SEG_STRIDE) != PLSR_SEG_OFF_FREQ_L) | |||
| { | |||
| return; | |||
| } | |||
| seg0 = (uint16_t)(off / PLSR_SEG_STRIDE); | |||
| if (seg0 >= PLSR_SEG_MAX) | |||
| seg = (uint16_t)(offset / PLSR_SEG_STRIDE); | |||
| if (seg >= PLSR_SEG_MAX) | |||
| { | |||
| return; | |||
| } | |||
| cur1 = (uint16_t)(g_plsr_current_segment_index + 1U); | |||
| if ((cur1 < 1U) || ((uint16_t)(cur1 - 1U) != seg0)) | |||
| current_seg = (uint16_t)(g_plsr_current_segment_index + 1U); | |||
| if ((current_seg < 1U) || ((uint16_t)(current_seg - 1U) != seg)) | |||
| { | |||
| return; | |||
| } | |||
| f = (uint32_t)ReadHoldReg(start_addr) | | |||
| freqency = (uint32_t)ReadHoldReg(start_addr) | | |||
| ((uint32_t)ReadHoldReg((uint16_t)(start_addr + 1U)) << 16); | |||
| /* 运行中写频也做 0x04 门禁:非法不改段表、不请求 ChangeFreq */ | |||
| if ((f < 1U) || (f > 100000U)) | |||
| /* 运行中改频非法不改段表、不请求 ChangeFreq */ | |||
| if ((freqency < 1U) || (freqency > 100000U)) | |||
| { | |||
| PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); | |||
| return; | |||
| } | |||
| g_plsr_segments[seg0].freq_hz = (int32_t)f; | |||
| /* 运行中改频:立即只把该段频率双字写入 BKP,不等整包参数落盘 */ | |||
| PlsrPersistSaveSegFreqToBkp(seg0, f); | |||
| g_plsr_segments[seg].freq_hz = (int32_t)freqency; | |||
| /* 运行中改频只把该段频率写入 BKP */ | |||
| PlsrPersistSaveSegFreqToBkp(seg, freqency); | |||
| s_live_freq_hz = f; | |||
| s_live_freq_hz = freqency; | |||
| s_live_freq_req = 1U; | |||
| } | |||
| /** | |||
| * @brief 周期轮询(见 plsr_command.h) | |||
| * @brief 周期轮询 | |||
| * | |||
| * 控制位处理顺序(同周期多 bit 时): | |||
| * 1. 读 ctrl 后立即写 0(避免重复触发) | |||
| * 2. STOP — 急停 | |||
| * 3. CLR — 清累计 + ClearFault | |||
| * 4. START — 忙则 0x0C;否则 Apply 校验 → 0x04~0x0C 门禁则拒启 → Stop+Start | |||
| * 4. START — 忙则 0x0C;否则 Apply 校验 → 0x04~0x0C 故障码则拒启 → Stop+Start | |||
| * 动态改频在控制位之后、PublishMonitor 之前执行。 | |||
| */ | |||
| void PlsrCommandPoll(void) | |||
| @@ -188,7 +187,7 @@ void PlsrCommandPoll(void) | |||
| if (ctrl != 0U) | |||
| { | |||
| WriteHoldReg(PLSR_CTRL_REG, 0U); /* 从站「读-改-清」协议:处理后清零 */ | |||
| WriteHoldReg(PLSR_CTRL_REG, 0U); | |||
| if ((ctrl & PLSR_CTRL_BIT_STOP) != 0U) | |||
| { | |||
| @@ -198,7 +197,7 @@ void PlsrCommandPoll(void) | |||
| if ((ctrl & PLSR_CTRL_BIT_CLR) != 0U) | |||
| { | |||
| PlsrClearAccPulse(); | |||
| PlsrCommandClearFault(); /* 清零累计时同步清 0x2006 */ | |||
| PlsrCommandClearFault(); /* 清零累计时同步清故障码 */ | |||
| } | |||
| /* 同时有停止位时不启动 */ | |||
| @@ -212,11 +211,11 @@ void PlsrCommandPoll(void) | |||
| } | |||
| else if (PlsrParamBlockApplyFromHold() == 0U) | |||
| { | |||
| /* Apply 失败:故障码已由参数块写入 0x2006,不落 BKP */ | |||
| /* 如果从modbus保持寄存器写入plsr结构体失败,暂不处理 */ | |||
| } | |||
| else if (PlsrCommandIsStartBlocked() != 0U) | |||
| { | |||
| /* 0x04~0x0B 等门禁故障:禁止启动 */ | |||
| /* 0x04~0x0B 故障码:禁止启动 */ | |||
| } | |||
| else | |||
| { | |||
| @@ -233,9 +232,9 @@ void PlsrCommandPoll(void) | |||
| /* 动态改频:标志置位后按新目标重规划剩余脉冲 */ | |||
| if (s_live_freq_req != 0U) | |||
| { | |||
| uint32_t f = s_live_freq_hz; | |||
| uint32_t freq = s_live_freq_hz; | |||
| s_live_freq_req = 0U; | |||
| (void)PlsrChangeFreq(f); | |||
| (void)PlsrChangeFreq(freq); | |||
| } | |||
| if (skip_monitor == 0U) | |||
| @@ -44,40 +44,24 @@ | |||
| /* | |||
| * 故障码定义(写入 0x2006,须经 PlsrCommandSetFault,勿直接只写寄存器) | |||
| * | |||
| * 码 | 宏名 | 含义 | 等级 | 处理策略 | |||
| * ----|-------------------------|--------------------------------|------|------------------ | |||
| * 0 | PLSR_ERR_NONE | 无故障 | — | 启动/CLR 时写入 | |||
| * 1 | PLSR_ERR_PULSE_CNT | 实际脉冲数与段目标不一致 | 告警 | 继续跑,不中断 | |||
| * 2 | PLSR_ERR_FREQ_UNREACH | 规划峰值达不到设定目标(三角) | 告警 | 按压后规划继续 | |||
| * 3 | PLSR_ERR_CURVE_MISMATCH | 加减速相内脉冲与规划预算不符 | 告警 | 继续跑 | |||
| * 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_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, 100000] Hz(非 0) | |||
| #define PLSR_ERR_PULSE_RANGE 0x05U //脉冲个数 ∉ int32 合法范围 | |||
| #define PLSR_ERR_SEG_COUNT 0x06U //总段数 ∉ [1, 10] | |||
| #define PLSR_ERR_START_SEG 0x07U //起始段 ∉ [1, 10] | |||
| #define PLSR_ERR_START_END_SPD 0x08U //起/止速非0且 ∉ [1, 100000] Hz | |||
| #define PLSR_ERR_PULSE_Y 0x09U //脉冲端子 ∉ {Y0,Y1,Y2} | |||
| #define PLSR_ERR_DIR_Y 0x0AU //方向端子 ≠ Y3 | |||
| #define PLSR_ERR_DEFAULT_SPD 0x0BU //默认速度 ∉ [1, 100000] Hz | |||
| #define PLSR_ERR_DUP_START 0x0CU //运行中重复 START | |||
| /** 参数类门禁故障码下限(含) */ | |||
| /** 参数类门禁故障码下限 */ | |||
| #define PLSR_ERR_PARAM_BLOCK_MIN PLSR_ERR_FREQ_ILLEGAL | |||
| /** 参数类门禁故障码上限(含 0x0C 重复启动) */ | |||
| /** 参数类门禁故障码上限 */ | |||
| #define PLSR_ERR_PARAM_BLOCK_MAX PLSR_ERR_DUP_START | |||
| /** | |||
| @@ -98,7 +82,7 @@ void PlsrCommandPoll(void); | |||
| * @brief 置故障码并立即写 0x2006 | |||
| * @param code PLSR_ERR_* 之一 | |||
| * @note 调用时机:run_control 诊断点;PublishMonitor 也会重发 s_fault | |||
| * @note 副作用:更新 s_fault 镜像,告警码不自动清除(须 START 或 CLR) | |||
| * @note 注意:更新 s_fault 镜像,告警码不自动清除(须 START 或 CLR) | |||
| */ | |||
| void PlsrCommandSetFault(uint16_t code); | |||
| @@ -113,7 +97,7 @@ uint16_t PlsrCommandGetFault(void); | |||
| /** | |||
| * @brief 是否因参数/重复启动类故障禁止 START | |||
| * @return 1=0x2006 为 0x04~0x0C(门禁/重复启动);0=可尝试启动 | |||
| * @return 1=故障码为 0x04~0x0C;0=可尝试启动 | |||
| */ | |||
| uint8_t PlsrCommandIsStartBlocked(void); | |||
| @@ -121,8 +105,6 @@ uint8_t PlsrCommandIsStartBlocked(void); | |||
| * @brief FC10 写段频率双字后的钩子 | |||
| * @param start_addr 写入起始保持寄存器地址 | |||
| * @param quantity 写入字数,须为 2 | |||
| * @note 调用时机:Modbus 从站 FC10 应答路径;仅运行中且地址为「当前段 FREQ_L」有效 | |||
| * @note 副作用:更新段表 freq_hz,置 s_live_freq_req 由 Poll 调 ChangeFreq | |||
| */ | |||
| void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity); | |||
| @@ -4,20 +4,11 @@ | |||
| * | |||
| * @details 模块职责 | |||
| * 维护公共参数 g_plsr_config 和段参数 g_plsr_segments[],实现寄存器与 | |||
| * 运行参数之间的双向转换,以及 | |||
| * 「5+N 分帧」收齐后的异步 Apply(信号量唤醒本任务)。 | |||
| * | |||
| * 静态状态说明 | |||
| * g_plsr_config — 公共运行参数 | |||
| * g_plsr_segments[] — 10 段运行参数 | |||
| * s_param_sem — 收齐分帧后 Post,Task Pend 后 Apply | |||
| * s_expect_frames — 期望总帧 = 5 + 公共帧1 中的段数 | |||
| * s_recv_frames — 已收帧计数(公共帧1 起算) | |||
| * s_xfer_active — 正在接收一批分帧传输 | |||
| * 运行参数之间的双向转换,以及「5+N 分帧」收齐后的异步导入 | |||
| * | |||
| * 与其它模块关系 | |||
| * Modbus FC10 应答路径调用 OnHoldWrite;Command START 也会同步 ApplyFromHold; | |||
| * Persist:校验全部通过才 SaveParamsFromHold;失败只写故障码,不落 BKP; | |||
| * Modbus FC10 应答路径调用 OnHoldWrite;START 也会同步 ApplyFromHold; | |||
| * Persist:校验全部通过才 SaveParamsFromHold;失败只写故障码,不存BKP; | |||
| * 非上电不再 ExportToHold(hold 保留上位机写入值,由故障码提示修正)。 | |||
| */ | |||
| #include "plsr_param.h" | |||
| @@ -34,7 +25,7 @@ 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](见 plsr_param.h) */ | |||
| /** @return 有效段数,须在[0, PLSR_SEG_MAX]之间 */ | |||
| uint16_t PlsrParamGetSegCount(void) | |||
| { | |||
| if (g_plsr_config.seg_count < 1U) | |||
| @@ -49,8 +40,7 @@ uint16_t PlsrParamGetSegCount(void) | |||
| } | |||
| /** | |||
| * @brief 启动段 1-based(见 plsr_param.h) | |||
| * @note 非法起始段当前仅裁剪,TODO 可报故障码 | |||
| * @brief 启动段 1-based | |||
| */ | |||
| uint16_t PlsrParamGetStartSeg(void) | |||
| { | |||
| @@ -64,7 +54,6 @@ uint16_t PlsrParamGetStartSeg(void) | |||
| { | |||
| return 1U; | |||
| } | |||
| /* TODO:起始段非法时输出故障码 */ | |||
| if (g_plsr_config.start_seg > n) | |||
| { | |||
| return n; | |||
| @@ -72,10 +61,6 @@ uint16_t PlsrParamGetStartSeg(void) | |||
| return g_plsr_config.start_seg; | |||
| } | |||
| /*============================================================================*/ | |||
| /* 寄存器双字读写辅助 */ | |||
| /*============================================================================*/ | |||
| /** 读相邻两寄存器拼成无符号 32 位(低地址=低 16 位) */ | |||
| static uint32_t PlsrParamReadDWord(uint16_t addr) | |||
| { | |||
| @@ -84,15 +69,8 @@ static uint32_t PlsrParamReadDWord(uint16_t addr) | |||
| return ((uint32_t)high << 16) | (uint32_t)low; | |||
| } | |||
| /** 写无符号 32 位到相邻两寄存器 */ | |||
| static void PlsrParamWriteDWord(uint16_t addr, uint32_t value) | |||
| { | |||
| WriteHoldReg(addr, (uint16_t)(value & 0xFFFFU)); | |||
| WriteHoldReg((uint16_t)(addr + 1U), (uint16_t)((value >> 16) & 0xFFFFU)); | |||
| } | |||
| /** | |||
| * @brief 判断本次 FC10 是否为公共帧 2~5(双字速度/加减速) | |||
| * @brief 判断本次 FC10 是否为公共帧 2~5 | |||
| * @return 1=是;0=否 | |||
| */ | |||
| static uint8_t PlsrParamIsCommonTailFrameWrite(uint16_t start_addr, uint16_t quantity) | |||
| @@ -112,7 +90,7 @@ static uint8_t PlsrParamIsCommonTailFrameWrite(uint16_t start_addr, uint16_t qua | |||
| } | |||
| /** | |||
| * @brief 判断本次 FC10 是否为「整段 8 字写到某段基址」 | |||
| * @brief 判断本次 FC10 是否为段参数 | |||
| * @return 1=是段帧;0=否 | |||
| */ | |||
| static uint8_t PlsrParamIsSegFrameWrite(uint16_t start_addr, uint16_t quantity) | |||
| @@ -135,20 +113,8 @@ static uint8_t PlsrParamIsSegFrameWrite(uint16_t start_addr, uint16_t quantity) | |||
| return 0U; | |||
| } | |||
| /** | |||
| * @brief 更新分帧状态三寄存器,供上位机诊断 | |||
| * @param st PLSR_PARAM_XFER_* | |||
| * @param fail_frame 失败帧序号(成功时写 0) | |||
| */ | |||
| static void PlsrParamSetXferStatus(uint16_t st, uint16_t fail_frame) | |||
| { | |||
| WriteHoldReg(PLSR_PARAM_XFER_STATUS_REG, st); | |||
| WriteHoldReg(PLSR_PARAM_XFER_FAIL_FRAME_REG, fail_frame); | |||
| WriteHoldReg(PLSR_PARAM_XFER_RECV_REG, s_recv_frames); | |||
| } | |||
| /*============================================================================*/ | |||
| /* 参数校验辅助 */ | |||
| /* 参数校验辅助 */ | |||
| /*============================================================================*/ | |||
| #define PLSR_PARAM_SPD_MIN_HZ 1U | |||
| @@ -160,7 +126,7 @@ static uint8_t PlsrParamIsSpeedHzValid(uint32_t hz) | |||
| } | |||
| /** | |||
| * 起速/止速:0 合法(运行层 ResolveStartHz / ResolveEndHz 处理); | |||
| * 起速/止速:0 合法; | |||
| * 非 0 须在 1~100kHz。 | |||
| */ | |||
| static uint8_t PlsrParamIsStartEndSpeedValid(uint32_t hz) | |||
| @@ -202,11 +168,11 @@ static uint8_t PlsrParamIsPulseCntValid(int32_t pulse_cnt) | |||
| /*============================================================================*/ | |||
| /** | |||
| * @brief 保持寄存器 → 运行映像,边拷贝边校验(见 plsr_param.h) | |||
| * @brief 保持寄存器 → 运行映像,边拷贝边校验 | |||
| * | |||
| * @details 校验失败时仍完成拷贝(保留上位机原始值),故障码写入 0x2006; | |||
| * 多项非法时仅保留校验过程中「最后一个」故障码。 | |||
| * @return 1=全部通过;0=存在门禁故障(不落 BKP) | |||
| * @details 校验失败时仍完成拷贝,故障码写入 0x2006; | |||
| * 多项非法时仅保留校验过程中最后一个故障码。 | |||
| * @return 1=全部通过;0=存在门禁故障(不落存BKP) | |||
| */ | |||
| uint8_t PlsrParamBlockApplyFromHold(void) | |||
| { | |||
| @@ -318,65 +284,12 @@ uint8_t PlsrParamBlockApplyFromHold(void) | |||
| } | |||
| /** | |||
| * @brief 运行映像 → 全部相关保持寄存器(含未使用段槽位) | |||
| * | |||
| * @details 用途(与落 BKP 无关) | |||
| * 1. Apply 钳位后摊回 hold,使「读 PLC」与运行结构体一致; | |||
| * 2. ModbusDataInit() 清 hold 后,把已 Apply 的运行参数填回, | |||
| * 否则上位机读公共/段参数全 0,START 也会用空 hold 再次 Apply 冲掉结构体。 | |||
| * @brief 统计接受帧数,收满释放信号量 | |||
| * | |||
| * @note 0x100F 保留字写 0;段表写满 PLSR_SEG_MAX 槽,避免读回脏数据 | |||
| * @note 落 BKP 请用 PlsrPersistSaveParamsFromHold(读 hold 原值),不依赖本函数 | |||
| */ | |||
| void PlsrParamBlockExportToHold(void) | |||
| { | |||
| uint16_t i; | |||
| uint16_t base; | |||
| WriteHoldReg(PLSR_REG_PULSE_Y, g_plsr_config.pulse_y); | |||
| WriteHoldReg(PLSR_REG_DIR_Y, g_plsr_config.dir_y); | |||
| WriteHoldReg(PLSR_REG_WAIT_X, g_plsr_config.wait_x_sel); | |||
| WriteHoldReg(PLSR_REG_EXT_X, g_plsr_config.ext_x_sel); | |||
| WriteHoldReg(PLSR_REG_SEND_MODE, (uint16_t)g_plsr_config.send_mode); | |||
| WriteHoldReg(PLSR_REG_DIR_DELAY, g_plsr_config.dir_delay_ms); | |||
| WriteHoldReg(PLSR_REG_DIR_LOGIC, (uint16_t)g_plsr_config.dir_logic); | |||
| WriteHoldReg(PLSR_REG_ACCEL_MODE, (uint16_t)g_plsr_config.accel_mode); | |||
| WriteHoldReg(PLSR_REG_RUN_MODE, (uint16_t)g_plsr_config.run_mode); | |||
| WriteHoldReg(PLSR_REG_SEG_COUNT, g_plsr_config.seg_count); | |||
| WriteHoldReg(PLSR_REG_START_SEG, g_plsr_config.start_seg); | |||
| PlsrParamWriteDWord(PLSR_REG_DEFAULT_SPD_L, g_plsr_config.default_speed); | |||
| PlsrParamWriteDWord(PLSR_REG_START_SPD_L, g_plsr_config.start_speed); | |||
| WriteHoldReg(0x100FU, 0U); | |||
| PlsrParamWriteDWord(PLSR_REG_END_SPD_L, g_plsr_config.end_speed); | |||
| WriteHoldReg(PLSR_REG_ACCEL_MS, g_plsr_config.accel_ms); | |||
| WriteHoldReg(PLSR_REG_DECEL_MS, g_plsr_config.decel_ms); | |||
| for (i = 0U; i < PLSR_SEG_MAX; i++) | |||
| { | |||
| base = (uint16_t)(PLSR_REG_SEG1_BASE + i * PLSR_SEG_STRIDE); | |||
| PlsrParamWriteDWord((uint16_t)(base + PLSR_SEG_OFF_FREQ_L), | |||
| (uint32_t)g_plsr_segments[i].freq_hz); | |||
| PlsrParamWriteDWord((uint16_t)(base + PLSR_SEG_OFF_PULSE_L), | |||
| (uint32_t)g_plsr_segments[i].pulse_cnt); | |||
| WriteHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT), | |||
| (uint16_t)g_plsr_segments[i].wait_type); | |||
| WriteHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT_MS), | |||
| g_plsr_segments[i].wait_ms); | |||
| WriteHoldReg((uint16_t)(base + PLSR_SEG_OFF_ACT_MS), | |||
| g_plsr_segments[i].act_ms); | |||
| WriteHoldReg((uint16_t)(base + PLSR_SEG_OFF_JUMP), | |||
| g_plsr_segments[i].jump_seg); | |||
| } | |||
| } | |||
| /** | |||
| * @brief FC10 写后分帧状态机(见 plsr_param.h) | |||
| * | |||
| * 状态转移: | |||
| * 公共帧1@0x1000~0x100A → BUSY,expect=5+N,recv=1 | |||
| * 公共帧1@0x1000~0x100A,expect=5+N,recv=1 | |||
| * 传输中公共帧2~5 / 段帧 → recv++ | |||
| * recv>=expect → 清 active,Post 信号量(或同步 Apply) | |||
| * 其它写地址忽略(例如运行中只写频率双字不走本路径的分帧逻辑) | |||
| * recv>=expect → 清 active,Post 信号量 | |||
| * 运行中只写频率双字不走本路径 | |||
| */ | |||
| void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity) | |||
| { | |||
| @@ -385,11 +298,6 @@ void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity) | |||
| return; | |||
| } | |||
| /* | |||
| * 公共帧1:0x1000~0x100A(含段数)→ 开启传输,期望帧=5+段数。 | |||
| * 公共帧2~5 / 段帧:传输中且地址匹配 → 帧计数+1。 | |||
| * 收齐后 post 信号量,由 ParamBlockTask 执行 Apply。 | |||
| */ | |||
| if ((start_addr == PLSR_REG_COMMON_F1_BASE) && | |||
| (quantity >= PLSR_PARAM_COMMON_FRAME1_WORDS)) | |||
| { | |||
| @@ -401,14 +309,12 @@ void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity) | |||
| s_expect_frames = (uint16_t)(PLSR_PARAM_COMMON_FRAMES + seg_n); | |||
| s_recv_frames = 1U; | |||
| s_xfer_active = 1U; | |||
| PlsrParamSetXferStatus(PLSR_PARAM_XFER_BUSY, 0U); | |||
| } | |||
| else if ((s_xfer_active != 0U) && | |||
| ((PlsrParamIsCommonTailFrameWrite(start_addr, quantity) != 0U) || | |||
| (PlsrParamIsSegFrameWrite(start_addr, quantity) != 0U))) | |||
| { | |||
| s_recv_frames++; | |||
| WriteHoldReg(PLSR_PARAM_XFER_RECV_REG, s_recv_frames); | |||
| } | |||
| else | |||
| { | |||
| @@ -422,33 +328,23 @@ void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity) | |||
| { | |||
| (void)OSSemPost(s_param_sem); | |||
| } | |||
| else if (PlsrParamBlockApplyFromHold() != 0U) | |||
| { | |||
| /* 信号量尚未创建时的兜底:同步 Apply */ | |||
| PlsrParamSetXferStatus(PLSR_PARAM_XFER_OK, 0U); | |||
| } | |||
| else | |||
| { | |||
| PlsrParamSetXferStatus(PLSR_PARAM_XFER_FAIL, s_recv_frames); | |||
| } | |||
| } | |||
| } | |||
| /** @brief 创建信号量并置传输空闲(见 plsr_param.h) */ | |||
| /** @brief 创建信号量并置清空接收计数 */ | |||
| void PlsrParamBlockInit(void) | |||
| { | |||
| s_param_sem = OSSemCreate(0U); | |||
| s_expect_frames = 0U; | |||
| s_recv_frames = 0U; | |||
| s_xfer_active = 0U; | |||
| PlsrParamSetXferStatus(PLSR_PARAM_XFER_IDLE, 0U); | |||
| } | |||
| /** | |||
| * @brief 参数块任务(见 plsr_param.h) | |||
| * @brief 参数块任务 | |||
| * | |||
| * for(;;):OSSemPend → ApplyFromHold(校验+写 0x2006)→ 通过则 SaveParamsFromHold。 | |||
| * 校验失败:不落 BKP,hold 保留上位机原值,由故障码提示修正。 | |||
| * OSSemPend → ApplyFromHold(校验+写 0x2006)→ 通过则 SaveParamsFromHold。 | |||
| * 校验失败:不存 BKP,hold 保留上位机原值,由故障码提示修正。 | |||
| */ | |||
| void PlsrParamBlockTask(void *pArg) | |||
| { | |||
| @@ -466,12 +362,7 @@ void PlsrParamBlockTask(void *pArg) | |||
| if (PlsrParamBlockApplyFromHold() != 0U) | |||
| { | |||
| PlsrParamSetXferStatus(PLSR_PARAM_XFER_OK, 0U); | |||
| PlsrPersistSaveParamsFromHold(); /* 仅全部校验通过才落 BKP */ | |||
| } | |||
| else | |||
| { | |||
| PlsrParamSetXferStatus(PLSR_PARAM_XFER_FAIL, s_recv_frames); | |||
| PlsrPersistSaveParamsFromHold(); /* 仅全部校验通过才存 BKP */ | |||
| } | |||
| } | |||
| } | |||
| @@ -4,7 +4,7 @@ | |||
| * | |||
| * @details 模块职责 | |||
| * 1. 定义公共参数区 0x1000~0x1013、段表区 0x1100+i*0x10 的地址与字段语义; | |||
| * 2. 维护 g_plsr_config / g_plsr_segments[](运动规划只读,不直接读寄存器); | |||
| * 2. 维护 g_plsr_config / g_plsr_segments[]; | |||
| * 3. 支持上位机「5 公共帧 + N 段帧」分帧 FC10 写入:收齐后 ApplyFromHold; | |||
| * 4. 上电由 PersistLoad 填 hold;ExportToHold 仅保留作调试接口。 | |||
| * | |||
| @@ -12,8 +12,8 @@ | |||
| * - modbus_rtu / modbus_data :ReadHoldReg / WriteHoldReg | |||
| * - plsr_command :启动前 ApplyFromHold;运行中修改当前段 freq_hz | |||
| * - plsr_run_control :GetCfg / GetSeg / GetSegCount / GetStartSeg | |||
| * - plsr_persist :Apply 成功后 SaveParamsFromHold;动态改频 SaveSegFreqToBkp | |||
| * - PlsrParamBlockTask :独立 uC/OS 任务,等信号量后 Apply + 整包落 BKP | |||
| * - plsr_persist :拷贝成功后存入BKP;动态改频存频率进BKP | |||
| * - PlsrParamBlockTask :独立 uC/OS 任务,等信号量后 Apply + 整包存 BKP | |||
| * | |||
| * 关键数据流 | |||
| * 上位机写公共帧1@0x1000 → OnHoldWrite 开传输 expect=5+N,recv=1 | |||
| @@ -23,7 +23,7 @@ | |||
| * | |||
| * 协议概要 | |||
| * - 公共 5 帧: | |||
| * 1: 0x1000~0x100A(11 字,含段数 N@0x1009) | |||
| * 1: 0x1000~0x100A(11 字) | |||
| * 2: 0x100B~0x100C(默认速度) | |||
| * 3: 0x100D~0x100E(起速) | |||
| * 4: 0x1010~0x1011(止速;跳过 0x100F) | |||
| @@ -59,7 +59,7 @@ | |||
| /* 0x100F 保留,写帧填 0 */ | |||
| #define PLSR_REG_END_SPD_L 0x1010U /* 止速 Hz */ | |||
| #define PLSR_REG_END_SPD_H 0x1011U | |||
| #define PLSR_REG_ACCEL_MS 0x1012U /* 默认速度加速时间 ms(定斜率) */ | |||
| #define PLSR_REG_ACCEL_MS 0x1012U /* 默认速度加速时间 ms */ | |||
| #define PLSR_REG_DECEL_MS 0x1013U /* 默认速度减速时间 ms */ | |||
| /* ---------- 公共参数分帧(5 帧 + N 段帧) ---------- */ | |||
| @@ -87,16 +87,6 @@ | |||
| #define PLSR_SEG_OFF_ACT_MS 6U /* ACT 时间 ms */ | |||
| #define PLSR_SEG_OFF_JUMP 7U /* 0=顺序/末段停;1~N=跳转目标段号 */ | |||
| /* ---------- 分帧传输状态(上位机可选读) ---------- */ | |||
| #define PLSR_PARAM_XFER_RECV_REG 0x0FFCU /* 已接收帧计数 */ | |||
| #define PLSR_PARAM_XFER_FAIL_FRAME_REG 0x0FFDU /* 失败时的帧序号 */ | |||
| #define PLSR_PARAM_XFER_STATUS_REG 0x0FFEU /* IDLE/BUSY/OK/FAIL */ | |||
| #define PLSR_PARAM_XFER_IDLE 0U | |||
| #define PLSR_PARAM_XFER_BUSY 1U | |||
| #define PLSR_PARAM_XFER_OK 2U | |||
| #define PLSR_PARAM_XFER_FAIL 3U | |||
| /** 方向逻辑:正转时方向脚电平 */ | |||
| typedef enum { | |||
| PLSR_DIR_LOGIC_POS = 0, /* 正转→方向高,反转→低 */ | |||
| @@ -113,7 +103,7 @@ typedef enum { | |||
| PLSR_SEND_FOLLOW = 1 | |||
| } PlsrSendMode_e; | |||
| /** 加减速曲线形状(脉冲域规划) */ | |||
| /** 加减速曲线形状 */ | |||
| typedef enum { | |||
| PLSR_ACCEL_LINEAR = 0, /* f^2 = f0^2 ± 2an */ | |||
| PLSR_ACCEL_S = 1, /* 时间域七段 S:加速度梯形 1:2:1 */ | |||
| @@ -131,7 +121,7 @@ typedef enum { | |||
| } PlsrPosMode_e; | |||
| /** | |||
| * 段末/段内等待类型(由 run_control + signal_io 执行) | |||
| * 段末/段内等待类型 | |||
| * TIME/SIGNAL/ACT/EXT:完成/后续均规划到止速;并阻止 FOLLOW 不停表衔接 | |||
| * EXT_OR_DONE:与下一段同向时后续可接目标/完成匀速跑完并可 FOLLOW 衔接; | |||
| * 与下一段反向时规划同其它等待(减速到止速,下一段从起速再爬) | |||
| @@ -145,8 +135,7 @@ typedef enum { | |||
| } PlsrWaitType_e; | |||
| /** | |||
| * 公共运行参数映像(运动侧只读) | |||
| * 斜率:a ≈ default_speed * 1000 / accel_ms(Hz/s) | |||
| * 公共运行参数映像 | |||
| */ | |||
| typedef struct { | |||
| uint16_t pulse_y; /* 0=Y0/TIM10 1=Y1/TIM13 2=Y2/TIM11 */ | |||
| @@ -178,15 +167,6 @@ typedef struct { | |||
| } PlsrSeg_t; | |||
| /* ---------- 运行参数 ---------- */ | |||
| /* | |||
| * 所有 PLSR 模块都直接读取这两份数据。 | |||
| * g_plsr_config :公共参数,只有一份。 | |||
| * g_plsr_segments[i] :第 i+1 段参数,i 的范围是 0~9。 | |||
| * | |||
| * 参数任务负责从保持寄存器更新它们;运动过程中其它模块只读取, | |||
| * 只有“运行中改频”会修改当前段的 freq_hz。 | |||
| */ | |||
| extern PlsrCfg_t g_plsr_config; | |||
| extern PlsrSeg_t g_plsr_segments[PLSR_SEG_MAX]; | |||
| @@ -210,7 +190,6 @@ void PlsrParamBlockInit(void); | |||
| /** | |||
| * @brief 参数块任务:阻塞等信号量 → ApplyFromHold(校验)→ 通过则 SaveParamsFromHold | |||
| * @param pArg 未使用 | |||
| * @note for(;;) 死循环为 RTOS 任务常态;空循环体是错觉(花括号内有 Pend/Apply) | |||
| */ | |||
| void PlsrParamBlockTask(void *pArg); | |||
| @@ -218,20 +197,14 @@ void PlsrParamBlockTask(void *pArg); | |||
| * @brief FC10 写保持寄存器后由 Modbus 回调 | |||
| * @param start_addr 起始地址 | |||
| * @param quantity 字数 | |||
| * @note 公共帧开传输;段帧累加;收齐 post 信号量(或无信号量时同步 Apply) | |||
| * @note 公共帧开传输;段帧累加;收齐 post 信号量 | |||
| */ | |||
| void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity); | |||
| /** | |||
| * @brief 保持寄存器 → g_plsr_config / g_plsr_segments,边拷贝边校验 | |||
| * @return 1=全部通过(写 0x2006=0);0=存在门禁故障(写对应码,不落 BKP) | |||
| * @return 1=全部通过;0=存在门禁故障 | |||
| */ | |||
| uint8_t PlsrParamBlockApplyFromHold(void); | |||
| /** | |||
| * @brief g_plsr_config / g_plsr_segments → 保持寄存器(调试/特殊用途) | |||
| * @note 上电参数由 BKP→hold(PersistLoad);非法参数保留 hold 原值供上位机读回修正 | |||
| */ | |||
| void PlsrParamBlockExportToHold(void); | |||
| #endif | |||
| @@ -2,12 +2,7 @@ | |||
| * @file plsr.c | |||
| * @brief PLSR 顶层初始化和周期任务 | |||
| * | |||
| * @details 模块职责 | |||
| * 本文件只做两件事:按顺序初始化各模块,以及运行 PlsrTask 周期任务。 | |||
| * 启停和中断函数直接实现在 run_control.c,这里不再做重复转发。 | |||
| * | |||
| * 与其它模块关系 | |||
| * 本文件仅依赖 plsr.h 及各子模块头文件,不被其它 plsr 模块反向引用。 | |||
| * @details 按顺序初始化各模块,以及运行 PlsrTask 周期任务。 | |||
| * | |||
| * 关键数据流 | |||
| * PlsrInit 顺序:PersistLoad(BKP→hold) → ApplyFromHold(hold→结构体) → … | |||
| @@ -24,15 +19,15 @@ | |||
| #include "ucos_ii.h" | |||
| /** | |||
| * @brief 子系统初始化(见 plsr.h) | |||
| * @brief 子系统初始化 | |||
| * | |||
| * 顺序要点 | |||
| * PersistLoad → Apply:BKP → hold → 结构体(BKP 内参数应已合法); | |||
| * PersistLoad → Apply:BKP → hold → 结构体(BKP 内参数已合法); | |||
| * 非上电不再把结构体 Export 回 hold;Modbus 清零后由 BKP 再填 hold。 | |||
| */ | |||
| void PlsrInit(void) | |||
| { | |||
| PlsrPersistInit(); /* 使能 BKPSRAM 写访问,否则落盘无效 */ | |||
| PlsrPersistInit(); /* 使能 BKPSRAM 写访问,否则存BKP无效 */ | |||
| PlsrPersistLoad(); /* BKPSRAM → g_hold_reg */ | |||
| (void)PlsrParamBlockApplyFromHold(); /* hold → 运行参数 + 校验 */ | |||
| PlsrPulseDriverInit(); | |||
| @@ -30,27 +30,14 @@ extern volatile uint16_t g_plsr_current_segment_index; | |||
| extern volatile int32_t g_plsr_accumulated_pulses; | |||
| #include "plsr_param.h" | |||
| /* | |||
| * PLSR_LOOP_TEST_EN:调试宏。 | |||
| * 1 = 第 1 段跑完后空闲约 1s 自动再启(仅联调);正式产品保持 0。 | |||
| */ | |||
| #ifndef PLSR_LOOP_TEST_EN | |||
| #define PLSR_LOOP_TEST_EN 0 | |||
| #endif | |||
| /** | |||
| * @brief 子系统一次性初始化 | |||
| * @note 调用时机:OS 启动后、Modbus 从站就绪前,由 main 或启动任务调用一次 | |||
| * @note 副作用:加载 Flash 公共参数、初始化 TIM/GPIO、导出默认映像到保持寄存器 | |||
| * @brief plsr任务初始化 | |||
| */ | |||
| void PlsrInit(void); | |||
| /** | |||
| * @brief uC/OS-II 周期任务入口 | |||
| * @param pArg 任务参数(未使用,传 NULL) | |||
| * @note 调用时机:创建后永久循环;WAIT/ACT 到期由信号量立刻唤醒,否则最多 1 个 OS tick | |||
| * @note 副作用:轮询 Modbus 控制位、刷新监控寄存器、推进运行控制状态机、 | |||
| * 空闲时触发 Flash 持久化;首次进入延迟 ~300ms 再导出参数(避免 Modbus 清零冲掉) | |||
| * @param pArg 任务参数 | |||
| */ | |||
| void PlsrTask(void *pArg); | |||