From 9cfefb35011445cebb5643c90800ad796667bb6a Mon Sep 17 00:00:00 2001 From: hanyongwei <2043702190@qq.com> Date: Tue, 18 Aug 2026 10:01:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3wait=E4=BF=A1=E5=8F=B7?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?wait=E4=BF=A1=E5=8F=B7=E8=A7=A6=E5=8F=91=E8=BD=AF=E4=BB=B6?= =?UTF-8?q?=E6=B6=88=E6=8A=96=E3=80=82=E6=AE=B5=E6=9C=AA=E5=8F=91=E5=AE=8C?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=90=8E=EF=BC=8C=E6=AE=B5=E5=8F=91=E5=AE=8C?= =?UTF-8?q?=E7=AB=8B=E5=88=BB=E8=BF=9B=E4=B8=8B=E4=B8=80=E6=AE=B5=E3=80=82?= =?UTF-8?q?=E6=AE=B5=E5=8F=91=E5=AE=8C=E6=9C=AA=E8=A7=A6=E5=8F=91=E5=88=99?= =?UTF-8?q?=E7=AD=89=E5=BE=85=E8=A7=A6=E5=8F=91=E3=80=82=E6=AF=8F=E4=B8=80?= =?UTF-8?q?=E6=AE=B5=E9=83=BD=E8=B5=B0=E8=BF=9E=E7=BB=AD=E6=AE=B5=E7=9A=84?= =?UTF-8?q?=E6=9C=80=E5=90=8E=E4=B8=80=E6=AE=B5=E7=9A=84=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E6=9C=89=E5=87=8F=E9=80=9F=E9=98=B6=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hanyongwei <2043702190@qq.com> --- plsr/param/plsr_param.h | 2 +- plsr/run_control/plsr_run_control.c | 12 ++- plsr/signal_io/plsr_signal_io.c | 136 +++++++++++++++++++++------- plsr/signal_io/plsr_signal_io.h | 19 ++-- 4 files changed, 124 insertions(+), 45 deletions(-) diff --git a/plsr/param/plsr_param.h b/plsr/param/plsr_param.h index 77d84cb..54fcc00 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 口下降沿,再跳转 */ + PLSR_WAIT_SIGNAL = 1, /* 发完后等 WAIT 口导通(20ms 消抖),再跳转 */ PLSR_WAIT_ACT = 2, /* 出脉冲满 act_ms 后中途切段并立即跳转 */ PLSR_WAIT_EXT = 3, /* 运行中 EXT 下降沿中途切段并立即跳转 */ PLSR_WAIT_EXT_OR_DONE = 4 /* EXT 沿或脉冲发完,先到先跳转 */ diff --git a/plsr/run_control/plsr_run_control.c b/plsr/run_control/plsr_run_control.c index ef39e4a..7ca7b8e 100644 --- a/plsr/run_control/plsr_run_control.c +++ b/plsr/run_control/plsr_run_control.c @@ -161,13 +161,23 @@ static void PlsrRunControlEnterPostWaitOrNext(void) } if (seg->wait_type == PLSR_WAIT_SIGNAL) { + /* + * 与 WAIT 时间相同:本段已按末段走完(停表),再等条件才 BeginSeg。 + * ※2 导通发生在发完之前:发完立刻下一段。 + * ※3 发完仍未导通:等到导通(消抖后)才下一段。 + * 不在此处清沿/电平,否则会丢掉段中已经导通的状态。 + */ PlsrPulseDriverStop(); s_follow_cont = 0U; s_pwm_on = 0U; s_chain_valid = 0U; s_chain_freq = 0U; s_cur_freq = 0U; - PlsrSignalIoClearEdges(); + if (PlsrSignalIoWaitIsOn() != 0U) + { + PlsrRunControlGotoNextOrFinish(s_cur_seg); + return; + } s_wait_is_signal = 1U; s_state = RC_WAIT_COND; return; diff --git a/plsr/signal_io/plsr_signal_io.c b/plsr/signal_io/plsr_signal_io.c index e89edf3..a3066dd 100644 --- a/plsr/signal_io/plsr_signal_io.c +++ b/plsr/signal_io/plsr_signal_io.c @@ -1,30 +1,82 @@ /** * @file plsr_signal_io.c - * @brief X4/X5 EXTI 下降沿 + TIM3 1ms + * @brief WAIT/EXT:EXTI 边沿触发 + TIM3 20ms 消抖确认 + * + * 上拉默认高;外部导通拉低为 ON。 + * 触发仍走 EXTI(升降沿);抖动会连打中断,只把消抖计时清零。 + * TIM3 只在“有待确认沿”时数 20ms,到期再读一次电平,不是平时轮询当主触发。 */ #include "plsr_signal_io.h" #include "plsr_param.h" #include "plsr_run_control.h" #include "main.h" -/* X4=PB5 → EXTI5;X5=PG12 → EXTI12 */ #define PLSR_X4_PORT GPIOB #define PLSR_X4_PIN GPIO_PIN_5 #define PLSR_X5_PORT GPIOG #define PLSR_X5_PIN GPIO_PIN_12 -/* - * APB1=42MHz → TIM3CLK=84MHz;PSC=83 ARR=999 → 1kHz 更新 - */ #define PLSR_TIM3_PSC 83U #define PLSR_TIM3_ARR 999U +#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,读清 */ + GPIO_TypeDef *port; + uint16_t pin; +} PlsrDebounce_t; + static volatile uint32_t s_ms; -static volatile uint8_t s_fall_x4; -static volatile uint8_t s_fall_x5; +static PlsrDebounce_t s_db_x4; +static PlsrDebounce_t s_db_x5; static TIM_HandleTypeDef s_htim3; +static uint8_t PlsrSignalIoPinOnNow(const PlsrDebounce_t *db) +{ + return (HAL_GPIO_ReadPin(db->port, db->pin) == GPIO_PIN_RESET) ? 1U : 0U; +} + +static void PlsrSignalIoArmDebounce(PlsrDebounce_t *db) +{ + db->pending = 1U; + db->wait_ms = 0U; +} + +static void PlsrSignalIoDebounceConfirm(PlsrDebounce_t *db) +{ + uint8_t on; + + if (db->pending == 0U) + { + return; + } + + if (db->wait_ms < 0xFFU) + { + db->wait_ms++; + } + if (db->wait_ms < PLSR_SIGNAL_DEBOUNCE_MS) + { + return; + } + + on = PlsrSignalIoPinOnNow(db); + db->pending = 0U; + if (db->stable_on != on) + { + if (on != 0U) + { + db->rose = 1U; + } + db->stable_on = on; + } +} + static void PlsrSignalIoGpioExtiInit(void) { GPIO_InitTypeDef gpio = {0}; @@ -33,7 +85,7 @@ static void PlsrSignalIoGpioExtiInit(void) __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_SYSCFG_CLK_ENABLE(); - gpio.Mode = GPIO_MODE_IT_FALLING; + gpio.Mode = GPIO_MODE_IT_RISING_FALLING; gpio.Pull = GPIO_PULLUP; gpio.Speed = GPIO_SPEED_FREQ_LOW; @@ -69,10 +121,27 @@ static void PlsrSignalIoTim3Init(void) void PlsrSignalIoInit(void) { s_ms = 0U; - s_fall_x4 = 0U; - s_fall_x5 = 0U; + + s_db_x4.port = PLSR_X4_PORT; + 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_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; + PlsrSignalIoGpioExtiInit(); PlsrSignalIoTim3Init(); + + /* 上电已导通时没有沿,补一次确认 */ + PlsrSignalIoArmDebounce(&s_db_x4); + PlsrSignalIoArmDebounce(&s_db_x5); } uint32_t PlsrSignalIoGetMs(void) @@ -96,39 +165,37 @@ uint8_t PlsrSignalIoMsReached(uint32_t deadline_ms) void PlsrSignalIoClearEdges(void) { - s_fall_x4 = 0U; - s_fall_x5 = 0U; + s_db_x4.rose = 0U; + s_db_x5.rose = 0U; } -static uint8_t PlsrSignalIoTakePinFalling(uint16_t sel_01) +static PlsrDebounce_t *PlsrSignalIoDbBySel(uint16_t sel_01) { - if (sel_01 != 0U) - { - if (s_fall_x5 != 0U) - { - s_fall_x5 = 0U; - return 1U; - } - return 0U; - } - if (s_fall_x4 != 0U) - { - s_fall_x4 = 0U; - return 1U; - } - return 0U; + return (sel_01 != 0U) ? &s_db_x5 : &s_db_x4; } -uint8_t PlsrSignalIoTakeWaitFalling(void) +uint8_t PlsrSignalIoWaitIsOn(void) { PlsrCfg_t *cfg = PlsrParamGetCfg(); - return PlsrSignalIoTakePinFalling(cfg->wait_x_sel); + return PlsrSignalIoDbBySel(cfg->wait_x_sel)->stable_on; +} + +uint8_t PlsrSignalIoTakeWaitFalling(void) +{ + return PlsrSignalIoWaitIsOn(); } uint8_t PlsrSignalIoTakeExtFalling(void) { PlsrCfg_t *cfg = PlsrParamGetCfg(); - return PlsrSignalIoTakePinFalling(cfg->ext_x_sel); + PlsrDebounce_t *db = PlsrSignalIoDbBySel(cfg->ext_x_sel); + + if (db->rose != 0U) + { + db->rose = 0U; + return 1U; + } + return 0U; } void PlsrSignalIoOnTim3Irq(void) @@ -137,7 +204,8 @@ void PlsrSignalIoOnTim3Irq(void) { TIM3->SR = (uint32_t)~TIM_SR_UIF; s_ms++; - /* 升降速:1ms 更新一次输出频率 */ + PlsrSignalIoDebounceConfirm(&s_db_x4); + PlsrSignalIoDebounceConfirm(&s_db_x5); PlsrRunControlOn1ms(); } } @@ -147,7 +215,7 @@ void PlsrSignalIoOnExti9_5(void) if (__HAL_GPIO_EXTI_GET_IT(PLSR_X4_PIN) != 0U) { __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN); - s_fall_x4 = 1U; + PlsrSignalIoArmDebounce(&s_db_x4); } } @@ -156,6 +224,6 @@ void PlsrSignalIoOnExti15_10(void) if (__HAL_GPIO_EXTI_GET_IT(PLSR_X5_PIN) != 0U) { __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN); - s_fall_x5 = 1U; + PlsrSignalIoArmDebounce(&s_db_x5); } } diff --git a/plsr/signal_io/plsr_signal_io.h b/plsr/signal_io/plsr_signal_io.h index dfacb5a..88f1b68 100644 --- a/plsr/signal_io/plsr_signal_io.h +++ b/plsr/signal_io/plsr_signal_io.h @@ -1,10 +1,10 @@ /** * @file plsr_signal_io.h - * @brief 等待/EXT 输入(X4=PB5、X5=PG12 EXTI)+ TIM3 1ms 时基(WAIT/ACT) + * @brief 等待/EXT 输入(X4=PB5、X5=PG12)软件消抖 + TIM3 1ms 时基 * * 公共参数:wait_x_sel / ext_x_sel:0=X4,1=X5。 - * 引脚上拉默认高,外部拉低 → 下降沿触发。 - * TIM3 仅作毫秒计数,不占用 TIM10/11/13/14。 + * 上拉默认高,外部导通拉低 = ON。 + * 边沿由 EXTI 触发;TIM3 仅在有沿之后数 20ms 再读电平确认(消抖)。 */ #ifndef PLSR_SIGNAL_IO_H #define PLSR_SIGNAL_IO_H @@ -22,22 +22,23 @@ uint32_t PlsrSignalIoDeadlineFromNow(uint32_t ms); /** 1=已到或过期(含无符号环绕) */ uint8_t PlsrSignalIoMsReached(uint32_t deadline_ms); -/** 清 X4/X5 下降沿锁存 */ +/** 清 WAIT/EXT 的 OFF→ON 锁存(不影响当前消抖电平) */ void PlsrSignalIoClearEdges(void); +/** WAIT 所选口消抖后是否导通 */ +uint8_t PlsrSignalIoWaitIsOn(void); + /** - * 取并清除 WAIT 所选口的下降沿(按 cfg->wait_x_sel) - * @return 1=本次取到沿 + * WAIT:消抖后已导通则 1(电平,不读清)。 + * ※2 段中已导通 → 发完立刻下一段;※3 未导通则一直等。 */ uint8_t PlsrSignalIoTakeWaitFalling(void); /** - * 取并清除 EXT 所选口的下降沿(按 cfg->ext_x_sel) - * @return 1=本次取到沿 + * EXT:消抖后 OFF→ON,读清。一次按压只切一次段。 */ uint8_t PlsrSignalIoTakeExtFalling(void); -/* 由 stm32f4xx_it.c 转发 */ void PlsrSignalIoOnTim3Irq(void); void PlsrSignalIoOnExti9_5(void); void PlsrSignalIoOnExti15_10(void);