Browse Source

修复起始脉冲重复输出

dev1
hanyongwei 3 weeks ago
parent
commit
183bd22770
5 changed files with 1592 additions and 790 deletions
  1. +2
    -2
      .gitignore
  2. +1481
    -752
      iar/plsr.dep
  3. +40
    -1
      plsr/accel_curve/plsr_accel_curve.c
  4. +3
    -5
      plsr/pulse_driver/plsr_pulse_driver.c
  5. +66
    -30
      plsr/run_control/plsr_run_control.c

+ 2
- 2
.gitignore View File

@@ -15,7 +15,6 @@ iar/modbus/Exe/
iar/modbus/List/
iar/modbus/Obj/
iar/Backup of modbus.ewp
host/
iar/settings/modbus.reggroups
build-plsr_host-Desktop_Qt_5_6_3_MinGW_32bit-Debug/
plsr/test/
@@ -23,4 +22,5 @@ tools/
.cursor/
PLSR测试大纲.html
_gen_outline_p1.py
run_control_full.txt
run_control_full.txt
plsr/README.md

+ 1481
- 752
iar/plsr.dep
File diff suppressed because it is too large
View File


+ 40
- 1
plsr/accel_curve/plsr_accel_curve.c View File

@@ -1631,7 +1631,46 @@ uint32_t PlsrAccelNextFrequency(PlsrAccelRuntime_t *runtime)
}
else if (runtime->curve_mode == PLSR_ACCEL_LINEAR)
{
/* 直线由 SquareStep 钳位 */
/*
* 未到本相最后一拍:不要钳到 end。
* 否则减速在 n=N-1 就落到止速,ARPE 下会表现为末两拍同频。
*/
if (runtime->frequency_rising == 0U)
{
if ((runtime->current_frequency_hz <= runtime->end_frequency_hz) &&
(runtime->end_frequency_hz < 100000U))
{
runtime->current_frequency_hz = runtime->end_frequency_hz + 1U;
}
}
else if ((runtime->current_frequency_hz >= runtime->end_frequency_hz) &&
(runtime->end_frequency_hz > 1U) &&
(runtime->total_pulses > 0U) &&
(runtime->completed_pulses < runtime->total_pulses))
{
runtime->current_frequency_hz = runtime->end_frequency_hz - 1U;
}
}
else if (runtime->frequency_table_id != 0U)
{
/* 查表:最后一拍之前若已是 end,同样让出 1Hz */
if ((runtime->total_pulses > 0U) &&
(runtime->completed_pulses < runtime->total_pulses))
{
if (runtime->frequency_rising == 0U)
{
if ((runtime->current_frequency_hz <= runtime->end_frequency_hz) &&
(runtime->end_frequency_hz < 100000U))
{
runtime->current_frequency_hz = runtime->end_frequency_hz + 1U;
}
}
else if ((runtime->current_frequency_hz >= runtime->end_frequency_hz) &&
(runtime->end_frequency_hz > 1U))
{
runtime->current_frequency_hz = runtime->end_frequency_hz - 1U;
}
}
}
else if (runtime->frequency_table_id == 0U)
{


+ 3
- 5
plsr/pulse_driver/plsr_pulse_driver.c View File

@@ -790,8 +790,9 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz)
}

/*
* 冷启动首拍:无论下一频是否变化,先把工作 ARR 钉回起跳频,再开预装载。
* 必须在「freq==last 早退」之前做,否则首拍保护标志清不掉。
* 冷启动首拍:只把工作 ARR 钉回起跳频,再开预装载。
* 影子不要钉成起跳——下面立刻写入的下一拍频率才应进入影子;
* 若此处把影子也钉回起跳且 next==start 早退,会让第 2 拍再跑一遍起跳频。
*/
if (s_protect_start_period != 0U)
{
@@ -802,9 +803,6 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz)
htim->Instance->CCR1 = (s_protect_ccr < 1U) ? 1U : s_protect_ccr;
htim->Instance->CR1 |= TIM_CR1_ARPE;
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;
/* 影子也先钉成起跳,下面再写入真正的下一拍频率 */
htim->Instance->ARR = s_protect_arr;
htim->Instance->CCR1 = (s_protect_ccr < 1U) ? 1U : s_protect_ccr;
}
else
{


+ 66
- 30
plsr/run_control/plsr_run_control.c View File

@@ -37,8 +37,10 @@
* 5) s_segment_pulses_done >= target → OPM 末拍 or 立刻 AfterSegDone
* 6) 按 s_phase 改频:CONST 只进减速;APPROACH Step;DECEL Step
*
* ARPE 补偿(为何 remain==dec_n+1 才进减速):
* 本拍 ISR 写的 ARR 要「再下一拍」才生效;故须提前一拍写入 f_end。
* 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) → 梯形/三角;
@@ -59,14 +61,14 @@
* 【运行节拍】纯脉冲计数:
* UPDATE ISR:s_segment_pulses_done++;末拍用 ArmSegEndStop 完整收尾;
* 加/减速逐拍 PlsrAccelNextFrequency + SetFreqIsr;
* 匀速复用 ARR(不改频);remain<=dec_n+1 进减速(补偿 ARR 预装载晚一拍)
* 匀速复用 ARR(不改频);remain<=dec_n 进减速。
* 任务 TickMs:ACT(OS 节拍)/ EXT / ApplyPending;
* TIM5 one-shot:换向/WAIT/ACT/ACT剩余;ACT 到期收完当前脉冲并锁低,周期边界再切段。
* PlsrTask:DebouncePoll + TickMs + WakePend。
*
* 【段末频率 / ARPE】预装载开启时,本拍写的 ARR 要到再下一拍才生效;
* 若不超前,末拍实际是 f(N-1)≈sqrt(f_end^2+2a),示波器偶发「末频偏高」
* 减速在 remain==dec_n+1 切入;纯减速开表再预装一拍
* 【段末频率 / 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 末拍下降沿拉低),
@@ -859,9 +861,9 @@ static uint32_t PlsrRunControlRemainPulses(void)
}

