瀏覽代碼

清理部分冗余设计2

dev3
hanyongwei 2 週之前
父節點
當前提交
ad2a6c7d76
共有 7 個文件被更改,包括 159 次插入365 次删除
  1. +12
    -90
      plsr/accel_curve/plsr_accel_curve.c
  2. +0
    -8
      plsr/accel_curve/plsr_accel_curve.h
  3. +51
    -52
      plsr/pulse_driver/plsr_pulse_driver.c
  4. +22
    -121
      plsr/run_control/plsr_run_control.c
  5. +0
    -6
      plsr/run_control/plsr_run_control.h
  6. +71
    -68
      plsr/signal_io/plsr_signal_io.c
  7. +3
    -20
      plsr/signal_io/plsr_signal_io.h

+ 12
- 90
plsr/accel_curve/plsr_accel_curve.c 查看文件

@@ -1,50 +1,6 @@
/**
* @file plsr_accel_curve.c
* @brief 脉冲域规划/取频:直线 frequency_hz^2=start_frequency_hz^2±2an;S/正弦按时间轴剖面
*
* ============================================================================
* 【阅读指南 — 先看这个再往下翻 if/else】
* ============================================================================
*
* 本文件只做一件事:给定「段入口 start_frequency_hz、目标 target_frequency_hz、出口 end_frequency_hz、总脉冲 N、
* 曲线模式 curve_mode」,算出三相预算 accel_pulses / constant_pulses / decel_pulses,以及运行时每拍该什么频率。
*
* 一、名词(全文件统一)
* start_frequency_hz 段入口频率(规划后实际起点,常由 run_control 的 ResolveStartHz 给出)
* target_frequency_hz 段目标峰值(段表频率;脉冲不够时会被 FitPeak 压低)
* end_frequency_hz 段出口频率(run_control 按 wait/止速 解析后传入)
* accel_pulses 从 start_frequency_hz 爬到 target_frequency_hz 需要的脉冲个数
* constant_pulses 保持 target_frequency_hz 的匀速脉冲个数
* decel_pulses 从 target_frequency_hz 收到 end_frequency_hz 的脉冲个数
* accel_rate_hz_per_s 加速斜率 Hz/s ≈ default_speed*1000/acceleration_time_ms
* decel_rate_hz_per_s 减速斜率 Hz/s ≈ default_speed*1000/deceleration_time_ms
*
* 二、三种曲线模式(curve_mode)
* LINEAR 直线:f_n = sqrt(start_frequency_hz^2 ± 2*a*pulse_count);ISR 里 SquareStep ±1Hz 逼近
* S 时间域 jerk 梯形;规划/ISR 用离散 Δt=1/frequency_hz 仿真;ISR 查预建表
* SINE raised-cosine 时间剖面;同上,查预建表
*
* 三、主流程(函数调用链)
* ResolveStartHz / ResolveEndHz → 起跳/落地(配置起止速=0 时用)
* PlsrAccelCurvePlan → 估 acc/dec/const;不够则砍匀速再降峰
* PlsrAccelPrebuildFrequencyTables → S/正弦预建频率表(任务上下文,勿在 ISR)
* PlsrAccelCurveFreqAtPulse → 按「已完成脉冲数」取频(任务侧 RefreshProfile)
* PlsrAccelNextFrequency → ISR 每 UPDATE 前进一步,返回下一拍频率
*
* 四、Plan 里 if/else 决策树(见 PlsrAccelCurvePlan 内注释)
* total=0 → 全 0 返回
* acc+dec <= total → 有匀速:const = total - acc - dec
* acc+dec > total → 无匀速:FitPeak 降 target_frequency_hz 直到 acc+dec 放得下
*
* 五、FreqAtPulse 的 completed_segment_pulses 含义(易混)
* completed_segment_pulses = 已完成脉冲数(不是「当前第几拍」)
* done=0 → 第 1 拍频率 = start_frequency_hz;done=1 → 第 2 拍 ≈ sqrt(start_frequency_hz^2+2a) …
*
* @details 模块职责
* 实现 plsr_accel_curve.h 全部 API。核心路径:
* Plan → 估 accel_pulses/decel_pulses → 不够则先砍 constant_pulses,再 FitPeak 降峰;
* BeginAcceleration/BeginDeceleration/BeginConstantSpeed + NextFrequency
* 供 ISR 每个脉冲更新频率。
* @brief 脉冲域规划/取频:直线 frequency_hz^2=start_frequency_hz^2±2an;S/正弦按时间
*/
#include "plsr_accel_curve.h"
#include <stdint.h>
@@ -334,7 +290,7 @@ static uint32_t PlsrAccelCurveCalculateLinearRampPulses(uint32_t start_frequency
}

/*============================================================================*/
/* S / 正弦:时间轴剖面(加速度梯形 / raised-cosine) */
/* S / 正弦 */
/*============================================================================*/

