瀏覽代碼

修复起始频率大于目标频率时从起始频率减速

Signed-off-by: hanyongwei <2043702190@qq.com>
dev1
hanyongwei 3 週之前
父節點
當前提交
e00bd1bcaa
共有 6 個檔案被更改,包括 174 行新增42 行删除
  1. +2
    -2
      iar/plsr.dep
  2. +23
    -5
      plsr/accel_curve/plsr_accel_curve.c
  3. +1
    -1
      plsr/accel_curve/plsr_accel_curve.h
  4. +31
    -5
      plsr/run_control/plsr_run_control.c
  5. +51
    -20
      plsr/signal_io/plsr_signal_io.c
  6. +66
    -9
      plsr/signal_io/plsr_signal_io.h

+ 2
- 2
iar/plsr.dep 查看文件

@@ -1509,7 +1509,7 @@
<inputs> <inputs>
<tool> <tool>
<name>ICCARM</name> <name>ICCARM</name>
<file> 299 159 195 448 426 360 212 282 289 11 9 223 12 4 2 10 3 16 0 142 17 6 7 8 184 149 221 230 231 232 13 227 1 233 229 228 226 222 224 225 219 374 392 377 70 173 387 401 368 347 39 216</file>
<file> 299 159 195 448 426 360 212 282 386 289 11 9 223 12 4 2 10 3 16 0 142 17 6 7 8 184 149 221 230 231 232 13 227 1 233 229 228 226 222 224 225 219 374 392 377 70 173 387 401 368 347 39 216</file>
</tool> </tool>
</inputs> </inputs>
</file> </file>
@@ -1682,7 +1682,7 @@
<inputs> <inputs>
<tool> <tool>
<name>ICCARM</name> <name>ICCARM</name>
<file> 289 11 9 223 12 4 2 10 159 195 448 426 360 212 3 16 0 142 17 6 7 8 184 149 221 230 231 232 13 227 1 233 229 228 226 222 224 225 219 374 392 377 70 173 387 401 368 347 39 216 381 299 399 5 15 386</file>
<file> 289 11 9 223 12 4 2 10 159 195 448 426 360 212 3 16 0 142 17 6 7 8 184 149 221 230 231 232 13 227 1 233 229 228 226 222 224 225 219 374 392 377 70 173 387 401 368 347 39 216 381 299 399 5 15 386 282</file>
</tool> </tool>
</inputs> </inputs>
</file> </file>


+ 23
- 5
plsr/accel_curve/plsr_accel_curve.c 查看文件

