☰
中科蓝讯SDK开发-BT897X、BT891X、AB573X、AB572X 系列 自定义NTC过温放电/充电状态下保护功能教程
2026/11/5 2:01:30 网站建设 项目流程

前言

现在为止也开发了许多杰理,中科蓝讯TWS蓝牙耳机、音响项目 SDK的案子,在调试案子时不断的向前辈们学习到了很多关于蓝牙音响、蓝牙TWS耳机专业的知识。想在这里做一个学习汇总,方便各位同行和对杰理芯片SDK感兴趣的小伙伴们学习;

本章详细讲解中科蓝讯SDK开发-BT897X、BT891X、AB573X、AB572X 系列 自定义NTC过温放电/充电状态下保护功能教程

1. 功能需求

场景温度异常动作当前状态
耳机放电(正常使用)过高 或 过低自动关机两路默认关闭,验证后再开
耳机充电(开机、关机充电都算)过高 或 过低停止充电,绝不关机✅ 已实测通过
充电停充后温度恢复到恢复阈值自动复充(滞回,防临界抖动)✅ 已实测通过

四路保护(放电高温、放电低温、充电高温、充电低温)各自独立开关,阈值、恢复阈值、防抖次数全部用 config.h 宏配置。

2. 原理:温度怎么变成"关机/停充"动作

2.1 NTC 测温电路与公式

上拉电阻 R_up ──┬── ADC 引脚(PE7) (接常供电源)│ R_ntc(NTC 热敏电阻) │ GND
  • NTC 是负温度系数热敏电阻:温度越高,阻值越小;
  • 两个电阻串联分压,ADC 读分压点电压,得到 8bit 读数(满量程 255):
ADC = 255 × R_ntc / (R_up + R_ntc)
  • 上拉电阻的供电必须是常供且电压恒定的电源(踩坑见 7.1:接 VDDMIC 会 ADC 恒 0)。

方向约定(本教程一切判断的基础):

温度变化NTC 阻值ADC 值
温度升高变小变小
温度降低变大变大

所以判断规则只有两条:

  • ADC ≤ 高温阈值→ 温度过高
  • ADC ≥ 低温阈值→ 温度过低

2.2 软件骨架:两条检测线

放电和充电的保护动作不同(关机 vs 停充)、运行环境不同(中断 vs 充电循环),所以拆成两条线:

放电线:5ms 中断 usr_tmr5ms_thread()(system.c L246) └─ sys_ntc_check()(L255-257 挂载) 越界 100ms → sys_cb.pwroff.ntc_ind = 1 → 主循环 pwroff_process()(func.c L584→L234)→ 播关机提示音 → 关机 充电线:充电流程 5ms 函数 sfunc_charge_process()(func_charge.c L103) └─ user_ntc_charge_check()(L109-113 挂载) 越界 100ms → CHARGE_OFF() 停充 到达恢复阈值 100ms → 复充

为什么充电要单独一条线:

充电时耳机运行在专用循环里,不处理关机标志:

  • 开机后插电:进入充电功能态循环func_charge_process()(func_charge.c L164 附近每 5ms 调sfunc_charge_process());
  • 关机状态插电:运行power_on_check()充电循环(system.c L612 每 5ms 调sfunc_charge_process())。

这两个循环每 5ms 都调用同一个函数sfunc_charge_process(),所以充电检测挂进去一处,就同时覆盖两种充电场景。而且充电异常不能关机——用户正插着电,耳机"自杀"体验极差。

两条线互斥,互不干扰:

  • 放电检测函数开头看到"正在充电"就直接返回(充电场景归充电线管);
  • 充电检测函数只在充电流程里被调,正常使用时根本不跑。

2.3 三个关键基础设施

