现场测试 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 兜底)
141 lines
4.5 KiB
C
141 lines
4.5 KiB
C
/*
|
||
* test_power_on_stable.c — 上电自检: 基准值稳定后才结束自检 (V4.23)
|
||
*
|
||
* 背景: 原逻辑 _stable_cnt 达 128 样本(≈1.3s)即判稳, 与"基准值是否真稳定"无关;
|
||
* 且 static 计数不清零, 二次稳定期(安全复位)1 个样本即判稳(绿灯自检形同虚设)。
|
||
* 修复: 稳定期累计样本 g_stable_cnt + 连续窗口 Origin 均值漂移 ≤0.1% 的
|
||
* g_settle_cnt; 两者达标才 g_loop_stable=1; 硬兜底 500 样本(5s)。
|
||
*
|
||
* 验证:
|
||
* 1. 干净常量值 → 第 200 样本判稳 (窗口100/200 两次漂移 0)
|
||
* 2. 首窗 Origin 尖峰(1.3×) → 多等一窗, 第 300 样本判稳
|
||
* 3. 持续漂移(每窗 +500, >0.1% 带) → 永不 settle, 第 500 样本硬兜底判稳
|
||
* 4. 判稳退出后计数清零, 二次稳定期重新从 0 累计(不瞬间判稳)
|
||
*
|
||
* 编译: gcc -Wall -o test_power_on_stable test_power_on_stable.c && ./test_power_on_stable
|
||
*===========================================================================*/
|
||
#include <stdio.h>
|
||
#include <stdint.h>
|
||
#include <assert.h>
|
||
|
||
#define WIN 100 /* 稳定期小窗口 */
|
||
#define STABLE_SAMPLES 128 /* 稳定期最少样本数 */
|
||
#define STABLE_ORIGIN_PPT 1 /* 0.1% */
|
||
#define STABLE_SETTLE_WINDOWS 2
|
||
#define STABLE_MAX_SAMPLES 500
|
||
|
||
static uint32_t origin;
|
||
static uint32_t g_origin_prev;
|
||
static uint16_t g_stable_cnt;
|
||
static uint16_t g_settle_cnt;
|
||
static uint8_t g_loop_stable;
|
||
|
||
/* 仿真 vd1_task 稳定期单样本处理; 返回 1=本样本判稳 */
|
||
static int stable_step(uint32_t value)
|
||
{
|
||
static uint32_t sum = 0;
|
||
static uint16_t cnt = 0;
|
||
uint32_t prev_origin;
|
||
int win_done = 0;
|
||
|
||
if (g_loop_stable) return 1;
|
||
if (origin == 0) return 0;
|
||
|
||
prev_origin = origin;
|
||
sum += value; cnt++;
|
||
g_stable_cnt++;
|
||
if (cnt >= WIN) {
|
||
win_done = 1;
|
||
origin = sum / WIN;
|
||
sum = 0; cnt = 0;
|
||
}
|
||
if (win_done) {
|
||
uint32_t drift = (origin > prev_origin) ? (origin - prev_origin)
|
||
: (prev_origin - origin);
|
||
uint32_t band = (uint32_t)(origin * STABLE_ORIGIN_PPT / 1000);
|
||
if (drift <= band) {
|
||
if (g_settle_cnt < 0xFFFF) g_settle_cnt++;
|
||
} else {
|
||
g_settle_cnt = 0;
|
||
}
|
||
}
|
||
|
||
if ((g_stable_cnt >= STABLE_SAMPLES &&
|
||
g_settle_cnt >= STABLE_SETTLE_WINDOWS) ||
|
||
g_stable_cnt >= STABLE_MAX_SAMPLES) {
|
||
g_loop_stable = 1;
|
||
g_stable_cnt = 0;
|
||
g_settle_cnt = 0;
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static void reset(uint32_t initial_origin)
|
||
{
|
||
origin = initial_origin;
|
||
g_origin_prev = 0;
|
||
g_stable_cnt = 0;
|
||
g_settle_cnt = 0;
|
||
g_loop_stable = 0;
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
const uint32_t BASE = 128844UL;
|
||
int i, done;
|
||
|
||
/* --- 1. 干净常量值: 第 200 样本判稳 --- */
|
||
reset(BASE);
|
||
done = 0;
|
||
for (i = 1; i <= 600 && !done; i++) {
|
||
done = stable_step(BASE);
|
||
if (done) break;
|
||
}
|
||
printf("1. 常量值 判稳样本=%d (期望 200)\n", i);
|
||
assert(i == 200);
|
||
assert(g_stable_cnt == 0 && g_settle_cnt == 0);
|
||
|
||
/* --- 2. 首窗 Origin 尖峰(1.3×, 实际值正常): 第 300 样本判稳 --- */
|
||
reset((uint32_t)(BASE * 1.3));
|
||
done = 0;
|
||
for (i = 1; i <= 600 && !done; i++) {
|
||
done = stable_step(BASE);
|
||
if (done) break;
|
||
}
|
||
printf("2. 首窗尖峰 判稳样本=%d (期望 300)\n", i);
|
||
assert(i == 300);
|
||
|
||
/* --- 3. 持续漂移: 每窗均值 +500 (>0.1% 带) → 硬兜底 500 --- */
|
||
reset(BASE);
|
||
done = 0;
|
||
for (i = 1; i <= 600 && !done; i++) {
|
||
uint32_t w = (uint32_t)((i - 1) / WIN);
|
||
done = stable_step(BASE + 500UL * w);
|
||
if (done) break;
|
||
}
|
||
printf("3. 持续漂移 判稳样本=%d (期望 500 硬兜底)\n", i);
|
||
assert(i == 500);
|
||
|
||
/* --- 4. 二次稳定期: 计数清零, 重新累计 → 第 200 样本判稳(非 1 样本) --- */
|
||
reset(BASE);
|
||
done = 0;
|
||
for (i = 1; i <= 600 && !done; i++) {
|
||
done = stable_step(BASE);
|
||
if (done) break;
|
||
}
|
||
assert(i == 200); /* 第一次完成 */
|
||
/* 模拟安全复位: 仅清 g_loop_stable, 计数应已是 0 */
|
||
g_loop_stable = 0;
|
||
done = 0;
|
||
for (i = 1; i <= 600 && !done; i++) {
|
||
done = stable_step(BASE);
|
||
if (done) break;
|
||
}
|
||
printf("4. 二次稳定期 判稳样本=%d (期望 200, 修掉原 1 样本瞬间判稳)\n", i);
|
||
assert(i == 200);
|
||
|
||
printf("ALL PASS (test_power_on_stable)\n");
|
||
return 0;
|
||
}
|