Files
DLD154V4B/tests/test_red_breath.c
T
wangfq cd0fd90770 feat(V4B): V4.23 — 红灯呼吸对齐vd960Loop(≈2.6s) + 上电自检基准判稳
现场测试 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 兜底)
2026-09-02 16:26:03 +08:00

105 lines
3.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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;
}