① SARADC 缓存式采样。saradc_get_value8(ADCCH_NTC)不是当场启动转换,而是读后台扫描缓存。缓存由 5ms 中断里的 SARADC 处理流程每 5ms 刷新一轮;采样通道在 adkey.c L32-39 使能(Downloader 勾了"是否使能NTC",才把 PE7 加进扫描列表)。含义:读到的永远是"最近一轮"的值,不是瞬间值——这也是后面方案 C 讲供电时序时要用的关键事实。

② 5ms 节奏。两条检测线都是每 5ms 跑一次,所以防抖 20 次 = 100ms。所有 static 计数器都是"跨调用累计"的(5ms 调一次,static 不清零,一直累加)。

③ 动作链路全公版,我们只需要置标志/操作寄存器:

  • 关机链路:置sys_cb.pwroff.ntc_ind = 1→ 主循环每轮调pwroff_process()(func.c L234-270)→ 发现all_flag != 0→ 播关机提示音 →func_cb.sta = FUNC_PWROFF→ 公版自动完成断链、关机。
  • 停充/复充:直接操作充电寄存器(宏来自 api_charge.h):
    • 停充CHARGE_OFF()(L57)=RTCCON8 |= BIT(1); RTCCON8 &= ~BIT(6);
    • 复充是它的逆操作 =RTCCON8 |= BIT(6); RTCCON8 &= ~BIT(1);
    • CHARGE_DC_IN()(L50)= 读 RTCCON 位 20,判断是否处于 DC 充电状态。

3. 主方案实现步骤(本工程采用芯片内部上拉电阻10K的方式)

3.1 第 1 步:config.h 添加配置宏(L14-44)

所有开关和参数都集中在这里,改功能先看这里:不管采用什么方案直接复制这里宏定义就好;

/***************************************************************************** * LYF_NTC过温保护配置 *****************************************************************************/ //自定义NTC过温保护功能总开关 #define LYF_USER_NTC_EN 1 //阈值计算公式:ADC值 = 当前热敏电阻温度阻值 / (当前热敏电阻温度阻值 +(内部/外部)上拉电阻阻值) * 255 //NTC四路保护独立开关:1=启用该路判断,0=停用 #define LYF_USER_NTC_DISCHARGE_HIGH_EN 0 //放电·高温→关机(默认开) #define LYF_USER_NTC_DISCHARGE_HIGH_TEMP_THD 59 //放电·高温截止:60°C → ADC≈59 #define LYF_USER_NTC_DISCHARGE_LOW_EN 0 //放电·低温→关机(默认关) #define LYF_USER_NTC_DISCHARGE_LOW_TEMP_THD 209 //放电·低温截止:-10°C → ADC≈209 #define LYF_USER_NTC_CHARGE_HIGH_EN 1 //充电·高温→停充(默认开) #define LYF_USER_NTC_CHARGE_HIGH_TEMP_THD 84 //充电·高温截止:45°C → ADC≈84 #define LYF_USER_NTC_CHARGE_LOW_EN 1 //充电·低温→停充(默认关) #define LYF_USER_NTC_CHARGE_LOW_TEMP_THD 187 //充电·低温截止:0°C → ADC≈187 //NTC充电复充开关:1=温度回到窗口内自动复充;0=停充后保持,拔出重插才恢复 #define LYF_USER_NTC_CHARGE_RECOVER_EN 1 //NTC充电复充恢复阈值(滞回控制:与截止阈值错开,防止临界温度反复停充/复充) #define LYF_USER_NTC_CHARGE_HIGH_RECOVER_THD 90 //充电·高温恢复:约42°C(须 > 高温截止84,滞回约5°C) //低温停充后:温度需升得足够高才复充,判断条件 adc <= 该值(该值须 < 低温截止阈值) #define LYF_USER_NTC_CHARGE_LOW_RECOVER_THD 180 //充电·低温恢复:约3°C(须 < 低温截止187,滞回约5°C) //NTC防抖次数:连续 N 个检测周期(5ms)越界才动作,滤除 ADC 抖动。20×5ms=100ms #define LYF_USER_NTC_DEBOUNCE_CNT 20 //NTCADC日志log打印总开关 #define LYF_USER_NTC_ADC_LOG_EN 1

