3、电量监测基础:电压法、库仑计数法、阻抗跟踪法

做按摩仪电池管理,最头疼的问题是什么?

我个人觉得,不是充电慢,也不是电池寿命短,而是——你永远不知道设备还能撑多久

用户正按得舒服呢,突然没电了。这体验,你说糟不糟心?

所以,电量监测是电池管理的核心。今天咱们就聊聊三种主流方法:电压法、库仑计数法、阻抗跟踪法。每种方法我都踩过坑,咱们一个一个说。

3.1 电压法:最简单,但坑最多

电压法,说白了就是查表。

你测一下电池两端电压,然后去查一个预设的电压-电量对应表,就能知道大概还剩多少电。

核心原理:锂电池的电压与剩余电量存在一定的对应关系。满电时约4.2V,没电时约3.0V。

听起来很简单对吧?但我告诉你,这方法在按摩仪上基本不靠谱

为什么?因为按摩仪工作时,电机一启动,电流瞬间拉大,电池电压会骤降。你测到的电压根本不是真实电压,而是被负载拉低的“假电压”。

避坑指南:我曾经在一个项目里直接用电压法显示电量,结果用户一开机,电量从80%直接跳到30%。用户投诉说“这破机器电量显示是随机的吧?”——嗯,从那以后我再也不敢在动态负载下用纯电压法了。

电压法适合什么场景?

  • 待机状态:设备不工作,负载很小,电压相对稳定
  • 成本敏感:MCU资源紧张,不想加额外芯片
  • 粗略估算:只需要显示“低、中、高”三档电量

代码实现也很简单,我贴一个我常用的查表函数:

// 电压-电量对应表(单位:mV)
// 温度25°C,空载条件下
const uint16_t voltage_table[] = {
    4200,  // 100%
    4100,  // 90%
    3950,  // 80%
    3850,  // 70%
    3750,  // 60%
    3650,  // 50%
    3550,  // 40%
    3450,  // 30%
    3350,  // 20%
    3200,  // 10%
    3000   // 0%
};

uint8_t get_battery_level(uint16_t voltage_mv) {
    for (int i = 0; i < 11; i++) {
        if (voltage_mv >= voltage_table[i]) {
            return 100 - i * 10;
        }
    }
    return 0;
}

小技巧:实际使用时,建议做滑动平均滤波。连续采样5-10次,去掉最大值最小值,再取平均。这样能滤掉电压抖动。

3.2 库仑计数法:精度高,但会漂

库仑计数法,说白了就是数电子

你想想看,电池放电,流出去的电荷量 = 电流 × 时间。如果能实时监测电流,再对时间积分,就能算出放了多少电。

核心公式:剩余电量 = 初始电量 - ∫(电流 × dt)

这个方法精度高,但有个致命问题——误差会累积

我做过一个项目,用库仑计芯片监测电量。刚开始挺准的,误差在1%以内。但用了两周后,误差慢慢漂到了5%。为什么?因为电流采样有微小偏差,每次积分都带一点误差,日积月累就大了。

避坑指南:我曾经以为库仑计一劳永逸,结果产品出货后,用户反馈“电量显示越来越不准”。后来我加了定期校准机制——每次充满电时,强制把电量重置为100%。这才解决了漂移问题。

库仑计数法的硬件实现有两种:

  • 专用库仑计芯片:如TI的BQ系列,精度高,但贵
  • MCU+ADC采样:成本低,但需要MCU有足够算力

我贴一个MCU实现的简化代码:

// 库仑计数法实现(简化版)
// 每10ms执行一次
static int32_t remaining_capacity_mah = 2000;  // 初始容量2000mAh
static uint32_t last_tick = 0;

void coulomb_counting_update(uint16_t current_ma) {
    uint32_t now = get_system_tick();
    uint32_t delta_ms = now - last_tick;
    last_tick = now;
    
    // 放电时电流为正,充电时为负
    // 积分:容量(mAh) = 电流(mA) × 时间(h)
    // delta_ms转小时:delta_ms / 3600000
    int32_t delta_capacity = (int32_t)current_ma * delta_ms / 3600000;
    
    remaining_capacity_mah -= delta_capacity;
    
    // 防止过冲
    if (remaining_capacity_mah < 0) remaining_capacity_mah = 0;
    if (remaining_capacity_mah > 2000) remaining_capacity_mah = 2000;
}

