现场测试 DLD154V4 反馈两问题修复:
1. 红灯呼吸太快 → 借鉴 vd960Loop 效果 (main.c poll_red_pwm)
- 参数按 665/6800 缩放取整: 大步 100→39(≈5.9%), 近顶 20→10(≈1.5%),
分界 585(88%), 峰值保持 660×3 步
- 周期 ≈1.6s → ≈2.6s (仿真 42 步×60ms=2520ms)
2. 绿灯上电自检闪到"稳定基准值"才停 (TaskLoop.c 稳定期判稳)
- 根因: 固定 128 样本即判稳, 与基准是否稳定无关; static 计数不清零,
二次稳定期(安全复位)1 样本瞬间判稳
- 修复: 全局 g_stable_cnt/g_settle_cnt, 每窗(100样本≈1s)Origin 均值
漂移 ≤0.1% → settle++, 连续 2 窗 + 最少 128 样本判稳; 硬兜底 500
样本(5s); 计数判稳退出/INIT_VD 清零
验证: tests/test_power_on_stable.c (200/300/500/200 样本 PASS),
tests/test_red_breath.c (周期 2520ms/峰值保持/写值≤ARR PASS),
gcc -fsyntax-only 两文件 0 error (借 vd960Loop AT32F421 库头)
文档: devlog 置顶 + 修订表回填 V2.12~V2.20 + V2.21; product-manual §5.1/
核心特性; technical-spec V2.2 (§5.2 参数表/§7 判稳语义/§15 修订记录)
待现场验证: 呼吸观感、绿灯自检时长 (无车 2~3s / 首窗尖峰 3s / 5s 兜底)
105 lines
3.5 KiB
C
105 lines
3.5 KiB
C
/*
|
||
* test_red_breath.c — 红灯呼吸节奏回归 (V4.23, 对齐 vd960Loop 效果)
|
||
*
|
||
* 复刻 main.c poll_red_pwm (V4.23) 逻辑, mock tmr_channel_value_set 记录写值:
|
||
* - PWM 满量程 665, 60ms/步 (12×5ms)
|
||
* - 期望: 每写值 ∈ [0, 665]; 峰值保持 ≥3 步;
|
||
* - 全周期(两次最暗之间) ≈ 43 步 × 60ms ≈ 2.58s ∈ [2.4, 2.8]s
|
||
*
|
||
* 编译: gcc -Wall -o test_red_breath test_red_breath.c && ./test_red_breath
|
||
*===========================================================================*/
|
||
#include <stdio.h>
|
||
#include <stdint.h>
|
||
#include <assert.h>
|
||
|
||
#define RED_BREATH_ARR 665
|
||
#define RED_STEP_BIG 39
|
||
#define RED_STEP_SMALL 10
|
||
#define RED_SPLIT 585
|
||
#define RED_HOLD_LEVEL 660
|
||
#define RED_HOLD_TICKS 3
|
||
#define RED_STEP_TICKS 12
|
||
#define TICK_MS 5
|
||
|
||
static uint16_t pulse;
|
||
static uint8_t g_pulse_counter;
|
||
static uint8_t g_flag_pulse;
|
||
static uint8_t g_cnt_pwm_red_low_timeout;
|
||
|
||
static uint16_t last_written = 0xFFFF;
|
||
static unsigned write_cnt = 0;
|
||
|
||
static void tmr_channel_value_set_mock(uint16_t v) { last_written = v; write_cnt++; }
|
||
|
||
/* 与 main.c 相同的实现 */
|
||
static void poll_red_pwm(void)
|
||
{
|
||
g_pulse_counter++;
|
||
if (g_pulse_counter >= RED_STEP_TICKS) {
|
||
g_pulse_counter = 0;
|
||
if (g_flag_pulse) {
|
||
if (pulse < RED_SPLIT)
|
||
pulse += RED_STEP_BIG;
|
||
else
|
||
pulse += RED_STEP_SMALL;
|
||
|
||
if (pulse >= RED_BREATH_ARR) {
|
||
g_cnt_pwm_red_low_timeout++;
|
||
if (g_cnt_pwm_red_low_timeout >= RED_HOLD_TICKS) {
|
||
g_flag_pulse = 0;
|
||
g_cnt_pwm_red_low_timeout = 0;
|
||
}
|
||
pulse = RED_HOLD_LEVEL;
|
||
}
|
||
} else {
|
||
if (pulse <= RED_STEP_BIG) {
|
||
pulse = 0;
|
||
g_flag_pulse = 1;
|
||
} else {
|
||
pulse -= RED_STEP_BIG;
|
||
}
|
||
}
|
||
tmr_channel_value_set_mock(pulse);
|
||
}
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
unsigned calls, steps;
|
||
unsigned dark_events[8], di = 0;
|
||
unsigned hold_cnt_max = 0, hold_cnt = 0;
|
||
|
||
pulse = 0; g_pulse_counter = 0; g_flag_pulse = 1;
|
||
g_cnt_pwm_red_low_timeout = 0; write_cnt = 0;
|
||
|
||
/* 跑约 5 个完整周期; 每个写值事件后置回哨兵, 只在写值步统计 */
|
||
for (calls = 1; calls <= 2600; calls++) {
|
||
poll_red_pwm();
|
||
if (last_written != 0xFFFF) {
|
||
assert(last_written <= RED_BREATH_ARR);
|
||
if (last_written >= 640) { /* 峰值区保持观测(按写值步) */
|
||
hold_cnt++;
|
||
if (hold_cnt > hold_cnt_max) hold_cnt_max = hold_cnt;
|
||
} else {
|
||
hold_cnt = 0;
|
||
}
|
||
if (last_written == 0 && di < 8) {
|
||
dark_events[di++] = calls; /* 最暗写值时刻 */
|
||
if (di >= 2) break;
|
||
}
|
||
last_written = 0xFFFF; /* 事件已消费 */
|
||
}
|
||
}
|
||
assert(di >= 2);
|
||
steps = (dark_events[1] - dark_events[0]) / RED_STEP_TICKS;
|
||
double cycle_ms = (double)(dark_events[1] - dark_events[0]) * TICK_MS;
|
||
|
||
printf("周期步数=%u (≈43), 周期时长=%.0fms (期望 2400~2800ms)\n", steps, cycle_ms);
|
||
printf("峰值连续保持写值步数(≥3 步, 含下降第一步)≈%u\n", hold_cnt_max);
|
||
assert(cycle_ms >= 2400 && cycle_ms <= 2800);
|
||
assert(steps >= 40 && steps <= 46);
|
||
assert(hold_cnt_max >= 3);
|
||
printf("ALL PASS (test_red_breath), write_cnt=%u\n", write_cnt);
|
||
return 0;
|
||
}
|