diff --git a/plsr/param/plsr_param.h b/plsr/param/plsr_param.h index 54fcc00..aefc603 100644 --- a/plsr/param/plsr_param.h +++ b/plsr/param/plsr_param.h @@ -82,7 +82,7 @@ typedef enum { typedef enum { PLSR_WAIT_TIME = 0, /* 发完后等 wait_ms,再跳转 */ - PLSR_WAIT_SIGNAL = 1, /* 发完后等 WAIT 口导通(20ms 消抖),再跳转 */ + PLSR_WAIT_SIGNAL = 1, /* 发完后等 WAIT 口下降沿(EXTI),再跳转 */ PLSR_WAIT_ACT = 2, /* 出脉冲满 act_ms 后中途切段并立即跳转 */ PLSR_WAIT_EXT = 3, /* 运行中 EXT 下降沿中途切段并立即跳转 */ PLSR_WAIT_EXT_OR_DONE = 4 /* EXT 沿或脉冲发完,先到先跳转 */ diff --git a/plsr/pulse_driver/plsr_pulse_driver.c b/plsr/pulse_driver/plsr_pulse_driver.c index af0d422..fa0bca3 100644 --- a/plsr/pulse_driver/plsr_pulse_driver.c +++ b/plsr/pulse_driver/plsr_pulse_driver.c @@ -80,7 +80,7 @@ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) __HAL_RCC_GPIOF_CLK_ENABLE(); gpio.Mode = GPIO_MODE_AF_PP; - gpio.Pull = GPIO_NOPULL; + gpio.Pull = GPIO_PULLDOWN; gpio.Speed = GPIO_SPEED_FREQ_HIGH; if (htim->Instance == TIM10) diff --git a/plsr/run_control/plsr_run_control.c b/plsr/run_control/plsr_run_control.c index 7ca7b8e..f8abfbe 100644 --- a/plsr/run_control/plsr_run_control.c +++ b/plsr/run_control/plsr_run_control.c @@ -103,7 +103,15 @@ static void PlsrRunControlArmActExtOnPulseStart(void) { PlsrSeg_t *seg = PlsrParamGetSeg(s_cur_seg); - PlsrSignalIoClearEdges(); + /* + * EXT 中途切段:开跑时丢掉旧沿,避免上一段的 WAIT 沿立刻切段。 + * WAIT 信号不在这里清:段中落地的下降沿要留给※2。 + */ + if ((seg->wait_type == PLSR_WAIT_EXT) || + (seg->wait_type == PLSR_WAIT_EXT_OR_DONE)) + { + PlsrSignalIoClearEdges(); + } s_act_armed = 0U; if ((seg->wait_type == PLSR_WAIT_ACT) && (seg->act_ms > 0U)) { @@ -162,10 +170,8 @@ static void PlsrRunControlEnterPostWaitOrNext(void) if (seg->wait_type == PLSR_WAIT_SIGNAL) { /* - * 与 WAIT 时间相同:本段已按末段走完(停表),再等条件才 BeginSeg。 - * ※2 导通发生在发完之前:发完立刻下一段。 - * ※3 发完仍未导通:等到导通(消抖后)才下一段。 - * 不在此处清沿/电平,否则会丢掉段中已经导通的状态。 + * 与 WAIT 时间相同:本段发完停表,再等 EXTI 确认后的下降沿。 + * 只认锁存的沿,不读当前电平——口线虚低或脉冲耦合都会误跳下一段。 */ PlsrPulseDriverStop(); s_follow_cont = 0U; @@ -173,7 +179,7 @@ static void PlsrRunControlEnterPostWaitOrNext(void) s_chain_valid = 0U; s_chain_freq = 0U; s_cur_freq = 0U; - if (PlsrSignalIoWaitIsOn() != 0U) + if (PlsrSignalIoTakeWaitFalling() != 0U) { PlsrRunControlGotoNextOrFinish(s_cur_seg); return; @@ -885,6 +891,7 @@ uint8_t PlsrRunControlStart(uint16_t start_seg_1based) s_chain_valid = 0U; s_chain_freq = 0U; s_cur_freq = PlsrRunControlClampSpeed(cfg->start_speed); + PlsrSignalIoClearEdges(); PlsrRunControlBeginSeg((uint16_t)(start_seg_1based - 1U)); return 1U; } diff --git a/plsr/signal_io/plsr_signal_io.c b/plsr/signal_io/plsr_signal_io.c index a3066dd..ead5058 100644 --- a/plsr/signal_io/plsr_signal_io.c +++ b/plsr/signal_io/plsr_signal_io.c @@ -1,10 +1,10 @@ /** * @file plsr_signal_io.c - * @brief WAIT/EXT:EXTI 边沿触发 + TIM3 20ms 消抖确认 + * @brief WAIT/EXT:EXTI 下降沿触发(X4=PB5、X5=PG12) * - * 上拉默认高;外部导通拉低为 ON。 - * 触发仍走 EXTI(升降沿);抖动会连打中断,只把消抖计时清零。 - * TIM3 只在“有待确认沿”时数 20ms,到期再读一次电平,不是平时轮询当主触发。 + * 输入上拉,空闲为高;飞线接地产生下降沿。 + * 触发只认 EXTI,不靠平时扫口。沿到来后等 20ms 再读一次: + * 仍为低才锁存(消抖,并滤掉 Y0 脉冲耦合出的尖峰)。 */ #include "plsr_signal_io.h" #include "plsr_param.h" @@ -22,35 +22,32 @@ #define PLSR_SIGNAL_DEBOUNCE_MS 20U typedef struct { - volatile uint8_t pending; /* EXTI 置位:等待 20ms 后确认 */ - uint8_t wait_ms; /* 距上次沿已过毫秒 */ - uint8_t stable_on; /* 消抖后是否导通 */ - uint8_t rose; /* 消抖确认的 OFF→ON,读清 */ + volatile uint8_t pending; /* EXTI 下降沿,待 20ms 确认 */ + volatile uint8_t wait_ms; + volatile uint8_t fell; /* 确认后的下降沿,读清 */ GPIO_TypeDef *port; uint16_t pin; -} PlsrDebounce_t; +} PlsrEdge_t; static volatile uint32_t s_ms; -static PlsrDebounce_t s_db_x4; -static PlsrDebounce_t s_db_x5; +static PlsrEdge_t s_db_x4; +static PlsrEdge_t s_db_x5; static TIM_HandleTypeDef s_htim3; -static uint8_t PlsrSignalIoPinOnNow(const PlsrDebounce_t *db) +static uint8_t PlsrSignalIoPinIsLow(const PlsrEdge_t *db) { return (HAL_GPIO_ReadPin(db->port, db->pin) == GPIO_PIN_RESET) ? 1U : 0U; } -static void PlsrSignalIoArmDebounce(PlsrDebounce_t *db) +static void PlsrSignalIoOnFalling(PlsrEdge_t *db) { db->pending = 1U; db->wait_ms = 0U; } -static void PlsrSignalIoDebounceConfirm(PlsrDebounce_t *db) +static void PlsrSignalIoDebounceConfirm(PlsrEdge_t *db) { - uint8_t on; - if (db->pending == 0U) { return; @@ -65,15 +62,11 @@ static void PlsrSignalIoDebounceConfirm(PlsrDebounce_t *db) return; } - on = PlsrSignalIoPinOnNow(db); db->pending = 0U; - if (db->stable_on != on) + /* 尖峰/耦合在 20ms 后已回到高,不算触发;飞线接地保持为低才算 */ + if (PlsrSignalIoPinIsLow(db) != 0U) { - if (on != 0U) - { - db->rose = 1U; - } - db->stable_on = on; + db->fell = 1U; } } @@ -85,7 +78,10 @@ static void PlsrSignalIoGpioExtiInit(void) __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_SYSCFG_CLK_ENABLE(); - gpio.Mode = GPIO_MODE_IT_RISING_FALLING; + HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); + HAL_NVIC_DisableIRQ(EXTI15_10_IRQn); + + gpio.Mode = GPIO_MODE_IT_FALLING; gpio.Pull = GPIO_PULLUP; gpio.Speed = GPIO_SPEED_FREQ_LOW; @@ -95,6 +91,11 @@ static void PlsrSignalIoGpioExtiInit(void) gpio.Pin = PLSR_X5_PIN; HAL_GPIO_Init(PLSR_X5_PORT, &gpio); + __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN); + __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN); + NVIC_ClearPendingIRQ(EXTI9_5_IRQn); + NVIC_ClearPendingIRQ(EXTI15_10_IRQn); + HAL_NVIC_SetPriority(EXTI9_5_IRQn, 8, 0); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); HAL_NVIC_SetPriority(EXTI15_10_IRQn, 8, 0); @@ -126,22 +127,24 @@ void PlsrSignalIoInit(void) s_db_x4.pin = PLSR_X4_PIN; s_db_x4.pending = 0U; s_db_x4.wait_ms = 0U; - s_db_x4.stable_on = 0U; - s_db_x4.rose = 0U; + s_db_x4.fell = 0U; s_db_x5.port = PLSR_X5_PORT; s_db_x5.pin = PLSR_X5_PIN; s_db_x5.pending = 0U; s_db_x5.wait_ms = 0U; - s_db_x5.stable_on = 0U; - s_db_x5.rose = 0U; + s_db_x5.fell = 0U; PlsrSignalIoGpioExtiInit(); PlsrSignalIoTim3Init(); - /* 上电已导通时没有沿,补一次确认 */ - PlsrSignalIoArmDebounce(&s_db_x4); - PlsrSignalIoArmDebounce(&s_db_x5); + /* 配置 EXTI 时可能打出假沿,丢掉 */ + __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN); + __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN); + s_db_x4.fell = 0U; + s_db_x4.pending = 0U; + s_db_x5.fell = 0U; + s_db_x5.pending = 0U; } uint32_t PlsrSignalIoGetMs(void) @@ -165,11 +168,13 @@ uint8_t PlsrSignalIoMsReached(uint32_t deadline_ms) void PlsrSignalIoClearEdges(void) { - s_db_x4.rose = 0U; - s_db_x5.rose = 0U; + s_db_x4.fell = 0U; + s_db_x4.pending = 0U; + s_db_x5.fell = 0U; + s_db_x5.pending = 0U; } -static PlsrDebounce_t *PlsrSignalIoDbBySel(uint16_t sel_01) +static PlsrEdge_t *PlsrSignalIoDbBySel(uint16_t sel_01) { return (sel_01 != 0U) ? &s_db_x5 : &s_db_x4; } @@ -177,22 +182,30 @@ static PlsrDebounce_t *PlsrSignalIoDbBySel(uint16_t sel_01) uint8_t PlsrSignalIoWaitIsOn(void) { PlsrCfg_t *cfg = PlsrParamGetCfg(); - return PlsrSignalIoDbBySel(cfg->wait_x_sel)->stable_on; + return PlsrSignalIoPinIsLow(PlsrSignalIoDbBySel(cfg->wait_x_sel)); } uint8_t PlsrSignalIoTakeWaitFalling(void) { - return PlsrSignalIoWaitIsOn(); + PlsrCfg_t *cfg = PlsrParamGetCfg(); + PlsrEdge_t *db = PlsrSignalIoDbBySel(cfg->wait_x_sel); + + if (db->fell != 0U) + { + db->fell = 0U; + return 1U; + } + return 0U; } uint8_t PlsrSignalIoTakeExtFalling(void) { PlsrCfg_t *cfg = PlsrParamGetCfg(); - PlsrDebounce_t *db = PlsrSignalIoDbBySel(cfg->ext_x_sel); + PlsrEdge_t *db = PlsrSignalIoDbBySel(cfg->ext_x_sel); - if (db->rose != 0U) + if (db->fell != 0U) { - db->rose = 0U; + db->fell = 0U; return 1U; } return 0U; @@ -215,7 +228,7 @@ void PlsrSignalIoOnExti9_5(void) if (__HAL_GPIO_EXTI_GET_IT(PLSR_X4_PIN) != 0U) { __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN); - PlsrSignalIoArmDebounce(&s_db_x4); + PlsrSignalIoOnFalling(&s_db_x4); } } @@ -224,6 +237,6 @@ void PlsrSignalIoOnExti15_10(void) if (__HAL_GPIO_EXTI_GET_IT(PLSR_X5_PIN) != 0U) { __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN); - PlsrSignalIoArmDebounce(&s_db_x5); + PlsrSignalIoOnFalling(&s_db_x5); } } diff --git a/plsr/signal_io/plsr_signal_io.h b/plsr/signal_io/plsr_signal_io.h index 88f1b68..9a2f731 100644 --- a/plsr/signal_io/plsr_signal_io.h +++ b/plsr/signal_io/plsr_signal_io.h @@ -1,10 +1,9 @@ /** * @file plsr_signal_io.h - * @brief 等待/EXT 输入(X4=PB5、X5=PG12)软件消抖 + TIM3 1ms 时基 + * @brief 等待/EXT 输入(X4=PB5、X5=PG12) * * 公共参数:wait_x_sel / ext_x_sel:0=X4,1=X5。 - * 上拉默认高,外部导通拉低 = ON。 - * 边沿由 EXTI 触发;TIM3 仅在有沿之后数 20ms 再读电平确认(消抖)。 + * 上拉空闲为高;飞线接地产生下降沿,由 EXTI 触发(不轮询)。 */ #ifndef PLSR_SIGNAL_IO_H #define PLSR_SIGNAL_IO_H @@ -22,20 +21,20 @@ uint32_t PlsrSignalIoDeadlineFromNow(uint32_t ms); /** 1=已到或过期(含无符号环绕) */ uint8_t PlsrSignalIoMsReached(uint32_t deadline_ms); -/** 清 WAIT/EXT 的 OFF→ON 锁存(不影响当前消抖电平) */ +/** 清 WAIT/EXT 下降沿锁存 */ void PlsrSignalIoClearEdges(void); -/** WAIT 所选口消抖后是否导通 */ +/** WAIT 口当前是否为低(已接地)。仅段末判断※2 时读一次,不作周期轮询触发 */ uint8_t PlsrSignalIoWaitIsOn(void); /** - * WAIT:消抖后已导通则 1(电平,不读清)。 - * ※2 段中已导通 → 发完立刻下一段;※3 未导通则一直等。 + * WAIT:消耗一次已确认的 EXTI 下降沿。 + * ※2 段中飞线接地并保持 → 发完立刻下一段;※3 未触发则一直等。 */ uint8_t PlsrSignalIoTakeWaitFalling(void); /** - * EXT:消抖后 OFF→ON,读清。一次按压只切一次段。 + * EXT:消耗一次 EXTI 下降沿锁存。一次按压只切一次段。 */ uint8_t PlsrSignalIoTakeExtFalling(void);