// 充满电时调用
void coulomb_reset(void) {
    remaining_capacity_mah = 2000;  // 重置为满电
}

小技巧:库仑计法的精度取决于电流采样频率。按摩仪电机启动瞬间电流变化很快,建议采样频率不低于100Hz。另外,低功耗模式下可以降低采样率以省电。

3.3 阻抗跟踪法:最准,但也最复杂

阻抗跟踪法,是TI公司搞出来的技术。说白了,它结合了电压法和库仑计数法的优点,还考虑了电池内阻的变化。

你想想看,电池用久了,内阻会变大。同样放100mA电流,新电池电压降0.1V,旧电池可能降0.3V。如果不考虑内阻变化,电量估算肯定不准。

核心思路:实时监测电池内阻,根据内阻修正电压-电量对应关系,再用库仑计数法做动态积分。

这个方法我是在一个高端按摩仪项目里用的。说实话,效果确实好——电量显示误差能控制在2%以内,而且不会随时间漂移。

但代价是什么?

  • 硬件复杂:需要高精度ADC,同时采集电压和电流
  • 算法复杂:需要建立电池模型,做实时参数辨识
  • 成本高:通常需要专用芯片,如TI的BQ34Z100

我简单说一下阻抗跟踪法的流程:

  1. 开路电压测量:设备待机时,测电池开路电压,查表得到初始电量
  2. 内阻计算:负载变化时,记录电压变化ΔV和电流变化ΔI,内阻R = ΔV / ΔI
  3. 动态修正:根据内阻修正电压-电量曲线,再用库仑计数法跟踪
  4. 定期自学习:每次完整充放电循环后,更新电池模型参数

避坑指南:我曾经以为阻抗跟踪法一劳永逸,结果发现温度影响很大。冬天电池内阻会增大,如果不做温度补偿,电量显示会偏大。后来我加了NTC温度传感器,根据温度查表修正内阻值,这才搞定。

这里贴一个简化的阻抗跟踪法伪代码:

// 阻抗跟踪法(伪代码)
// 每100ms执行一次

void impedance_track_update(uint16_t voltage_mv, uint16_t current_ma, int16_t temperature_c) {
    static uint16_t last_voltage = 0;
    static uint16_t last_current = 0;
    static uint16_t internal_resistance = 100;  // 初始内阻100mΩ
    
    // 1. 检测负载变化
    if (abs(current_ma - last_current) > 50) {
        // 2. 计算内阻
        uint16_t delta_v = abs(voltage_mv - last_voltage);
        uint16_t delta_i = abs(current_ma - last_current);
        if (delta_i > 0) {
            // 内阻 = 电压变化 / 电流变化(单位:mΩ)
            internal_resistance = delta_v * 1000 / delta_i;
        }
    }
    
    // 3. 温度补偿
    // 温度每降低10°C,内阻增加约15%
    int16_t temp_factor = (25 - temperature_c) / 10 * 15;
    uint16_t compensated_resistance = internal_resistance * (100 + temp_factor) / 100;
    
    // 4. 修正电压(补偿IR压降)
    uint16_t corrected_voltage = voltage_mv + (current_ma * compensated_resistance / 1000);
    
    // 5. 用修正后的电压查表得到电量
    uint8_t level = get_battery_level(corrected_voltage);
    
    // 6. 更新历史值
    last_voltage = voltage_mv;
    last_current = current_ma;
}

小技巧:如果你不想用专用芯片,也可以用MCU实现简化版的阻抗跟踪。关键是要做好内阻的平滑滤波,因为单次计算的内阻值噪声很大。我习惯用一阶低通滤波,系数取0.1左右。

3.4 三种方法对比

最后,我做个总结对比,方便你选型:

方法 精度 成本 复杂度 适用场景
电压法 低(±20%) 极低 简单 待机状态、粗略指示
库仑计数法 中(±5%) 中等 动态负载、需要连续监测
阻抗跟踪法 高(±2%) 复杂 高端产品、长寿命要求

我个人建议:

  • 如果做低成本按摩仪,用电压法+待机校准就够了
  • 如果做中端产品,用库仑计数法+定期充满校准
  • 如果做高端旗舰,直接上阻抗跟踪法,用户体验好很多

嗯,电量监测这块就聊到这儿。下一章咱们讲讲充电管理,那又是另一番天地了。