3.2 第 2 步:config.h中和Downloader中将原厂相关NTC相关宏打开并选择好检测ADC通道引脚和开启内部10K电阻

3.3 第 3 步:system.c 放电检测函数(L54-106)

自定义实现放电检测函数,不采用公版软件的放电检测函数

#if LYF_USER_NTC_EN #if USER_NTC AT(.com_text.ntc) u8 sys_ntc_check(void) { // ① Downloader 的 NTC 总开关("是否使能NTC"),没使能就直接返回 if (!xcfg_cb.ntc_en) { return 0; } // ② 充电时不做放电检测:充电的温度保护由充电检测函数负责(见 3.3) if (CHARGE_DC_IN()) { return 0; } // ③ 读 NTC 分压点的 8bit ADC 值 // 温度越高 → NTC 阻值越小 → ADC 值越小 u8 adc = saradc_get_value8(ADCCH_NTC); // ④ 越界判断:ADC ≤ 高温阈值 = 温度过高;ADC ≥ 低温阈值 = 温度过低 u8 dis_over = 0; // dis_over = 是否越出允许放电的温度窗口 #if LYF_USER_NTC_DISCHARGE_HIGH_EN if (adc <= LYF_USER_NTC_DISCHARGE_HIGH_TEMP_THD) { // 高温越界 dis_over = 1; } #endif #if LYF_USER_NTC_DISCHARGE_LOW_EN if (adc >= LYF_USER_NTC_DISCHARGE_LOW_TEMP_THD) { // 低温越界 dis_over = 1; } #endif // ⑤ 归零式防抖:连续越界 20 次(20×5ms=100ms)才动作; // 中间只要一次温度回到窗口内,计数就清零重新累计 static u8 dis_cnt = 0; // 连续越界计数(static 跨 5ms 调用累计) if (dis_over) { if (++dis_cnt >= LYF_USER_NTC_DEBOUNCE_CNT) { sys_cb.pwroff.ntc_ind = 1; // ★ 置公版 NTC 关机标志 return 1; // 播提示音+关机流程由公版自动完成,无需再写代码 } } else { dis_cnt = 0; // 温度恢复正常,防抖清零 } #if LYF_USER_NTC_ADC_LOG_EN static u16 dbg_cnt_a = 0; if (++dbg_cnt_a >= 200) { // 200×5ms=1s 打印一次 dbg_cnt_a = 0; printf("[LYF_NTC_CHECK] adc=%d\n", saradc_get_value8(ADCCH_NTC)); } #endif return 0; } #endif #endif

逐步讲解(对照 ①②③④⑤):

1、两道闸门:Downloader 没勾"是否使能NTC"(xcfg_cb.ntc_en=0)直接返回;正在充电直接返回(交给充电线)。所以这个函数只在"开机不充电"时干活;

2、读 ADC:读的是后台扫描缓存(见 2.3 ①),值越小温度越高;

3、越界判断:四路开关用#if包着,关掉的路连判断代码都不编译;

4、归零式防抖:连续 20 次越界(100ms)才置关机标志。中间任何一次温度回窗,计数清零重来——滤掉 ADC 抖动和临界点反复横跳;

5、只置标志:sys_cb.pwroff.ntc_ind = 1之后的事情(提示音、关机)全由公版pwroff_process()完成。

注意事项:

  • 成员名必须写sys_cb.pwroff.ntc_ind。公版回退代码里误写成sys_cb.pwroff_flag.ntc_ind(system.c L211,没有这个成员),照抄会编译报错;
  • 挂载点不用动:公版已经在 5ms 中断里调本函数(system.c L255-257)。

3.4 第 4 步:system.c 充电检测函数(L108-197)