/**
* ARPE:本拍 ISR 写入的 ARR 要到「再下一拍」才被计数器使用
* 故在 remain==dec_n+1 时进入并写入 f(1),末拍才能吃到 f_end
* 若已晚进(remain<=dec_n),预算改为 remain-1,仍保证 remain==2 时落到止速。
* ARPE:本拍 ISR 写入的影子 ARR 在下一周期生效
* remain==dec_n 时切入并写入 f(1),…,remain==1 写入 f_end → 末拍为止速
* 若已晚进(remain < planned),预算用满剩余拍数,避免再减 1 导致末两拍同为止速。
*/
static uint8_t PlsrRunControlShouldEnterDecel(uint32_t remain)
{
@@ -869,7 +871,7 @@ static uint8_t PlsrRunControlShouldEnterDecel(uint32_t remain)
{
return 0U;
}
return (remain <= (g_plsr_accel_plan.decel_pulses + 1U)) ? 1U : 0U;
return (remain <= g_plsr_accel_plan.decel_pulses) ? 1U : 0U;
}

static uint32_t PlsrRunControlDecelEnterBudget(uint32_t remain)
@@ -880,15 +882,15 @@ static uint32_t PlsrRunControlDecelEnterBudget(uint32_t remain)
{
planned = 1U;
}
if (remain > planned)
if (remain >= planned)
{
return planned;
}
if (remain > 1U)
if (remain < 1U)
{
return remain - 1U;
return 1U;
}
return 1U;
return remain;
}

/** 绝对模式:相对本次启动原点的位置 */
@@ -897,6 +899,38 @@ static int32_t PlsrRunControlAbsLocalPos(void)
return g_plsr_accumulated_pulses - s_absolute_origin;
}

/**
* 减速相写出频率:仅 remain==1(供末拍)允许钉止速;
* 更早写入若已碰到 end,则让出 1Hz,避免末两拍同频。
*/
static uint32_t PlsrRunControlDecelOutFreq(uint32_t profile_freq, uint32_t remain)
{
uint32_t end_hz = g_plsr_accel_plan.end_frequency_hz;

if (end_hz < 1U)
{
end_hz = 1U;
}

if (remain <= 1U)
{
return end_hz;
}

if (g_plsr_accel_runtime.frequency_rising == 0U)
{
if ((profile_freq <= end_hz) && (end_hz < 100000U))
{
return end_hz + 1U;
}
}
else if ((profile_freq >= end_hz) && (end_hz > 1U))
{
return end_hz - 1U;
}
return profile_freq;
}

/**
* @brief 进入减速相:budget 为曲线步进总数(非物理 remain),BeginDec
*/
@@ -919,7 +953,8 @@ static void PlsrRunControlEnterDecel(uint32_t from_hz, uint32_t budget)
}

/**
* 开表纯减速:Start(f1) 后再预装 f2,补偿 ARPE,使第 N 拍为 f_end。
* 开表纯减速:只 Start(f1)。下一拍起由 ISR NextFrequency 写入 f2…f_end。
* (旧逻辑再预装 f2 会在 ARPE 下让首拍直接吃到 f2,并多步进一次。)
*/
static void PlsrRunControlPrimeDecelOnStart(void)
{
@@ -927,11 +962,6 @@ static void PlsrRunControlPrimeDecelOnStart(void)

next = PlsrAccelNextFrequency(&g_plsr_accel_runtime);
PlsrRunControlApplyOutFreq(next, 1U);
if (g_plsr_accel_runtime.total_pulses > 1U)
{
next = PlsrAccelNextFrequency(&g_plsr_accel_runtime);
PlsrPulseDriverSetFreq(next);
}
}