@@ -488,12 +488,13 @@ static uint32_t PlsrAccelCurveFitPeak(uint32_t total_pulses,
if (f_want >= f_cur) if (f_want >= f_cur)
{ {
peak = f_cur + mid; peak = f_cur + mid;
n_a = PlsrAccelCurvePulsesForRamp(f_cur, peak, a_acc);
} }
else else
{ {
peak = f_cur - mid; peak = f_cur - mid;
n_a = PlsrAccelCurvePulsesForRamp(f_cur, peak, a_dec);
} }
n_a = PlsrAccelCurvePulsesForRamp(f_cur, peak, a_acc);
n_d = PlsrAccelCurvePulsesForRamp(peak, f_end, a_dec); n_d = PlsrAccelCurvePulsesForRamp(peak, f_end, a_dec);


if ((n_a + n_d) <= total_pulses) if ((n_a + n_d) <= total_pulses)
@@ -602,7 +603,15 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan,
plan->a_acc = a_acc; plan->a_acc = a_acc;
plan->a_dec = a_dec; plan->a_dec = a_dec;


acc_n = PlsrAccelCurvePulsesForRamp(f_cur, f_peak, a_acc);
if (f_cur > f_peak)
{
/* 入口高于峰值:首相为减速,用 a_dec(与 rampTimeMs 减速分支一致) */
acc_n = PlsrAccelCurvePulsesForRamp(f_cur, f_peak, a_dec);
}
else
{
acc_n = PlsrAccelCurvePulsesForRamp(f_cur, f_peak, a_acc);
}
dec_n = PlsrAccelCurvePulsesForRamp(f_peak, f_end, a_dec); dec_n = PlsrAccelCurvePulsesForRamp(f_peak, f_end, a_dec);


if (total_pulses == 0U) if (total_pulses == 0U)
@@ -627,7 +636,14 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan,
{ {
f_peak = PlsrAccelCurveFitPeak(total_pulses, f_cur, f_tgt, f_end, f_peak = PlsrAccelCurveFitPeak(total_pulses, f_cur, f_tgt, f_end,
a_acc, a_dec); a_acc, a_dec);
acc_n = PlsrAccelCurvePulsesForRamp(f_cur, f_peak, a_acc);
if (f_cur > f_peak)
{
acc_n = PlsrAccelCurvePulsesForRamp(f_cur, f_peak, a_dec);
}
else
{
acc_n = PlsrAccelCurvePulsesForRamp(f_cur, f_peak, a_acc);
}
dec_n = PlsrAccelCurvePulsesForRamp(f_peak, f_end, a_dec); dec_n = PlsrAccelCurvePulsesForRamp(f_peak, f_end, a_dec);
if (acc_n > total_pulses) if (acc_n > total_pulses)
{ {
@@ -701,7 +717,9 @@ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan,
rising = (plan->f_tgt >= plan->f_cur) ? 1U : 0U; rising = (plan->f_tgt >= plan->f_cur) ? 1U : 0U;
if (plan->mode == PLSR_ACCEL_LINEAR) if (plan->mode == PLSR_ACCEL_LINEAR)
{ {
f = PlsrAccelCurveFreqKinematic(plan->f_cur, plan->a_acc,
uint32_t a_use = (rising != 0U) ? plan->a_acc : plan->a_dec;

f = PlsrAccelCurveFreqKinematic(plan->f_cur, a_use,
pulse_done, rising, plan->f_tgt); pulse_done, rising, plan->f_tgt);
} }
else else
@@ -785,10 +803,10 @@ void PlsrAccelPulseRtBeginAcc(PlsrAccelPulseRt_t *rt,
rt->f0 = plan->f_cur; rt->f0 = plan->f_cur;
rt->f1 = plan->f_tgt; rt->f1 = plan->f_tgt;
rt->f = plan->f_cur; rt->f = plan->f_cur;
rt->a = plan->a_acc;
rt->n = 0U; rt->n = 0U;
rt->n_total = plan->acc_n; rt->n_total = plan->acc_n;
rt->rising = (plan->f_tgt >= plan->f_cur) ? 1U : 0U; rt->rising = (plan->f_tgt >= plan->f_cur) ? 1U : 0U;
rt->a = (rt->rising != 0U) ? plan->a_acc : plan->a_dec;
rt->mode = plan->mode; rt->mode = plan->mode;
rt->active = (plan->acc_n > 0U) && (plan->f_cur != plan->f_tgt) ? 1U : 0U; rt->active = (plan->acc_n > 0U) && (plan->f_cur != plan->f_tgt) ? 1U : 0U;
PlsrAccelPulseRtSetupShape(rt, rt->n_total); PlsrAccelPulseRtSetupShape(rt, rt->n_total);


+ 1
- 1
plsr/accel_curve/plsr_accel_curve.h 查看文件

@@ -32,7 +32,7 @@ typedef struct {
PlsrAccelMode_e mode; /* 直线 / S / 正弦 */ PlsrAccelMode_e mode; /* 直线 / S / 正弦 */
} PlsrAccelPlan_t; } PlsrAccelPlan_t;


/** 配置起速 → 规划用真实起点(Jump;起速 0 也不从 0Hz 开跑) */
/** 配置起速 → 规划用真实起点(0=Jump 起跳;非 0 且 >f_tgt 则直接用起速走减速) */
uint32_t PlsrAccelCurveResolveStartHz(uint32_t f_cfg, uint32_t PlsrAccelCurveResolveStartHz(uint32_t f_cfg,
uint32_t f_tgt, uint32_t f_tgt,
uint32_t default_spd, uint32_t default_spd,


+ 31
- 5
plsr/run_control/plsr_run_control.c 查看文件

@@ -136,6 +136,10 @@ static uint32_t s_plan_acc_n; /* PlanSeg 锁定加速脉冲预算
static uint32_t s_plan_dec_n; /* PlanSeg 锁定减速脉冲预算 */ static uint32_t s_plan_dec_n; /* PlanSeg 锁定减速脉冲预算 */
static uint32_t s_decel_budget; /* EnterDecel 时锁定的减速步进预算 */ static uint32_t s_decel_budget; /* EnterDecel 时锁定的减速步进预算 */


/** 本次 Start 的启动段(0-based);仅该段首次冷启动可套用「起速>目标」入口规则 */
static uint16_t s_run_entry_seg0;
static uint8_t s_run_first_entry;

/** /**
* 策略层解析后交给 PlanSeg 的段端点(不含 wait_type,仅频率与时间) * 策略层解析后交给 PlanSeg 的段端点(不含 wait_type,仅频率与时间)
*/ */
@@ -667,11 +671,29 @@ static uint8_t PlsrRunControlResolveSegPlanEndpoints(uint16_t seg_idx0, uint32_t
} }
else else
{ {
endpoints->freq_start_hz = PlsrAccelCurveResolveStartHz(cfg->start_speed,
f_tgt,
cfg->default_speed,
endpoints->accel_ms,
endpoints->decel_ms);
/*
* 停表后冷启动:仅本次运行的启动段、且目标频低于配置起速时,
* 入口直接用起速(再规划减速到目标);其余仍走起跳频率。
*/
if ((s_run_first_entry != 0U) &&
(seg_idx0 == s_run_entry_seg0) &&
(cfg->start_speed >= 1U) && (f_tgt < cfg->start_speed))
{
s_run_first_entry = 0U;
endpoints->freq_start_hz = PlsrRunControlClampSpeed(cfg->start_speed);
}
else
{
if ((s_run_first_entry != 0U) && (seg_idx0 == s_run_entry_seg0))
{
s_run_first_entry = 0U;
}
endpoints->freq_start_hz = PlsrAccelCurveResolveStartHz(cfg->start_speed,
f_tgt,
cfg->default_speed,
endpoints->accel_ms,
endpoints->decel_ms);
}
} }


/* /*
@@ -1261,6 +1283,7 @@ static void PlsrRunControlFinishAll(void)
s_wait_expire_req = 0U; s_wait_expire_req = 0U;
s_act_time_ms = 0U; s_act_time_ms = 0U;
s_last_period_wait = 0U; s_last_period_wait = 0U;
s_run_first_entry = 0U;
} }


/** /**
@@ -1554,6 +1577,8 @@ uint8_t PlsrRunControlStart(uint16_t start_seg_1based)
s_follow_cont = 0U; s_follow_cont = 0U;
s_chain_valid = 0U; s_chain_valid = 0U;
s_chain_freq = 0U; s_chain_freq = 0U;
s_run_entry_seg0 = (uint16_t)(start_seg_1based - 1U);
s_run_first_entry = 1U;
s_cur_freq = PlsrRunControlClampSpeed(cfg->start_speed); s_cur_freq = PlsrRunControlClampSpeed(cfg->start_speed);
/* /*
* 绝对原点:仅在首次 Start(或 ClearAccPulse 之后的第一次)锁定。 * 绝对原点:仅在首次 Start(或 ClearAccPulse 之后的第一次)锁定。
@@ -1592,6 +1617,7 @@ void PlsrRunControlStop(void)
s_wait_expire_req = 0U;/*段后等待到期请求标志*/ s_wait_expire_req = 0U;/*段后等待到期请求标志*/
s_act_time_ms = 0U;/*本段 ACT 定时时长*/ s_act_time_ms = 0U;/*本段 ACT 定时时长*/
s_last_period_wait = 0U; s_last_period_wait = 0U;
s_run_first_entry = 0U;
} }


/** @brief 运行中改频(见 plsr_run_control.h) */ /** @brief 运行中改频(见 plsr_run_control.h) */


+ 51
- 20
plsr/signal_io/plsr_signal_io.c 查看文件

@@ -2,11 +2,29 @@
* @file plsr_signal_io.c * @file plsr_signal_io.c
* @brief WAIT/EXT 输入 + TIM5 单次延时 + OS 节拍消抖 * @brief WAIT/EXT 输入 + TIM5 单次延时 + OS 节拍消抖
* *
* @details
* EXTI 下降沿 → pending;DebouncePoll 满约 20ms 且仍低 → fell。
* TIM5(32 位,APB1 84MHz):有延时才开表。
* PSC=8399 → 10kHz(1 次计数 = 100µs)
* ARR = delay_ms×10 − 1 → 一次溢出 = 设定的 ms(分辨率 0.1ms,够用)
* @details 实现要点
* 【EXTI 输入】
* X4=PB5 → EXTI9_5;X5=PG12 → EXTI15_10。
* 下降沿触发 OnFalling:仅 pending=1,不在 ISR 里判有效(避免抖动/毛刺)。
*
* 【消抖】
* DebouncePoll(任务上下文,约 1ms 一次):
* pending 且首次 → 记 arm_tick;
* 满 PLSR_SIGNAL_DEBOUNCE_MS(20ms)且 PinIsLow → fell=1。
* 上升沿恢复高电平则 Confirm 末尾不置 fell(pending 被清掉)。
*
* 【TIM5 单次延时】
* 32 位 TIM5,APB1 84MHz;仅在有延时时开表(URS+OPM)。
* PSC=8399 → 10kHz(1 计数 = 100µs);ARR = delay_ms×10 − 1。
* 一次 UPDATE 溢出 = delay_ms;中断内 Cancel 并 PlsrRunControlOnDelayTimer()。
*
* 【与 run_control 配合】
* ScheduleDelayMs :方向延时 / WAIT 时间 / ACT 定时
* TakeExtFalling :RUN 中 EXT 切段、WAIT_COND 等
* TakeWaitFalling :WAIT 信号段后等待
* ClearEdges :EXT 段开跑前丢旧沿
* ClearPending :纯 EXT 段末保留 fell、清 pending
* DelayRemainMs :ACT 脉冲先完后续装剩余时间
*/ */
#include "plsr_signal_io.h" #include "plsr_signal_io.h"
#include "plsr_param.h" #include "plsr_param.h"
@@ -14,34 +32,38 @@
#include "main.h" #include "main.h"
#include "ucos_ii.h" #include "ucos_ii.h"


/* ---------- 硬件引脚(与 CubeMX / 方案书一致) ---------- */
#define PLSR_X4_PORT GPIOB #define PLSR_X4_PORT GPIOB
#define PLSR_X4_PIN GPIO_PIN_5
#define PLSR_X4_PIN GPIO_PIN_5 /* X4:WAIT/EXT 可选 */
#define PLSR_X5_PORT GPIOG #define PLSR_X5_PORT GPIOG
#define PLSR_X5_PIN GPIO_PIN_12
#define PLSR_X5_PIN GPIO_PIN_12 /* X5:WAIT/EXT 可选 */


/* /*
* 84MHz / 8400 = 10kHz → 100µs/格。
* PSC=8399 落在 16 位内;不必用 1µs(那只是为了硬凑,ms 延时用不上)
* TIM5 时基:84MHz / (8399+1) = 10kHz → 100µs/格。
* PSC=8399 落在 16 位内;ms 级延时用 100µs 分辨率足够,不必 1µs 时基
*/ */
#define PLSR_TIM5_PSC_100US 8399U
#define PLSR_TIM5_TICKS_PER_MS 10U /* 10×100µs = 1ms */
#define PLSR_DELAY_MS_MAX 65535U
#define PLSR_TIM5_PSC_100US 8399U
#define PLSR_TIM5_TICKS_PER_MS 10U /* 10×100µs = 1ms */
#define PLSR_DELAY_MS_MAX 65535U


/** OS 节拍消抖窗口(ms),与 PlsrTask tick 配合 */
#define PLSR_SIGNAL_DEBOUNCE_MS 20U #define PLSR_SIGNAL_DEBOUNCE_MS 20U


/** 单路 X 口消抖状态(pending / fell 由 ISR 与任务共享,volatile) */
typedef struct { typedef struct {
volatile uint8_t pending;
volatile uint8_t stamp_ok;
volatile INT32U arm_tick;
volatile uint8_t fell;
volatile uint8_t pending; /* 1=EXTI 已见下降沿,待 Confirm */
volatile uint8_t stamp_ok; /* 1=已记 arm_tick,正在计时 */
volatile INT32U arm_tick; /* 消抖起点 OS tick */
volatile uint8_t fell; /* 1=消抖确认的有效下降沿,Take* 消费 */
GPIO_TypeDef *port; GPIO_TypeDef *port;
uint16_t pin; uint16_t pin;
} PlsrEdge_t; } PlsrEdge_t;


static PlsrEdge_t s_db_x4; /* X4 输入消抖状态(WAIT/EXT 共用) */
static PlsrEdge_t s_db_x5; /* X5 输入消抖状态 */
static volatile uint8_t s_delay_armed; /* 1=TIM5 单次延时正在计时 */
static PlsrEdge_t s_db_x4; /* X4 消抖状态 */
static PlsrEdge_t s_db_x5; /* X5 消抖状态 */
static volatile uint8_t s_delay_armed; /* 1=TIM5 单次延时正在计时 */


/** 毫秒 → OS tick 数(向上取整,至少 1 tick) */
static INT32U PlsrSignalIoMsToTicks(uint32_t ms) static INT32U PlsrSignalIoMsToTicks(uint32_t ms)
{ {
INT32U t; INT32U t;
@@ -58,17 +80,23 @@ static INT32U PlsrSignalIoMsToTicks(uint32_t ms)
return t; return t;
} }


/** @return 1=脚当前为低(有效按下/接地) */
static uint8_t PlsrSignalIoPinIsLow(const PlsrEdge_t *db) static uint8_t PlsrSignalIoPinIsLow(const PlsrEdge_t *db)
{ {
return (HAL_GPIO_ReadPin(db->port, db->pin) == GPIO_PIN_RESET) ? 1U : 0U; return (HAL_GPIO_ReadPin(db->port, db->pin) == GPIO_PIN_RESET) ? 1U : 0U;
} }


/** EXTI 下降沿:仅置 pending,消抖在 DebouncePoll 完成 */
static void PlsrSignalIoOnFalling(PlsrEdge_t *db) static void PlsrSignalIoOnFalling(PlsrEdge_t *db)
{ {
db->pending = 1U; db->pending = 1U;
db->stamp_ok = 0U; db->stamp_ok = 0U;
} }


/**
* @brief 单路消抖确认(DebouncePoll 每 tick 调用)
* @note 满 debounce_ms 仍低 → fell;否则丢弃 pending
*/
static void PlsrSignalIoDebounceConfirm(PlsrEdge_t *db) static void PlsrSignalIoDebounceConfirm(PlsrEdge_t *db)
{ {
INT32U need; INT32U need;
@@ -99,6 +127,7 @@ static void PlsrSignalIoDebounceConfirm(PlsrEdge_t *db)
} }
} }


/** X4/X5:下降沿 EXTI + 上拉;先关 NVIC 再配 GPIO,避免配置期间误触发 */
static void PlsrSignalIoGpioExtiInit(void) static void PlsrSignalIoGpioExtiInit(void)
{ {
GPIO_InitTypeDef gpio = {0}; GPIO_InitTypeDef gpio = {0};
@@ -130,6 +159,7 @@ static void PlsrSignalIoGpioExtiInit(void)
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
} }


/** TIM5:预配 PSC/最大 ARR,默认停表;ScheduleDelayMs 时再装 ARR 并 OPM 启动 */
static void PlsrSignalIoTim5Init(void) static void PlsrSignalIoTim5Init(void)
{ {
__HAL_RCC_TIM5_CLK_ENABLE(); __HAL_RCC_TIM5_CLK_ENABLE();
@@ -189,7 +219,7 @@ void PlsrSignalIoScheduleDelayMs(uint32_t delay_ms)
delay_ms = PLSR_DELAY_MS_MAX; delay_ms = PLSR_DELAY_MS_MAX;
} }


/* N ms → N×10 个 100µs 格 */
/* N ms → N×10 个 100µs 格;OPM 计满一次 UPDATE 即到期 */
ticks = delay_ms * PLSR_TIM5_TICKS_PER_MS; ticks = delay_ms * PLSR_TIM5_TICKS_PER_MS;


TIM5->CR1 = 0U; TIM5->CR1 = 0U;
@@ -263,6 +293,7 @@ void PlsrSignalIoClearPending(void)
s_db_x5.stamp_ok = 0U; s_db_x5.stamp_ok = 0U;
} }