#if USER_NTC AT(.com_text.ntc) void user_ntc_charge_check(void) { // ① 没插充电器就不检测(本函数挂在充电流程里,正常只有充电时才被调用) if (!CHARGE_DC_IN()) { return; } // ② 读 NTC 分压点的 8bit ADC 值(温度越高 → ADC 值越小) u8 adc = saradc_get_value8(ADCCH_NTC); // ③ 越界判断:ADC ≤ 高温阈值 = 温度过高;ADC ≥ 低温阈值 = 温度过低 u8 chg_over = 0; // chg_over = 是否越出允许充电的温度窗口 #if LYF_USER_NTC_CHARGE_HIGH_EN if (adc <= LYF_USER_NTC_CHARGE_HIGH_TEMP_THD) { // 高温越界 chg_over = 1; } #endif #if LYF_USER_NTC_CHARGE_LOW_EN if (adc >= LYF_USER_NTC_CHARGE_LOW_TEMP_THD) { // 低温越界 chg_over = 1; } #endif // ④ 防抖计数与状态标志(static 跨 5ms 调用累计): // over_cnt = 连续越界次数 // back_cnt = 连续满足恢复条件次数 // chg_stopped = 停充原因:0=充电中,1=高温停充,2=低温停充 static u8 over_cnt = 0; static u8 back_cnt = 0; static u8 chg_stopped = 0; if (chg_over) { // ⑤ 温度越界:连续越界 20 次(100ms)→ 停止充电(只停充,绝不关机) back_cnt = 0; // 恢复计数清零:两路计数互不干扰 if (++over_cnt >= LYF_USER_NTC_DEBOUNCE_CNT) { over_cnt = 0; // 记录停充原因(高温 or 低温),复充时按对应恢复阈值判断 #if LYF_USER_NTC_CHARGE_HIGH_EN if (adc <= LYF_USER_NTC_CHARGE_HIGH_TEMP_THD) { chg_stopped = 1; // 高温停充 } #endif #if LYF_USER_NTC_CHARGE_LOW_EN if (adc >= LYF_USER_NTC_CHARGE_LOW_TEMP_THD) { chg_stopped = 2; // 低温停充 } #endif CHARGE_OFF(); // 官方停充宏:RTCCON8 |= BIT(1); RTCCON8 &= ~BIT(6); //charge_led_off(); // 可选:灭充电指示灯(需要时取消注释) } } else { // ⑥ 温度回到窗口内 over_cnt = 0; // 越界计数清零 #if LYF_USER_NTC_CHARGE_RECOVER_EN // 复充模式(滞回):按停充原因用对应恢复阈值判断 + 连续满足 20 次(100ms)消抖 u8 recov_ok = 0; // recov_ok = 是否满足复充条件 if (chg_stopped == 1) { // 高温停充 → 温度降得足够低才复充 if (adc >= LYF_USER_NTC_CHARGE_HIGH_RECOVER_THD) { recov_ok = 1; } } else if (chg_stopped == 2) { // 低温停充 → 温度升得足够高才复充 if (adc <= LYF_USER_NTC_CHARGE_LOW_RECOVER_THD) { recov_ok = 1; } } if (recov_ok) { if (++back_cnt >= LYF_USER_NTC_DEBOUNCE_CNT) { back_cnt = 0; chg_stopped = 0; // 复充完成,清除停充原因 RTCCON8 |= BIT(6); // 打开内部充电使能 RTCCON8 &= ~BIT(1); // 清除停充位 → 恢复充电 //charge_led_on(); // 可选:亮充电指示灯 } } else { back_cnt = 0; // 未满足恢复条件,恢复计数清零 } #else back_cnt = 0; // 不复充模式:保持停充,拔出重插充电器才恢复 #endif } #if LYF_USER_NTC_ADC_LOG_EN static u16 dbg_cnt_b = 0; if (++dbg_cnt_b >= 200) { // 200×5ms=1s 打印一次 dbg_cnt_b = 0; printf("[LYF_NTC_CHARGE_CHECK] adc=%d\n", saradc_get_value8(ADCCH_NTC)); } #endif } #endif

