| @@ -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); | |||
| @@ -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 */ | |||
| } | |||
| } | |||
| @@ -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 */ | |||
| } | |||
| } | |||
| } | |||
| @@ -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; | |||
| @@ -25,9 +25,9 @@ | |||
| #include <stdint.h> | |||
| /* 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" | |||
| /** | |||
| @@ -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 | |||
| @@ -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) | |||