第二十八节 电池数据采集:电压/电流/温度传感器、ADC采样、数据滤波与校准
各位同学,今天我们来聊聊电池数据采集。这玩意儿,说白了就是手机的“听诊器”。手机电池健康不健康,电量还剩多少,全靠这些数据说话。我当年刚入行时,觉得这步很简单,不就是读个电压嘛。结果被现实狠狠教育了一顿——数据跳得像心电图,根本没法用。
嗯,这节课我们就把它彻底讲透。
一、传感器:电池的“五官”
电池数据采集,首先得有传感器。手机里常见的就三种:
- 电压传感器:测量电池正负极之间的电位差。单位是伏特(V)。
- 电流传感器:测量充放电电流。单位是安培(A)。
- 温度传感器:测量电池表面或内部温度。单位是摄氏度(℃)。
你可能会问:“电压不是直接量吗?为什么还要传感器?”
其实,电池电压是模拟信号,手机处理器只认数字信号。所以中间必须有个“翻译官”——ADC(模数转换器)。
核心要点:传感器负责感知物理量,ADC负责把模拟量变成数字量。两者缺一不可。
我个人习惯,在选型时优先考虑集成度高的方案。比如高通平台的PMIC(电源管理芯片)内部就集成了多路ADC和传感器接口。省事,也省PCB面积。
二、ADC采样:从模拟到数字的“翻译”
ADC采样,就是把连续的电压值,变成离散的数字值。这里面有几个关键参数:
| 参数 | 说明 | 典型值(手机场景) |
|---|---|---|
| 分辨率 | ADC能区分的最小电压变化 | 10位~16位 |
| 采样率 | 每秒采样的次数 | 100Hz~1kHz |
| 参考电压 | ADC的满量程电压 | 1.8V 或 3.3V |
| 输入范围 | 能测量的最大电压 | 0~Vref |
举个例子。一个10位ADC,参考电压3.3V。那么它的分辨率就是 3.3V / 1024 ≈ 3.2mV。也就是说,每变化3.2mV,数字值就跳1。
听起来不错?但实际项目中,我遇到过一个大坑:采样率太高,数据全是噪声。你想想看,电池电压变化其实很慢,你每秒采1000次,采到的全是电源纹波和开关噪声。白白浪费CPU资源。
我的建议:电池电压采样率设在100Hz左右就够了。电流采样可以稍高,200~500Hz。温度嘛,10Hz都嫌多。
三、数据滤波:把“脏数据”洗干净
ADC采回来的原始数据,直接拿去用?别闹。我见过太多新手,拿着跳来跳去的电压值去算电量,结果电量在5%和15%之间反复横跳。用户不骂娘才怪。
滤波,就是把这些毛刺去掉。常用的方法有几种:
1. 简单移动平均
取最近N个采样值的平均值。N越大越平滑,但响应也越慢。
// 移动平均滤波示例
#define FILTER_WINDOW 10
static int buffer[FILTER_WINDOW];
static int index = 0;
static int sum = 0;
int moving_average(int new_sample) {
sum -= buffer[index];
buffer[index] = new_sample;
sum += new_sample;
index = (index + 1) % FILTER_WINDOW;
return sum / FILTER_WINDOW;
}
2. 中值滤波
取一组采样值,排序后取中间那个。对付突发噪声特别有效。比如你手机放口袋里,突然被压了一下,电压瞬间跳变。中值滤波能直接把它扔掉。
3. 一阶低通滤波
也叫“指数加权平均”。新值 = 旧值 × α + 采样值 × (1-α)。α越接近1,滤波越强。
// 一阶低通滤波
#define ALPHA 0.9f
static float filtered_value = 0;
float lowpass_filter(float new_sample) {
filtered_value = ALPHA * filtered_value + (1 - ALPHA) * new_sample;
return filtered_value;
}
注意:滤波不是越强越好。滤波太狠,数据反应迟钝。比如你正在大电流放电,电压本来应该快速下降,结果滤波后的值还停留在高位。这会导致电量计算严重滞后。
我曾经在一个项目里,把滤波窗口设到了50。结果用户插上充电器,电量要等3秒才更新。被产品经理追着骂了三天。后来改成自适应滤波——电流变化大时自动减小滤波强度,平稳时加强滤波。这才搞定。
四、校准:让数据“说真话”
传感器和ADC都有误差。出厂时每个芯片都不一样。所以必须校准。
校准分两步:
- 零点校准:输入为0时,ADC读到的值应该是多少?比如电流为0时,理论上ADC输出应该是0。但实际可能有个小偏移。记下来,后面减掉。
- 满量程校准:输入一个已知的精确电压(比如2.5V),看ADC读出来是多少。算出增益误差,后面乘回来。
公式很简单:
实际值 = (ADC原始值 - 零点偏移) × 增益系数
校准数据一般存在手机的NVRAM或EFUSE里。每次开机读出来用。
重要提醒:温度对传感器和ADC都有影响。温度变了,零点偏移和增益系数也会变。所以高端方案会做“温度补偿校准”——在不同温度下分别校准,存一张校准表。运行时根据当前温度查表插值。
嗯,这块内容比较多。我画了一张图,帮你理清整个数据采集链路:
从这张图你能看到,数据从传感器出来,经过ADC、滤波、校准,最后才能用。每一步都有坑,每一步都马虎不得。
五、实战中的避坑指南
最后,分享几个我踩过的坑:
- ADC参考电压一定要稳。我曾经用LDO给ADC供电,结果LDO本身纹波就大,ADC读数跟着抖。后来换成高PSRR的LDO,问题解决。
- 采样线要短,要屏蔽。电池电压采样线如果走得太长,或者跟大电流线并行走,会耦合进噪声。我见过一个案子,采样线跟充电线走了同一段FPC,结果充电时电压读数直接偏了200mV。
- 校准数据要冗余存储。NVRAM会坏,EFUSE会烧。我习惯存三份,启动时做多数表决。至少保证有一份是对的。
- 别忘了热插拔场景。用户可能正在换电池(虽然现在手机很少可拆卸了)。热插拔瞬间,电压会剧烈变化。滤波算法要能快速响应,不能把真实变化也滤掉了。
一个小技巧:调试阶段,把原始ADC值、滤波后的值、校准后的值,全部通过log打出来。对比着看,很容易发现问题。我每次调试新平台,第一件事就是看这三组数据的波形。
好了,电池数据采集这块,核心就是传感器→ADC→滤波→校准。每一步都不难,但每一步都有细节。你把这些细节都吃透了,电池数据这块基本就稳了。
公众号:蓝海资料掘金营,微信deep3321