逐步讲解:

1、闸门:没插充电器直接返回。本函数只在充电流程里被调,此判断是双保险;

2、读 ADC + 越界判断:与放电函数完全同构;

3、停充(⑤ 分支):连续越界 100ms → 记下停充原因(高温=1、低温=2)→CHARGE_OFF()停充。从头到尾不碰关机标志,所以停充后温度继续越界也不会关机;

4、复充(⑥ 分支,滞回):不是"回到截止线就复充",而是按停充原因对照对应的恢复阈值判断,满足后连续 100ms 才复充。详细原理见第 4 章;

5、两个计数互斥:越界时清恢复计数,回窗时清越界计数,互不干扰。

3.5 第 5 步:func_charge.c 挂载充电检测(L98-113)

#if LYF_USER_NTC_EN && USER_NTC extern void user_ntc_charge_check(void); // defined in system.c #endif AT(.text.func.charge) u8 sfunc_charge_process(u32 counter) { u8 charge_sta = 0; sys_cb.sys_delay = 0; #if LYF_USER_NTC_EN #if USER_NTC user_ntc_charge_check(); // NTC charge temp protect (power-on charge & power-off charge) #endif #endif if ((counter % 20) == 0) { charge_process(); } ...

为什么挂这里:sfunc_charge_process()是充电流程的心脏,开机充电(func_charge.c L164)和关机充电(system.c L612)两个循环每 5ms 都调它一次,挂一处覆盖全部充电场景,检测节奏正好 5ms。

注意事项:

  • extern声明解决跨文件调用(函数定义在 system.c,不加声明会报implicit declaration编译错误);
  • #if层级与 system.c 定义处一致(LYF_USER_NTC_EN+USER_NTC双层),总开关关闭时不产生未定义调用。

3.6 第 6 步:Downloader 工具配置

用 Downloader 打开earphone.setting,确认三项(对应 xcfg.h L27-29 三个配置):

配置项当前值说明
是否使能 NTC(ntc_en)True必须勾。不勾则 adkey.c L36 不使能 PE7 通道,且放电检测函数在 ① 直接返回
NTC 使用内部 10K 上拉(ntc_user_inner_pu)True勾上后 adkey.c L33 会额外开芯片内部 10K 上拉,与外部上拉并联改变分压体系(见下方注意)
NTC 阈值(ntc_thd_val)100只被公版回退代码使用;本工程走自定义双窗口判断,此值不参与 LYF 逻辑

3.7 第 7 步:阈值换算速查表

查看热敏电阻对应的R-T对照表,去计算阈值(结果四舍五入)

阈值计算公式:
ADC值 = 当前热敏电阻温度阻值 / (当前热敏电阻温度阻值 +(内部/外部)上拉电阻阻值) * ADC采样精度(255)

例如:

计算0度的ADC值 = 28.22 /(28.22 + 10)* 255 = 188.2810047095761 = 188

计算45度的ADC值 = 4.9 / (4.9 + 10)* 255 =83.85906040268456 = 84

4. 复充滞回控制详解(本工程重点功能)

4.1 为什么要滞回

如果没有滞回,"温度回到窗口内就复充":45°C 停充 → 温度降到 44.9°C 复充 → 充电发热又升回 45°C 停充……在临界点附近反复停充/复充,充电 MOS 管疯狂开关,充电速度极慢还有发热风险。

滞回的做法:停充和复充用两条不同的线(对照 config.h):

高温方向:adc ≤ 84(45°C)停充 ──┐ │ 中间这段"缓冲带"既不动作也不改变状态 高温方向:adc ≥ 90(约42°C)复充 ─┘ 低温方向:adc ≥ 187(0°C)停充 ──┐ │ 低温方向:adc ≤ 180(约3°C)复充 ─┘