/** 离开加速相时触发 0x03 加速诊断(仅当前相为 APPROACH 时有效) */
@@ -989,7 +1019,7 @@ static void PlsrRunControlEnterConstHoldIsr(void)
* 【分支顺序】
* 1) CONST 且 remain 进减速窗 → EnterDecel,return 前不 Start
* 2) CONST → 仅 do_start 时 Start(f_tgt),return
* 3) DECEL 且刚开段(n=0) → PrimeDecelOnStart(预装两拍,补 ARPE
* 3) DECEL 且刚开段(n=0) → PrimeDecelOnStart(Start(f1),其余交 ISR
* 4) APPROACH → FreqAtPulse(done_n);若已到 f_tgt 则进 CONST 或 DECEL
* 5) 其它 → ApplyOutFreq(next, do_start)
*/
@@ -1022,7 +1052,7 @@ static void PlsrRunControlRefreshProfile(uint8_t do_start)
return;
}

/* 纯减速开表:超前预装,避免末拍停在 f(N-1) */
/* 纯减速开表:Start(f1),f2…f_end 由后续 UPDATE ISR 写入 */
if ((s_phase == PH_DECEL) &&
(do_start != 0U) &&
(s_segment_pulses_done == 0) &&
@@ -1348,13 +1378,17 @@ static void PlsrRunControlBeginSeg(uint16_t seg_idx0)
{
/* 分支 A:段间无缝(FOLLOW 或 ACT handoff) */
PlsrPulseDriverClearOnePulseStop();
/*
* 必须先 RC_RUN 再 RefreshProfile/Start:否则冷启动首拍 UPDATE 时
* OnPulseIsr 仍见非 RUN 直接 return,影子停在起跳频,第 1、2 拍同频。
*/
s_state = RC_RUN;
s_continue_without_stopping = 0U;
/*
* FOLLOW 真不停表:do_start=0 只改频。
* ACT 经 OPM 边界停表后 g_plsr_pwm_running 已为 0:须 Start 重开,否则无脉冲卡死。
*/
PlsrRunControlRefreshProfile((g_plsr_pwm_running == 0U) ? 1U : 0U);
s_state = RC_RUN;
s_continue_without_stopping = 0U;
PlsrRunControlArmActExtOnPulseStart();
}
else if ((g_plsr_direction_valid != 0U) && (s_forward == g_plsr_direction_forward))
@@ -1782,6 +1816,8 @@ void PlsrOnPulseIsr(void)
PlsrRunControlEnterDecel(g_plsr_accel_plan.target_frequency_hz,
PlsrRunControlDecelEnterBudget(remain));
next = PlsrAccelNextFrequency(&g_plsr_accel_runtime);
next = PlsrRunControlDecelOutFreq(next, remain);
g_plsr_accel_runtime.current_frequency_hz = next;
PlsrRunControlApplyOutFreqIsr(next);
}
}
@@ -1805,6 +1841,8 @@ void PlsrOnPulseIsr(void)
PlsrRunControlEnterDecel(next,
PlsrRunControlDecelEnterBudget(remain));
next = PlsrAccelNextFrequency(&g_plsr_accel_runtime);
next = PlsrRunControlDecelOutFreq(next, remain);
g_plsr_accel_runtime.current_frequency_hz = next;
PlsrRunControlApplyOutFreqIsr(next);
}
else
@@ -1820,23 +1858,21 @@ void PlsrOnPulseIsr(void)
else /* PH_DECEL */
{
/*
* remain==1:末拍已在跑(ARR 在 remain==2 时写入),勿再 Step,
* 以免 n 超过 budget 误触 0x03
* ARPE:remain==k 写入 → 下一拍使用。
* remain==1 必须写出 f_end(末拍);remain>1 禁止提前钉止速
*/
if ((remain <= 1U) &&
(g_plsr_accel_runtime.total_pulses > 0U) &&
(g_plsr_accel_runtime.completed_pulses >= g_plsr_accel_runtime.total_pulses))
{
next = g_plsr_accel_plan.end_frequency_hz;
if (next < 1U)
{
next = 1U;
}
}
else
{
next = PlsrAccelNextFrequency(&g_plsr_accel_runtime);
}
next = PlsrRunControlDecelOutFreq(next, remain);
g_plsr_accel_runtime.current_frequency_hz = next;
PlsrRunControlApplyOutFreqIsr(next);
}
}


Loading…
Cancel
Save