/** wait_x_sel / ext_x_sel:0→X4,非 0→X5 */
static PlsrEdge_t *PlsrSignalIoDbBySel(uint16_t sel_01) static PlsrEdge_t *PlsrSignalIoDbBySel(uint16_t sel_01)
{ {
return (sel_01 != 0U) ? &s_db_x5 : &s_db_x4; return (sel_01 != 0U) ? &s_db_x5 : &s_db_x4;


+ 66
- 9
plsr/signal_io/plsr_signal_io.h 查看文件

@@ -3,48 +3,105 @@
* @brief WAIT/EXT 外部输入与 TIM5 单次延时 * @brief WAIT/EXT 外部输入与 TIM5 单次延时
* *
* @details 模块职责 * @details 模块职责
* 1. 配置 X4=PB5、X5=PG12 为下降沿 EXTI(上拉空闲高,飞线接地出沿);
* 2. 消抖:EXTI 置 pending,任务侧按 OS 节拍确认 20ms 仍低 → fell;
* 3. TIM5(32 位)仅在有延时时开启:100µs 时基,ARR=ms×10−1,
* 一次计满 = 设定 ms(最长 65535ms),到期 UPDATE → OnDelayTimer。
* 1. 配置 X4=PB5、X5=PG12 为下降沿 EXTI(内部上拉,空闲高;飞线/触点接地出有效沿);
* 2. 消抖:EXTI 仅置 pending,任务侧 DebouncePoll 按 OS 节拍确认约 20ms 仍低 → fell;
* 3. TIM5(32 位)按需单次计时:100µs 时基,ARR=ms×10−1,一次 UPDATE = 设定 ms
* (最长 65535ms);到期回调 run_control::OnDelayTimer。
*
* 硬件与参数映射
* X4 (PB5, EXTI9_5) / X5 (PG12, EXTI15_10)
* wait_x_sel (0x1002) → 0=X4,1=X5,供 WAIT 信号等待(PLSR_WAIT_SIGNAL)
* ext_x_sel (0x1003) → 0=X4,1=X5,供 EXT 切段(PLSR_WAIT_EXT / EXT_OR_DONE)
* WAIT 与 EXT 可独立选口,共用同一套消抖状态机。
*
* 消抖状态机(每路 PlsrEdge_t)
* pending=1 ← EXTI 下降沿
* DebouncePoll:首次见 pending 记 arm_tick;满 20ms 且脚仍低 → fell=1
* Take*Falling 消费 fell;ClearPending 只清 pending/stamp,保留已确认 fell
*
* TIM5 单次延时用途(run_control 调用)
* - 方向切换延时 dir_delay_ms(RC_DIR_WAIT → Start)
* - WAIT 时间 PLSR_WAIT_TIME 段后等待
* - ACT 时间 PLSR_WAIT_ACT 段内定时(到期 OPM 收当前拍再切段)
* - ACT 脉冲先完但定时未到:DelayRemainMs 续装剩余 ms
* *
* 与其它模块关系 * 与其它模块关系
* - plsr_param :wait_x_sel / ext_x_sel * - plsr_param :wait_x_sel / ext_x_sel
* - plsr_run_control :TakeWait/ExtFalling、ScheduleDelayMs、OnDelayTimer
* - plsr.c :周期调用 DebouncePoll
* - stm32f4xx_it :TIM5 / EXTI 转发
* - plsr_run_control :TakeWait/ExtFalling、Schedule/CancelDelay、OnDelayTimer
* - plsr.c :PlsrTask 每 OS 节拍 DebouncePoll
* - stm32f4xx_it :TIM5 / EXTI9_5 / EXTI15_10 转发至本模块 IRQ 入口
*
* 线程/中断约定
* fell/pending 由 ISR 写、任务读;Take* 仅在任务上下文消费。
* ScheduleDelayMs / CancelDelay 由任务调用;OnTim5Irq 在 TIM5 中断内回调 run_control。
*/ */
#ifndef PLSR_SIGNAL_IO_H #ifndef PLSR_SIGNAL_IO_H
#define PLSR_SIGNAL_IO_H #define PLSR_SIGNAL_IO_H


#include <stdint.h> #include <stdint.h>


/**
* @brief 初始化 X4/X5 EXTI 消抖状态与 TIM5(不启动延时)
* @note 调用时机:PlsrInit,在 RunControl 之前
* @note 副作用:清 pending/fell;TIM5 停表、OPM 单次模式预配置
*/
void PlsrSignalIoInit(void); void PlsrSignalIoInit(void);


/** /**
* @brief 武装 TIM5 单次延时(ms),到期进 OnDelayTimer
* @brief 武装 TIM5 单次延时(ms),到期 OnTim5Irq → PlsrRunControlOnDelayTimer
* @param delay_ms 0 按 1ms;上限 65535ms * @param delay_ms 0 按 1ms;上限 65535ms
* @note 重入会先 Cancel 再重装;OPM 计满自动停表
*/ */
void PlsrSignalIoScheduleDelayMs(uint32_t delay_ms); void PlsrSignalIoScheduleDelayMs(uint32_t delay_ms);


/** @brief 停止 TIM5 单次延时,s_delay_armed=0 */
void PlsrSignalIoCancelDelay(void); void PlsrSignalIoCancelDelay(void);


/** /**
* @brief 读 TIM5 单次延时剩余 ms(未武装或已停表返回 0;向下取整) * @brief 读 TIM5 单次延时剩余 ms(未武装或已停表返回 0;向下取整)
* @note ACT 脉冲先完、定时仍走时,用于续装剩余 ACT 时间
*/ */
uint32_t PlsrSignalIoDelayRemainMs(void); uint32_t PlsrSignalIoDelayRemainMs(void);


/**
* @brief OS 节拍消抖轮询(X4/X5 各跑一遍 Confirm)
* @note 由 PlsrTask 每 tick 调用;满 PLSR_SIGNAL_DEBOUNCE_MS 且仍低才置 fell
*/
void PlsrSignalIoDebouncePoll(void); void PlsrSignalIoDebouncePoll(void);


/**
* @brief 清 X4/X5 的 pending 与 fell(开跑 EXT 段、FinishAll 时用)
* @note 丢弃尚未确认的沿与已锁存沿,防误切段
*/
void PlsrSignalIoClearEdges(void); void PlsrSignalIoClearEdges(void);

/**
* @brief 只清 pending/stamp,保留已确认的 fell
* @note 纯 EXT 段末:清消抖中的假沿,已确认沿留给 TakeExtFalling
*/
void PlsrSignalIoClearPending(void); void PlsrSignalIoClearPending(void);

/**
* @brief 消费 WAIT 口(wait_x_sel)上已确认的下降沿
* @return 1=本次取到有效沿并已清零 fell;0=无沿
* @note 仅认消抖后的 fell,不读当前 GPIO 电平(防虚低误跳)
*/
uint8_t PlsrSignalIoTakeWaitFalling(void); uint8_t PlsrSignalIoTakeWaitFalling(void);

/**
* @brief 消费 EXT 口(ext_x_sel)上已确认的下降沿
* @return 1=本次取到有效沿并已清零 fell;0=无沿
* @note RUN 中 EXT/EXT_OR_DONE 切段、WAIT_COND 等路径共用
*/
uint8_t PlsrSignalIoTakeExtFalling(void); uint8_t PlsrSignalIoTakeExtFalling(void);


/** @brief TIM5 UPDATE:单次延时到期 */
/** @brief TIM5 UPDATE 中断入口:单次延时到期 → run_control */
void PlsrSignalIoOnTim5Irq(void); void PlsrSignalIoOnTim5Irq(void);


/** @brief EXTI9_5 中断入口(X4 / PB5) */
void PlsrSignalIoOnExti9_5(void); void PlsrSignalIoOnExti9_5(void);

/** @brief EXTI15_10 中断入口(X5 / PG12) */
void PlsrSignalIoOnExti15_10(void); void PlsrSignalIoOnExti15_10(void);


#endif #endif

Loading…
取消
儲存