温度必须穿过整条缓冲带(约 3~5°C)才会切换状态,临界点的小抖动全被缓冲带吸收。

4.2 三态状态机与执行流程

chg_stopped记录停充原因,是整个滞回逻辑的核心:

状态含义复充条件
0充电中不动作
1高温停充adc ≥ 90连续 100ms → 复充
2低温停充adc ≤ 180连续 100ms → 复充

一次完整的高温滞回流程:

① adc 降到 ≤84,连续 100ms ──→ chg_stopped=1,CHARGE_OFF() 停充 ② 温度开始回落,adc 回到 84~90 之间(窗口内但没到恢复线) → recov_ok=0 → back_cnt 清零 → 不复充 ✓(旧版会在这里就复充) ③ adc 升到 ≥90,连续 100ms 不回落 → 复充,chg_stopped 清零回到 0 ④ 复充后温度又升,adc 再次 ≤84,回到 ①

低温方向镜像同理。极端情况(如高温停充后温度一路飙到低温截止线)会自动把chg_stopped改成 2,恢复到低温恢复阈值才复充——状态机自洽,不需要额外代码。

7. 其它情况方案(备选)

检测逻辑(防抖、挂载点、停充/复充、关机链路)与第 2~6 章完全相同,只有「上拉来源」不同。以下三种方案针对"上拉供电怎么来"。

7.1 踩坑讲解:上拉供电不能接 VDDMIC

现象:功能落地后打印 ADC 恒为 0;万用表量外部上拉电阻、NTC 电阻都正常。耳机出现"一开机就关机"——ADC=0 低于高温阈值,防抖 100ms 后误触发关机。通话时 ADC 读数还会漂移,采集不准确。

排查链(本工程实际走过的路):

  1. 打印adc=0→ 排除软件读取问题(通道已使能、打印链路正常);
  2. 万用表量 PE7 引脚对地电压 = 0V → 分压点没有电;
  3. 量上拉电阻供电端(VDDMIC)→ 正常使用时无输出,通话时才输出电压;
  4. 结论:不是 NTC 电路坏了,是供电脚选错了——VDDMIC 只在通话时供电。

根因:VDDMIC 是芯片的MIC 供电 IO,专门给外部麦克风供电,电压档位可配(xcfg.h L131mic_pwr_level:2.5V~2.9V 可选)。它的输出跟随通话链路按需使能——只有通话时(麦克风工作)才输出电压,正常待机/播音乐时不输出。

为什么即使软件设法让它常开也不行:VDDMIC 的输出电压与通话状态强耦合——即使软件配置该脚一直输出,正常使用时和通话时的电压仍有差异(通话时偏高),NTC 分压的基准电压变了,ADC 读数就不准。NTC 检测要 7×24 小时稳定采样,供电电压必须恒定。(VDDDAC 同理:DAC 电源域,播放时才供电。)

电源选择表:

电源性质能否给 NTC 上拉供电
VDDIO(3.3V)IO 电源,常供✅ 推荐(与 ADC 参考电压同源)
普通 GPIO 输出高常供(软件控制)✅ 可用,见 7.2 方案 C(还能分时断电省电)
VBAT/DC5V电池/充电电源⚠️ 电压高于 ADC 参考,低温侧分压会截顶失真
VDDMICMIC 供电 IO,通话才输出❌ 正常使用无电,ADC 恒 0;通话时电压漂移

7.2 方案 B:普通 GPIO 分时供电(保留外部上拉)此方案还没有验证

供电策略一句话:开机期间常开电、关机断电——放电和充电都有电,关机零漏电。

电路:供电脚和采样脚分开:

PE4(GPIO,输出高=开电)── R_up(外部上拉)──┬── PE7(ADC 采样脚) │ R_ntc(NTC) │ GND

① 硬件:上拉电阻供电端飞由芯片的一个空闲 GPIO供电(示例 PE4,先确认原理图上该脚未被占用)。