/**
@@ -427,7 +383,7 @@ static uint32_t PlsrAccelCurveDeltaHzFromJerk(uint32_t acceleration_hz_per_s, ui
}

/**
* 时刻 elapsed_time_us 的 S 剖面频率(相对进度 0..frequency_difference_hz,再映射到 start_frequency_hz→end_frequency_hz)。
* 时刻 elapsed_time_us 的频率(相对进度 0..frequency_difference_hz,再映射到 start_frequency_hz→end_frequency_hz)。
*/
static uint32_t PlsrAccelCurveSCurveFrequencyAtTime(uint32_t start_frequency_hz, uint32_t end_frequency_hz, uint32_t acceleration_hz_per_s,
uint32_t jerk_time_us, uint32_t constant_accel_time_us,
@@ -539,8 +495,7 @@ static uint32_t PlsrAccelCurveSineFrequencyAtTime(uint32_t start_frequency_hz, u
}

/**
* 与 ISR / 建表一致:逐拍 Δt=1/frequency_hz 推进时间剖面,得到 S/正弦斜坡脉冲数。
* (旧版 ∫frequency_hz dt 解析估算已废弃,避免与离散运行不一致。)
* 与 ISR / 建表一致:逐拍 Δt=1/frequency_hz 推进时间,得到 S/正弦斜坡脉冲数。
*/
static uint32_t PlsrAccelCurveSimulateRampPulses(uint32_t start_frequency_hz, uint32_t end_frequency_hz,
uint32_t acceleration_hz_per_s,
@@ -762,21 +717,6 @@ static uint32_t PlsrAccelCurveFitTargetToPulseBudget(uint32_t total_pulses,

/**
* @brief 规划一整段脉冲域(见 plsr_accel_curve.h)
*
* 【输入】total_pulses=N, start_frequency_hz, target_frequency_hz, end_frequency_hz, default_speed_hz, accel/deceleration_time_ms, curve_mode
* 【输出】plan 里填 accel_pulses, constant_pulses, decel_pulses, start_frequency_hz, target_frequency_hz(可能被降峰), end_frequency_hz, accel_rate_hz_per_s, decel_rate_hz_per_s
*
* 步骤概要:
* 1) 钳频;start_frequency_hz/end_frequency_hz<1 时用 ResolveStart/EndHz 补起跳/落地
* 2) 算 accel_rate_hz_per_s、decel_rate_hz_per_s(default 为 0 时回退为 |频差|*1000/时间)
* 3) 估 accel_pulses(start_frequency_hz→peak_frequency_hz)、decel_pulses(peak_frequency_hz→end_frequency_hz);选 accel_rate_hz_per_s 还是 decel_rate_hz_per_s 看升降方向
* 4) 分配 constant_pulses 或 FitPeak 三角波
*
* 波形形状记忆:
* target_frequency_hz(peak_frequency_hz) ───── const ─────┐
* / \\ dec
* start_frequency_hz end_frequency_hz
* accel_pulses constant_pulses decel_pulses
*/
void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan,
uint32_t total_pulses,
@@ -980,15 +920,6 @@ static uint32_t PlsrAccelCurveTimedFrequencyAtPulse(

/**
* @brief 按已完成脉冲数取频(任务侧;ISR 用 PlsrAccelNextFrequency)
*
* 【分段逻辑 — 按 completed_segment_pulses 落在哪一段】
*
* completed_segment_pulses ∈ [0, accel_pulses) → 加速相(start_frequency_hz → target_frequency_hz)
* completed_segment_pulses ∈ [accel_pulses, accel_pulses+constant_pulses) → 匀速 target_frequency_hz
* completed_segment_pulses ∈ [accel_pulses+constant_pulses, …) → 减速相(target_frequency_hz → end_frequency_hz)
*
* 注意 completed_segment_pulses 是「已经发完的个数」:
* Start 后第 1 拍进行中时 done 仍为 0,FreqAtPulse(0)=start_frequency_hz。
*/
uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan,
uint32_t completed_segment_pulses)
@@ -1084,7 +1015,7 @@ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan,
/*============================================================================*/

/**
* @brief 为 S/正弦准备时间剖面(加速度梯形 / raised-cosine)
* @brief 为 S/正弦准备下一拍频率
*/
static uint32_t PlsrAccelNextFrequencyTimed(PlsrAccelRuntime_t *runtime);

@@ -1179,7 +1110,7 @@ static void PlsrAccelRuntimeSimulateOnePulse(PlsrAccelRuntime_t *runtime)
}

/**
* 将本相离散剖面写入 frequency_table[],返回写入长度;*table_stride_out 为抽样步长。
* 将本相离散频率写入 frequency_table[],返回写入长度;*table_stride_out 为抽样步长。
*/
static uint32_t PlsrAccelRuntimeBuildFrequencyTable(PlsrAccelRuntime_t *runtime,
uint32_t *frequency_table,
@@ -1317,7 +1248,7 @@ static void PlsrAccelRuntimeSelectFrequencyTable(PlsrAccelRuntime_t *runtime,
runtime->frequency_table_id = (table_length > 0U) ? frequency_table_id : 0U;
}

/** @brief 进入加速相(见 plsr_accel_curve.h) */
/** @brief 进入加速相 */
void PlsrAccelBeginAcceleration(PlsrAccelRuntime_t *runtime,
const PlsrAccelPlan_t *plan)
{
@@ -1336,7 +1267,7 @@ void PlsrAccelBeginAcceleration(PlsrAccelRuntime_t *runtime,
s_acceleration_table_stride);
}

/** @brief 进入减速相(见 plsr_accel_curve.h) */
/** @brief 进入减速相 */
void PlsrAccelBeginDeceleration(PlsrAccelRuntime_t *runtime,
const PlsrAccelPlan_t *plan)
{
@@ -1356,7 +1287,7 @@ void PlsrAccelBeginDeceleration(PlsrAccelRuntime_t *runtime,
s_deceleration_table_stride);
}

/** @brief 进入匀速相(见 plsr_accel_curve.h) */
/** @brief 进入匀速相 */
void PlsrAccelBeginConstantSpeed(PlsrAccelRuntime_t *runtime,
const PlsrAccelPlan_t *plan)
{
@@ -1467,7 +1398,7 @@ static uint32_t PlsrAccelNextFrequencyLinear(PlsrAccelRuntime_t *runtime)
}

/**
* S/正弦时间域步进:上一拍周期推进 t,再按剖面取下一拍频率。
* S/正弦时间域步进:上一拍周期推进 t,再按时间取下一拍频率。
*/
static uint32_t PlsrAccelNextFrequencyTimed(PlsrAccelRuntime_t *runtime)
{
@@ -1514,7 +1445,7 @@ static uint32_t PlsrAccelNextFrequencyTimed(PlsrAccelRuntime_t *runtime)
return frequency_hz;
}

/*仿真离散脉冲剖面,算出该段加减速一共需要输出多少个脉冲*/
/*仿真离散脉冲频率,算出该段加减速一共需要输出多少个脉冲*/
static uint32_t PlsrAccelCurveSimulateRampPulses(uint32_t start_frequency_hz, uint32_t end_frequency_hz,
uint32_t acceleration_hz_per_s,
PlsrAccelMode_e curve_mode)
@@ -1554,16 +1485,7 @@ static uint32_t PlsrAccelCurveSimulateRampPulses(uint32_t start_frequency_hz, ui
}

/**
* @brief ISR 热路径:本相再前进 1 脉冲,返回「下一拍应写入 ARR 的频率」
*
* 调用时机:每个 PWM UPDATE 中断里,在本段已发脉冲数加一之后。
*
* 模式分支:
* LINEAR → SquareStep:用 frequency_hz±1 逼近 sqrt(start_frequency_hz^2±2an),不全量开方
* S/SINE+表 → 查 s_acceleration_frequency_table / s_deceleration_frequency_table(Prebuild 填好),table_index=(pulse_count-1)/table_stride
* S/SINE无表 → 兜底 TimeStep(不应出现在正常路径)
*
* pulse_count 含义:本相已 Step 次数;BeginAcc 后第 1 次 Step 时 pulse_count 变为 1,对应「第 2 拍」频率。
* @brief ISR 热路径:本相再前进 1 脉冲,返回下一拍应写入 ARR 的频率
*/
uint32_t PlsrAccelNextFrequency(PlsrAccelRuntime_t *runtime)
{


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

@@ -4,14 +4,6 @@
*
* @details 按起/峰/止频率、斜率时间与总脉冲规划三相脉冲预算,并在脉冲序号上取频。
* 不读 wait_type,不碰 TIM/GPIO。
*
* 直线:下一频率由起点频率、变化率和已完成脉冲数计算(ISR 增量逼近)。
* S/正弦:开相时预计算频率表;ISR 只按脉冲序号查表(匀速相不改频)。
* 规划脉冲数与建表使用同一套离散逐拍仿真。
*
* 术语(全模块统一):
* 字段使用完整名称和单位,例如 accel_pulses、start_frequency_hz,
* 避免阅读代码时反复猜测 acc_n、f_cur、a_acc 等数学缩写。
*/
#ifndef PLSR_ACCEL_CURVE_H
#define PLSR_ACCEL_CURVE_H


+ 51
- 52
plsr/pulse_driver/plsr_pulse_driver.c 查看文件

@@ -33,13 +33,6 @@ TIM_HandleTypeDef htim13;
#define PLSR_Y3_PORT GPIOF
#define PLSR_Y3_PIN GPIO_PIN_9

/*
* ---------- 模块静态状态 ----------
* g_plsr_output_frequency_hz/psc/arr — 上次量化结果;匀速热路径比较后可跳过写寄存器
* s_active_htim — 当前选中脉冲路 HAL 句柄
* s_psc_locked / locked_psc — 段内 PSC 锁;跨度过大时 locked=0
* s_req_freq / pending — ISR 无法换 PSC 时的挂起改频
*/
volatile uint32_t g_plsr_output_frequency_hz;
volatile uint8_t g_plsr_pwm_running;
uint8_t g_plsr_direction_forward;
@@ -155,13 +148,18 @@ static void PlsrPulseDriverOcForceLowKeepRun(TIM_HandleTypeDef *htim)
return;
}

ccmr = htim->Instance->CCMR1;
ccmr &= (uint32_t)(~TIM_CCMR1_OC1M);
ccmr |= TIM_OCMODE_FORCED_INACTIVE;
ccmr = htim->Instance->CCMR1;//Output Compare 1 Mode,输出比较 1 模式
//- CC1E=1:OC 通道输出到 GPIO 引脚;
//- CC1E=0:通道输出关闭,引脚由 GPIO 寄存器控制。
ccmr &= (uint32_t)(~TIM_CCMR1_OC1M);//把[6:4]变成0
ccmr |= TIM_OCMODE_FORCED_INACTIVE;//写入0b100 强制无效模式到OC1M域
htim->Instance->CCMR1 = ccmr;
htim->Instance->CCER |= TIM_CCER_CC1E;
}

/**
* Forced inactive 拉低,关掉并清标志
*/
static void PlsrPulseDriverOcHoldLow(TIM_HandleTypeDef *htim)
{
uint32_t ccmr;
@@ -197,7 +195,7 @@ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
__HAL_RCC_GPIOF_CLK_ENABLE();

gpio.Mode = GPIO_MODE_AF_PP;
/* 下拉:通道若短暂高阻时保持低,避免上拉把「已高」盖住导致看不到开表上升沿 */
/* 下拉:通道若短暂高阻时保持低,避免上拉导致看不到开表上升沿 */
gpio.Pull = GPIO_PULLDOWN;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;

@@ -250,6 +248,7 @@ static void PlsrPulseDriverTimInitOne(TIM_HandleTypeDef *htim, TIM_TypeDef *inst
* ARR/CCR 预装载打开:改频只写入影子寄存器,在下一 UPDATE 生效。
* 避免关预装载时在 ISR 里直接改 ARR/CCR 产生毛刺边沿(段越长多计越多,
* 如设定 5000 实测 5007)。软件侧超前一拍写频率补偿延迟。
* polarity极性
*/
htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_PWM_Init(htim) != HAL_OK)
@@ -259,7 +258,7 @@ static void PlsrPulseDriverTimInitOne(TIM_HandleTypeDef *htim, TIM_TypeDef *inst

oc.OCMode = TIM_OCMODE_PWM1;
oc.Pulse = 500U;
oc.OCPolarity = TIM_OCPOLARITY_HIGH;
oc.OCPolarity = TIM_OCPOLARITY_HIGH;//0高电平有效,1低电平有效
oc.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(htim, &oc, TIM_CHANNEL_1) != HAL_OK)
{
@@ -270,7 +269,7 @@ static void PlsrPulseDriverTimInitOne(TIM_HandleTypeDef *htim, TIM_TypeDef *inst
PlsrPulseDriverOcHoldLow(htim);
}

/** @brief 驱动初始化(见 plsr_pulse_driver.h) */
/** @brief 驱动初始化 */
void PlsrPulseDriverInit(void)
{
g_plsr_output_frequency_hz = 0U;
@@ -295,7 +294,7 @@ void PlsrPulseDriverInit(void)
PlsrPulseDriverTimInitOne(&htim13, TIM13);
}

/** @brief 写方向脚(见 plsr_pulse_driver.h) */
/** @brief 写方向脚 */
void PlsrPulseDriverSetDir(uint8_t forward)
{
uint8_t level;
@@ -314,7 +313,7 @@ void PlsrPulseDriverSetDir(uint8_t forward)
g_plsr_direction_valid = 1U;
}

/** @brief 方向脚拉低(见 plsr_pulse_driver.h) */
/** @brief 方向脚拉低 */
void PlsrPulseDriverClearDir(void)
{
HAL_GPIO_WritePin(PLSR_Y3_PORT, PLSR_Y3_PIN, GPIO_PIN_RESET);
@@ -322,7 +321,7 @@ void PlsrPulseDriverClearDir(void)
g_plsr_direction_valid = 0U;
}

/** @brief 是否脉冲 TIM(见 plsr_pulse_driver.h) */
/** @brief 是否脉冲 TIM */
uint8_t PlsrPulseDriverIsPulseTim(TIM_TypeDef *instance)
{
return ((instance == TIM10) || (instance == TIM11) || (instance == TIM13)) ? 1U : 0U;
@@ -333,7 +332,7 @@ uint8_t PlsrPulseDriverIsPulseTim(TIM_TypeDef *instance)
/*============================================================================*/

/*
* STM32 定时器频率换算(本模块约定)
* STM32 定时器频率换算
* clk_hz — TIM 计数时钟(APB2=168MHz 或 APB1=84MHz)
* psc — 预分频寄存器值,实际分频 = PSC+1
* arr — 自动重装载,一个 PWM 周期 = (ARR+1)×(PSC+1) 个计数
@@ -365,7 +364,7 @@ static void PlsrPulseDriverCalcArrWithPsc(uint32_t clk_hz, uint32_t freq_hz, uin
{
ticks = 2UL;
}
a = ticks / (psc + 1UL);
if (a < 2UL)
{
@@ -415,7 +414,7 @@ static void PlsrPulseDriverCalcPscArr(uint32_t clk_hz, uint32_t freq_hz,
ticks = 2UL;
}

p = (ticks + 65535UL - 1UL) / 65535UL;
p = (ticks + 65536UL - 1UL) / 65536UL;
if (p == 0UL)
{
p = 1UL;
@@ -430,13 +429,13 @@ static void PlsrPulseDriverCalcPscArr(uint32_t clk_hz, uint32_t freq_hz,
PlsrPulseDriverCalcArrWithPsc(clk_hz, freq_hz, p, arr, ccr);
}

/** @brief 按频率跨度锁 PSC(见 plsr_pulse_driver.h) */
/** @brief 按频率跨度锁 PSC */
void PlsrPulseDriverLockPscRange(uint32_t f_min_hz, uint32_t f_max_hz)
{
uint32_t ticks_lo;
uint32_t ticks_hi;
uint32_t psc_div_lo;
uint32_t psc_div_hi;
uint32_t ticks_max;
uint32_t ticks_min;
uint32_t psc_div_max;
uint32_t psc_div_min;
uint32_t div;
uint32_t clk_hz = PlsrPulseDriverTimClkHz(
PlsrPulseDriverHtimByY(PlsrPulseDriverSelectY()));
@@ -451,35 +450,35 @@ void PlsrPulseDriverLockPscRange(uint32_t f_min_hz, uint32_t f_max_hz)
}
if (f_max_hz < f_min_hz)
{
uint32_t t = f_min_hz;
uint32_t temp = f_min_hz;
f_min_hz = f_max_hz;
f_max_hz = t;
f_max_hz = temp;
}

ticks_lo = clk_hz / f_min_hz;
ticks_hi = clk_hz / f_max_hz;
if (ticks_lo < 2UL)
ticks_max = clk_hz / f_min_hz;
ticks_min = clk_hz / f_max_hz;
if (ticks_max < 2UL)
{
ticks_lo = 2UL;
ticks_max = 2UL;
}
if (ticks_hi < 2UL)
if (ticks_min < 2UL)
{
ticks_hi = 2UL;
ticks_min = 2UL;
}

/* psc_div = PSC+1:低频要求 div 足够大,高频要求 div 足够小 */
psc_div_lo = (ticks_lo + 65535UL) / 65536UL;
if (psc_div_lo < 1UL)
psc_div_min = (ticks_max + 65535UL) / 65536UL;
if (psc_div_min < 1UL)
{
psc_div_lo = 1UL;
psc_div_min = 1UL;
}
psc_div_hi = ticks_hi / 2UL;
if (psc_div_hi < 1UL)
psc_div_max = ticks_min / 2UL;
if (psc_div_max < 1UL)
{
psc_div_hi = 1UL;
psc_div_max = 1UL;
}

if (psc_div_lo > psc_div_hi)
if (psc_div_min > psc_div_max)
{
/*
* 单一 PSC 无法同时覆盖 f_min~f_max(例如 1Hz~很高频)。
@@ -490,12 +489,12 @@ void PlsrPulseDriverLockPscRange(uint32_t f_min_hz, uint32_t f_max_hz)
return;
}

div = psc_div_lo;
div = psc_div_min;
s_locked_psc = div - 1UL;
s_psc_locked = 1U;
}

/** @brief 解除 PSC 锁(见 plsr_pulse_driver.h) */
/** @brief 解除 PSC 锁 */
void PlsrPulseDriverUnlockPsc(void)
{
s_psc_locked = 0U;
@@ -688,13 +687,13 @@ static void PlsrPulseDriverStartCommon(uint32_t freq_hz)
}
}

/** @brief 换向延时期间预装寄存器、CEN 保持关(见 plsr_pulse_driver.h) */
/** @brief 换向延时期间预装寄存器、CEN 保持关 */
void PlsrPulseDriverPrepare(uint32_t freq_hz)
{
PlsrPulseDriverLoadRegs(freq_hz);
}

/** @brief 任务上下文改频(见 plsr_pulse_driver.h) */
/** @brief 任务上下文改频 */
void PlsrPulseDriverSetFreq(uint32_t freq_hz)
{
uint32_t psc;
@@ -766,7 +765,7 @@ void PlsrPulseDriverSetFreq(uint32_t freq_hz)
s_last_arr = arr;
}

/** @brief ISR 改频(见 plsr_pulse_driver.h) */
/** @brief ISR 改频 */
void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz)
{
uint32_t psc;
@@ -864,19 +863,19 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz)
s_last_ccr = ccr;
}

/** @brief 丢弃挂起(见 plsr_pulse_driver.h) */
/** @brief 丢弃挂起 */
void PlsrPulseDriverClearPending(void)
{
s_req_pending = 0U;
}

/** @brief 取消冷启动首拍保护(见 plsr_pulse_driver.h) */
/** @brief 取消冷启动首拍保护*/
void PlsrPulseDriverClearStartPeriodProtect(void)
{
s_protect_start_period = 0U;
}

/** @brief 消费挂起改频(见 plsr_pulse_driver.h) */
/** @brief 消费挂起改频 */
void PlsrPulseDriverApplyPending(void)
{
uint32_t f;
@@ -895,13 +894,13 @@ void PlsrPulseDriverApplyPending(void)
PlsrPulseDriverSetFreq(f);
}

/** @brief 开 PWM + UPDATE 中断(见 plsr_pulse_driver.h) */
/** @brief 开 PWM + UPDATE 中断 */
void PlsrPulseDriverStart(uint32_t freq_hz)
{
PlsrPulseDriverStartCommon(freq_hz);
}

/** @brief 停三路(见 plsr_pulse_driver.h) */
/** @brief 停三路 */
void PlsrPulseDriverStop(void)
{
s_req_pending = 0U;
@@ -963,7 +962,7 @@ void PlsrPulseDriverArmActStop(void)
}

/**
* @brief 段末停表:OPM + 末拍 CC1 下降沿立刻拉低(见 plsr_pulse_driver.h)
* @brief 段末停表:OPM + 末拍 CC1 下降沿立刻拉低
*/
void PlsrPulseDriverArmSegEndStop(void)
{
@@ -994,7 +993,7 @@ void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
PlsrPulseDriverOcForceLowKeepRun(htim);
}

/** @brief 取消 OPM(见 plsr_pulse_driver.h) */
/** @brief 取消 OPM */
void PlsrPulseDriverClearOnePulseStop(void)
{
TIM_HandleTypeDef *htim = s_active_htim;
@@ -1007,7 +1006,7 @@ void PlsrPulseDriverClearOnePulseStop(void)
PlsrPulseDriverClearSegEndFallArm(htim);
}

/** @brief OPM 段末 UPDATE 后立刻拉低,消除 CNT 回零 PWM1 假上升沿(见 plsr_pulse_driver.h) */
/** @brief OPM 段末 UPDATE 后立刻拉低,消除 CNT 回零 PWM1 假上升沿 */
void PlsrPulseDriverHoldOutputLow(void)
{
TIM_HandleTypeDef *htim = s_active_htim;


+ 22
- 121
plsr/run_control/plsr_run_control.c 查看文件

@@ -1,92 +1,6 @@
/**
* @file plsr_run_control.c
* @brief 运行控制:等待策略 + 开段端点 + 执行驱动
*
* ============================================================================
* 【阅读指南 — 两层状态机 + 一条 ISR 主链】
* ============================================================================
*
* 第一层:段级状态 RcState_e(整段生命周期)
* RC_IDLE 空闲,等 START
* RC_DIR_WAIT 换向后等 dir_delay_ms(TIM5),到期再开 PWM
* RC_RUN 正在发脉冲(OnPulseIsr 推进)
* RC_WAIT_COND 本段脉冲发完,等时间/信号/EXT 再跳下一段
*
* 第二层:段内相 RunPhase_e(单段里的加减速,只在 RC_RUN 下有效)
* PH_APPROACH 从 freq_start 爬到 f_tgt
* PH_CONST 匀速 f_tgt(ISR 不改 ARR)
* PH_DECEL 从 f_tgt 收到 freq_end
*
* 主调用链(从 START 到一段脉冲):
* Start → BeginSeg → ResolveSegPlanEndpoints(算起/止频)
* → PlanSeg → accel_curve Plan + Prebuild
* → RefreshProfile(1) 开表
* → [DIR_WAIT?] → OnPulseIsr 循环
*
* 关键变量:
* s_segment_pulses_done / s_segment_pulse_target 本段已发 / 目标脉冲数
* remain = target - done(还剩几拍)
* s_phase 段内 APPROACH/CONST/DECEL
* s_stop_after_last_pulse 1=段末停表(非 FOLLOW 无缝);0=到点立刻跳下段
*
* OnPulseIsr 决策顺序(自上而下,命中 return):
* 1) 非 RC_RUN → 直接 return
* 2) s_waiting_for_last_period → 末拍周期结束,停表,AfterSegDone
* 3) s_segment_pulses_done++,累计 g_plsr_accumulated_pulses
* 4) s_act_waiting_for_pulse_boundary → ACT 到期,任务侧切段
* 5) s_segment_pulses_done >= target → OPM 末拍 or 立刻 AfterSegDone
* 6) 按 s_phase 改频:CONST 只进减速;APPROACH Step;DECEL Step
*
* ARPE(UPDATE ISR 写影子 → 下一周期才装入工作 ARR):
* 在 remain==k 时写入的频率供下一拍使用;进减速窗为 remain<=dec_n,
* 在 remain==1 写入 f_end,末拍才能吃到止速。勿再用 remain<=dec_n+1,
* 否则会在 remain==2 就强制止速,造成末两拍同频。
*
* 分层(阶段1薄拆分):
* 1) 曲线(accel_curve):只吃 (f_from,f_tgt,f_end,斜率,N,mode) → 梯形/三角;
* 不读 wait_type。端点须为真实频率(>=1);配置起/止=0 由运行层
* ResolveStart/EndHz 算起跳/落地后再传入。
* 2) 等待策略:只决定何时打断/段后等待;统一传递 handoff:
* - 仍在输出且 freq>=1 → 链式传给下一段
* - 已停表/输出为 0 → 下一段从配置起速(0 则起跳频率)开跑
* 3) 本段 f_end 由等待类型 + 发送模式 + 与「下一有效段」方向关系决定:
* - EXT_OR_DONE + 下一有效段同向 + 后续 → 过渡到该段目标
* - EXT_OR_DONE + 下一有效段同向 + 完成 → f_end=峰值,匀速跑完
* - EXT_OR_DONE + 下一有效段反向(可跳过中间频率0且脉冲0占位)→ 规划到公共止速
* - 真末段 → 一律规划到公共止速
* - TIME/SIGNAL/ACT/EXT → 完成/后续相同,规划到公共止速
* FOLLOW 另允许 EXT_OR_DONE 同向不停表衔接(直接下一段不得为无效占位)。
* 4) PlanSeg / ChangeFreq 共用规划入口,便于后期动态改频
*
* 【运行节拍】纯脉冲计数:
* UPDATE ISR:s_segment_pulses_done++;末拍用 ArmSegEndStop 完整收尾;
* 加/减速逐拍 PlsrAccelNextFrequency + SetFreqIsr;
* 匀速复用 ARR(不改频);remain<=dec_n 进减速。
* 任务 TickMs:ACT(OS 节拍)/ EXT / ApplyPending;
* TIM5 one-shot:换向/WAIT/ACT/ACT剩余;ACT 到期收完当前脉冲并锁低,周期边界再切段。
* PlsrTask:DebouncePoll + TickMs + WakePend。
*
* 【段末频率 / ARPE】UPDATE 里写的影子 ARR 在下一周期生效;
* 减速在 remain==dec_n 切入,共 Step dec_n 次,最后一次(remain==1)写入 f_end。
* 纯减速开表:Start(f1),后续由 ISR 顺序写入 f2…f_end(勿再预步进一拍)。
*
* 【段末停表】非 FOLLOW-keep 时开段锁 s_stop_after_last_pulse:
* UPDATE≈上升沿;s_segment_pulses_done 到 target 时 ArmSegEndStop(OPM+CC1 末拍下降沿拉低),
* 周期 UPDATE 再 HoldOutputLow + AfterSegDone 且不再 ++。FOLLOW-keep 到点立刻衔接。
*
* 【故障诊断 0x2006】(PlsrCommandSetFault,告警码 1~3 不停机;4 禁止启动)
* 0x01 段结束 AfterSegDone:s_segment_pulses_done != s_segment_pulse_target
* 0x02 PlanSeg 后:规划峰值达不到设定 f_tgt(典型三角)
* 0x03 加速离开 APPROACH / 减速段末:相内脉冲 ≠ 规划预算
* 0x04 目标频率 ∉ [1,100000]:Start / BeginSeg / ChangeFreq / 运行中写频
*
* 符号约定(与 accel_curve / param 对齐)
* seg_idx0 — 段下标 0-based(寄存器/界面段号为 1-based)
* f_tgt — 段表目标频率 Hz(规划输入,可能与规划峰值不同)
* s_segment_pulses_done — 本段已发脉冲数;s_segment_pulse_target — 本段目标脉冲数
* g_plsr_accel_plan.accel_pulses — PlanSeg 锁定的加速相脉冲预算(0x03 诊断用)
* g_plsr_accel_runtime.total_pulses — 进入减速相时锁定的步进预算(可能因 ARPE 缩短)
* remain — 本段剩余脉冲 = s_segment_pulse_target - s_segment_pulses_done
*/
#include "plsr_run_control.h"
#include "plsr.h"
@@ -100,9 +14,9 @@

/*
* ---------- 运行主状态机 RcState_e ----------
* RC_IDLE — 无段在执行;可 Start;脉冲 ISR 不推进
* RC_DIR_WAIT — 真换向后 TIM5 one-shot 等 dir_delay;到期 ISR 内开 PWM
* RC_RUN — 脉冲 ISR 推进;TickMs 处理 EXT / ACT(OS)
* RC_IDLE — 无段在执行
* RC_DIR_WAIT — 真换向后 TIM5等 dir_delay;到期 ISR 内开 PWM
* RC_RUN — 脉冲 ISR 推进;TickMs 处理 EXT / ACT时间
* RC_WAIT_COND — 段后等待:TIM5 时间 或 WAIT/EXT 沿
*/
typedef enum {
@@ -113,7 +27,7 @@ typedef enum {
} RcState_e;

/*
* ---------- 段内运行相 RunPhase_e(脉冲 ISR 热路径) ----------
* ---------- 段内运行相 RunPhase_e ----------
* PH_APPROACH — 起速 → 本段峰值 f_tgt
* PH_CONST — 匀速,复用 ARR 不写寄存器
* PH_DECEL — 段末过渡 → f_end(可升可降)
@@ -124,12 +38,9 @@ typedef enum {
PH_DECEL
} RunPhase_e;

/* 其它 PLSR 模块需要读取的运行结果只保存这一份。 */
volatile uint8_t g_plsr_busy;
volatile uint16_t g_plsr_current_segment_index;
volatile int32_t g_plsr_accumulated_pulses;

/* 运行控制内部状态保持一层变量,避免 s_run.xxx 的结构体嵌套。 */
static volatile RcState_e s_state;
static volatile uint8_t s_forward;
static volatile int32_t s_segment_pulses_done;
@@ -150,9 +61,7 @@ static uint8_t s_stop_after_last_pulse;
static volatile uint8_t s_waiting_for_last_period;
static OS_EVENT *s_wake_sem;

/**
* 策略层解析后交给 PlanSeg 的段端点(不含 wait_type,仅频率与时间)
*/
/* 策略层解析后交给 PlanSeg 的段端点 */
typedef struct {
uint32_t freq_start_hz; /* 本段入口频率 Hz(>=1,由衔接/起速解析) */
uint32_t freq_end_hz; /* 本段出口频率 Hz(由 wait/send/方向解析) */
@@ -190,19 +99,19 @@ static void PlsrRunControlWakePost(void);
static void PlsrRunControlWakeDrain(void);

/**
* @brief 解析下一段索引(原 path_plan)
* @brief 解析下一段索引
* @note jump=0:末段结束,非末段顺序下一段;jump=1..N:跳到对应段;其它结束
*/
static int16_t PlsrRunControlNextSeg(uint16_t cur_seg_0based)
static int16_t PlsrRunControlNextSeg(uint16_t cur_seg_based)
{
uint16_t n = PlsrParamGetSegCount();
uint16_t jump = g_plsr_segments[cur_seg_0based].jump_seg;
uint16_t jump = g_plsr_segments[cur_seg_based].jump_seg;

if (jump == 0U)
{
if ((n >= 1U) && (cur_seg_0based + 1U < n))
if ((n >= 1U) && (cur_seg_based + 1U < n))
{
return (int16_t)(cur_seg_0based + 1U);
return (int16_t)(cur_seg_based + 1U);
}
return -1;
}
@@ -214,21 +123,21 @@ static int16_t PlsrRunControlNextSeg(uint16_t cur_seg_0based)
}

/**
* @brief 无效占位段:频率 0 且脉冲 0(不参与 EXT_OR_DONE 同向衔接/换向判断)
* @brief 判断空段,无效占位段:频率 0 且脉冲 0
*/
static uint8_t PlsrRunControlIsEmptyPlaceholderSeg(uint16_t seg_0based)
static uint8_t PlsrRunControlIsEmptyPlaceholderSeg(uint16_t seg_based)
{
return ((g_plsr_segments[seg_0based].freq_hz == 0) &&
(g_plsr_segments[seg_0based].pulse_cnt == 0)) ? 1U : 0U;
return ((g_plsr_segments[seg_based].freq_hz == 0) &&
(g_plsr_segments[seg_based].pulse_cnt == 0)) ? 1U : 0U;
}

/**
* @brief 从 cur 的下一段起,沿 jump 跳过「频率0且脉冲0」无效段,找下一有效段
* @return 有效段 0-based;无则 -1
*/
static int16_t PlsrRunControlNextEffectiveSeg(uint16_t cur_seg_0based)
static int16_t PlsrRunControlNextEffectiveSeg(uint16_t cur_seg_based)
{
int16_t next = PlsrRunControlNextSeg(cur_seg_0based);
int16_t next = PlsrRunControlNextSeg(cur_seg_based);
uint16_t guard = 0U;

while ((next >= 0) && (guard < PLSR_SEG_MAX))
@@ -246,23 +155,23 @@ static int16_t PlsrRunControlNextEffectiveSeg(uint16_t cur_seg_0based)
/**
* @brief 判断段方向:相对看 pulse_cnt 符号;绝对看目标−局部位置
*/
static uint8_t PlsrRunControlIsForward(uint16_t seg_0based, int32_t acc_pulse)
static uint8_t PlsrRunControlIsForward(uint16_t seg_based, int32_t acc_pulse)
{
int32_t move;

if (g_plsr_config.run_mode == PLSR_POS_ABSOLUTE)
{
move = g_plsr_segments[seg_0based].pulse_cnt - acc_pulse;
move = g_plsr_segments[seg_based].pulse_cnt - acc_pulse;
}
else
{
move = g_plsr_segments[seg_0based].pulse_cnt;
move = g_plsr_segments[seg_based].pulse_cnt;
}
return (move >= 0) ? 1U : 0U;
}

/**
* @brief 停表并清频率链(段后 WAIT / 反向切段共用)
* @brief 停表并清频率链
*/
static void PlsrRunControlClearChainAndStop(void)
{
@@ -307,19 +216,11 @@ static void PlsrRunControlApplyKeepOrStop(uint8_t allow_act_handoff)
}
}

/**
* @brief 开跑瞬间武装 ACT/EXT
* @note EXT:清旧沿防误切;WAIT 信号不在此清(段中沿留给※2)
* @note ACT:写时长后武装 TIM5;到期 OPM 收当前拍,下一 UPDATE 再 ActExpire
*/
/* @brief 开始输出时:EXT 类清旧沿;ACT 类启动段内定时 */
static void PlsrRunControlArmActExtOnPulseStart(void)
{
uint16_t act_time_ms;

/*
* EXT 中途切段:开跑时丢掉旧沿,避免上一段的 WAIT 沿立刻切段。
* WAIT 信号不在这里清:段中落地的下降沿要留给※2。
*/
if ((g_plsr_segments[g_plsr_current_segment_index].wait_type == PLSR_WAIT_EXT) ||
(g_plsr_segments[g_plsr_current_segment_index].wait_type == PLSR_WAIT_EXT_OR_DONE))
{


+ 0
- 6
plsr/run_control/plsr_run_control.h 查看文件

@@ -1,12 +1,6 @@
/**
* @file plsr_run_control.h
* @brief 运行控制:多段脉冲状态机(开段 → 发脉冲 → 等待/跳转 → 收尾)
*
* @details 解析发送模式、等待类型与段间频率衔接;协调 accel_curve /
* pulse_driver / signal_io / param。状态:IDLE / DIR_WAIT / RUN / WAIT_COND。
*
* 与 accel_curve 对齐的符号:
* f_tgt — 段表目标频率 Hz;segment_pulses_done/target — 已发/目标脉冲数
*/
#ifndef PLSR_RUN_CONTROL_H
#define PLSR_RUN_CONTROL_H


+ 71
- 68
plsr/signal_io/plsr_signal_io.c 查看文件

@@ -8,7 +8,7 @@
* 下降沿触发 OnFalling:仅 pending=1,不在 ISR 里判有效(避免抖动/毛刺)。
*
* 【消抖】
* DebouncePoll(任务上下文,约 1ms 一次):
* DebouncePoll(任务上下文,约 10ms 一次):
* pending 且首次 → 记 arm_tick;
* 满 PLSR_SIGNAL_DEBOUNCE_MS(20ms)且 PinIsLow → fell=1。
* 上升沿恢复高电平则 Confirm 末尾不置 fell(pending 被清掉)。
@@ -32,7 +32,7 @@
#include "main.h"
#include "ucos_ii.h"

/* ---------- 硬件引脚(与 CubeMX / 方案书一致) ---------- */
/* ---------- 硬件引脚 ---------- */
#define PLSR_X4_PORT GPIOB
#define PLSR_X4_PIN GPIO_PIN_5 /* X4:WAIT/EXT 可选 */
#define PLSR_X5_PORT GPIOG
@@ -40,7 +40,7 @@

/*
* TIM5 时基:84MHz / (8399+1) = 10kHz → 100µs/格。
* PSC=8399 落在 16 位内;ms 级延时用 100µs 分辨率足够,不必 1µs 时基。
* PSC=8399 落在 16 位内
*/
#define PLSR_TIM5_PSC_100US 8399U
#define PLSR_TIM5_TICKS_PER_MS 10U /* 10×100µs = 1ms */
@@ -59,8 +59,8 @@ typedef struct {
uint16_t pin;
} PlsrEdge_t;

static PlsrEdge_t s_db_x4; /* X4 消抖状态 */
static PlsrEdge_t s_db_x5; /* X5 消抖状态 */
static PlsrEdge_t s_debounce_x4; /* X4 消抖状态 */
static PlsrEdge_t s_debounce_x5; /* X5 消抖状态 */
static volatile uint8_t s_delay_armed; /* 1=TIM5 单次延时正在计时 */

/** 毫秒 → OS tick 数(向上取整,至少 1 tick) */
@@ -81,49 +81,49 @@ static INT32U PlsrSignalIoMsToTicks(uint32_t ms)
}

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

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

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

if (db->pending == 0U)
if (debounce->pending == 0U)
{
return;
}

if (db->stamp_ok == 0U)
if (debounce->stamp_ok == 0U)
{
db->arm_tick = OSTimeGet();
db->stamp_ok = 1U;
debounce->arm_tick = OSTimeGet();
debounce->stamp_ok = 1U;
return;
}

need = PlsrSignalIoMsToTicks(PLSR_SIGNAL_DEBOUNCE_MS);
if ((OSTimeGet() - db->arm_tick) < need)
if ((OSTimeGet() - debounce->arm_tick) < need)
{
return;
}

db->pending = 0U;
db->stamp_ok = 0U;
if (PlsrSignalIoPinIsLow(db) != 0U)
debounce->pending = 0U;
debounce->stamp_ok = 0U;
if (PlsrSignalIoPinIsLow(debounce) != 0U)
{
db->fell = 1U;
debounce->fell = 1U;
}
}

@@ -164,14 +164,14 @@ static void PlsrSignalIoTim5Init(void)
{
__HAL_RCC_TIM5_CLK_ENABLE();

TIM5->CR1 = 0U;
TIM5->DIER = 0U;
TIM5->SR = 0U;
TIM5->PSC = PLSR_TIM5_PSC_100US;
TIM5->ARR = 0xFFFFFFFFUL;
TIM5->CNT = 0U;
TIM5->EGR = TIM_EGR_UG;
TIM5->SR = 0U;
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,这里再次清零中断标志

HAL_NVIC_SetPriority(TIM5_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(TIM5_IRQn);
@@ -181,29 +181,30 @@ void PlsrSignalIoInit(void)
{
s_delay_armed = 0U;

s_db_x4.port = PLSR_X4_PORT;
s_db_x4.pin = PLSR_X4_PIN;
s_db_x4.pending = 0U;
s_db_x4.stamp_ok = 0U;
s_db_x4.arm_tick = 0U;
s_db_x4.fell = 0U;
s_debounce_x4.port = PLSR_X4_PORT;
s_debounce_x4.pin = PLSR_X4_PIN;
s_debounce_x4.pending = 0U;
s_debounce_x4.stamp_ok = 0U;
s_debounce_x4.arm_tick = 0U;
s_debounce_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.stamp_ok = 0U;
s_db_x5.arm_tick = 0U;
s_db_x5.fell = 0U;
s_debounce_x5.port = PLSR_X5_PORT;
s_debounce_x5.pin = PLSR_X5_PIN;
s_debounce_x5.pending = 0U;
s_debounce_x5.stamp_ok = 0U;
s_debounce_x5.arm_tick = 0U;
s_debounce_x5.fell = 0U;

PlsrSignalIoGpioExtiInit();
PlsrSignalIoTim5Init();

//中断初始化时可能会进入中断,读取时需要结构体合法
//为了防止初始化终端后意外触发,需要再次清除标志位
__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;
s_debounce_x4.fell = 0U;
s_debounce_x4.pending = 0U;
s_debounce_x5.fell = 0U;
s_debounce_x5.pending = 0U;
}

void PlsrSignalIoScheduleDelayMs(uint32_t delay_ms)
@@ -266,31 +267,33 @@ uint32_t PlsrSignalIoDelayRemainMs(void)
return 0U;
}
left_ticks = (arr + 1U) - cnt;
/*会有个小bug。假定计数剩余个数655个,则要计数65.5ms,
该函数会向下取整,导致返回65ms。再次进来计数时就会误差0.5ms。理论最大误差1ms。*/
return left_ticks / PLSR_TIM5_TICKS_PER_MS;
}

void PlsrSignalIoDebouncePoll(void)
{
PlsrSignalIoDebounceConfirm(&s_db_x4);
PlsrSignalIoDebounceConfirm(&s_db_x5);
PlsrSignalIoDebounceConfirm(&s_debounce_x4);
PlsrSignalIoDebounceConfirm(&s_debounce_x5);
}

void PlsrSignalIoClearEdges(void)
{
s_db_x4.fell = 0U;
s_db_x4.pending = 0U;
s_db_x4.stamp_ok = 0U;
s_db_x5.fell = 0U;
s_db_x5.pending = 0U;
s_db_x5.stamp_ok = 0U;
s_debounce_x4.fell = 0U;
s_debounce_x4.pending = 0U;
s_debounce_x4.stamp_ok = 0U;
s_debounce_x5.fell = 0U;
s_debounce_x5.pending = 0U;
s_debounce_x5.stamp_ok = 0U;
}

void PlsrSignalIoClearPending(void)
{
s_db_x4.pending = 0U;
s_db_x4.stamp_ok = 0U;
s_db_x5.pending = 0U;
s_db_x5.stamp_ok = 0U;
s_debounce_x4.pending = 0U;
s_debounce_x4.stamp_ok = 0U;
s_debounce_x5.pending = 0U;
s_debounce_x5.stamp_ok = 0U;
}

uint8_t PlsrSignalIoTakeWaitFalling(void)
@@ -298,15 +301,15 @@ uint8_t PlsrSignalIoTakeWaitFalling(void)
/* wait_x_sel:0 代表 X4,1 代表 X5。读取后立即清掉该下降沿。 */
if (g_plsr_config.wait_x_sel == 0U)
{
if (s_db_x4.fell != 0U)
if (s_debounce_x4.fell != 0U)
{
s_db_x4.fell = 0U;
s_debounce_x4.fell = 0U;
return 1U;
}
}
else if (s_db_x5.fell != 0U)
else if (s_debounce_x5.fell != 0U)
{
s_db_x5.fell = 0U;
s_debounce_x5.fell = 0U;
return 1U;
}
return 0U;
@@ -317,15 +320,15 @@ uint8_t PlsrSignalIoTakeExtFalling(void)
/* ext_x_sel:0 代表 X4,1 代表 X5。读取后立即清掉该下降沿。 */
if (g_plsr_config.ext_x_sel == 0U)
{
if (s_db_x4.fell != 0U)
if (s_debounce_x4.fell != 0U)
{
s_db_x4.fell = 0U;
s_debounce_x4.fell = 0U;
return 1U;
}
}
else if (s_db_x5.fell != 0U)
else if (s_debounce_x5.fell != 0U)
{
s_db_x5.fell = 0U;
s_debounce_x5.fell = 0U;
return 1U;
}
return 0U;
@@ -351,7 +354,7 @@ void PlsrSignalIoOnExti9_5(void)
if (__HAL_GPIO_EXTI_GET_IT(PLSR_X4_PIN) != 0U)
{
__HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN);
PlsrSignalIoOnFalling(&s_db_x4);
PlsrSignalIoOnFalling(&s_debounce_x4);
}
}

@@ -360,6 +363,6 @@ void PlsrSignalIoOnExti15_10(void)
if (__HAL_GPIO_EXTI_GET_IT(PLSR_X5_PIN) != 0U)
{
__HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN);
PlsrSignalIoOnFalling(&s_db_x5);
PlsrSignalIoOnFalling(&s_debounce_x5);
}
}

+ 3
- 20
plsr/signal_io/plsr_signal_io.h 查看文件

@@ -14,26 +14,11 @@
* 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 调用)
* TIM5 单次延时用途
* - 方向切换延时 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_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
#define PLSR_SIGNAL_IO_H
@@ -42,13 +27,11 @@

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

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

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


Loading…
取消
儲存