② config.h 新增两个宏(放 LYF_NTC 宏区):

// NTC 供电 GPIO(PE4):输出高 = 开电,输出低 = 断电(开机期间开电,关机断电) #define LYF_NTC_VCC_EN() {GPIOEFEN &= ~BIT(4); GPIOEDE |= BIT(4); GPIOEDIR &= ~BIT(4); GPIOESET |= BIT(4);} #define LYF_NTC_VCC_DIS() {GPIOEFEN &= ~BIT(4); GPIOEDE |= BIT(4); GPIOEDIR &= ~BIT(4); GPIOECLR |= BIT(4);}

③ 四处挂载点(覆盖:开机、软关机、关机充电、关机充电退出):

路径动作插入位置
开机初始化开电system.csys_init()里sys_io_init()(L672)之后
软关机关电func_lowpwr.cfunc_pwroff()(L16)开头
关机充电进入开电system.cpower_on_check()里sfunc_charge_enter()(L581)之后
关机充电退出关电system.cpower_on_check()里sfunc_charge_exit()(L651)之后

system.c(开机初始化):

// io init sys_io_init(); NTC_VCC_EN(); // 开机初始化:开 NTC 供电(充放一体)

func_lowpwr.c(插入内容纯 ASCII):

void func_pwroff(int pwroff_tone_en) { NTC_VCC_DIS(); // NTC supply off (soft poweroff) ...

system.c(关机充电):

sfunc_charge_enter(chbox_out2pwr_en); NTC_VCC_EN(); // 关机充电:开 NTC 供电
#if CHARGE_EN sfunc_charge_exit(); NTC_VCC_DIS(); // 退出充电循环:关 NTC 供电 #endif

路径覆盖验证:

  • 开机(PWRKEY 长按/出仓唤醒)→sys_init()开电 → 放电检测(5ms 中断)有电;
  • 开机插电充电 → 一直有电,充电检测正常;
  • 软关机 →func_pwroff()关电 → 深睡零漏电;
  • 关机插电 →power_on_check()充电分支开电(此阶段sys_init()还没执行,必须单独开电);
  • 关机充电退出(充满/拔出,含"重新关机"路径)→ 经过 L651 关电 → 零漏电;
  • 复位后到sys_init()之间 GPIO 无电,但这段 5ms 中断未使能、没有检测在跑,无影响。

④ 放电检测直接可用:打开LYF_USER_NTC_DISCHARGE_HIGH_EN/LOW_EN即可,阈值沿用第 3 章实测体系(外部上拉没变)。放电检测挂在 5ms 中断(3.2),开机期间 GPIO 有电,读数正常。

⑤ 时序原理:为什么开机/充电期间常开电,而不是每次检测前开、检测后关

SARADC 缓存值由后台扫描每 5ms 刷新一次(见 2.3 ①),"开电 → 分压稳定 → 下一轮转换完成"需要几 ms。若每次检测前才开电,读到的还是上一轮无电时的旧值(0)。所以开电点都放在检测开始之前,开机/充电期间一直有电,检测只负责读。

阈值与滞回:外部上拉电阻没变,阈值沿用第 3 章实测体系;滞回复充沿用第 4 章(本工程已实装,无需额外工作)。

已知遗留(三方案通用):关机充电循环里 5ms 定时器未使能,SARADC 后台扫描停摆,缓存可能冻结在开电前的旧值。实测关机充电时若打印的 adc 一直不变化,需在关机充电循环里手动驱动bsp_saradc_process()(详见 6.8)。

变体:仅充电版(产品确定不做放电保护时):挂载点换成func_charge_enter()(func_charge.c L188)开电、func_charge_exit()(L211)关电,加上关机充电的两处。开机不充电期间 GPIO 无电(比充放一体版少 33µA),放电两路保持 0。


制作不易!喜欢的小伙伴给个小赞赞!喜欢我的小伙伴点个关注!有不懂的地方和需要的资源随时问我哟!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询