目录
1、使用一阶滞后滤波
2、查表 + 分段判断
3、结构体数组 + 插值法
4、迟滞机制(电量一直在跳是噪声干扰或负载波动导致电压抖动)
5、低功耗采样建议
6、升级
7、电压型迟滞回差(Hysteresis)电量判断(四格电量显示)
核心参数
代码示例
1、使用一阶滞后滤波
#define ALPHA 0.2f static float filtered_voltage = 0.0f; filtered_voltage = ALPHA * raw_voltage + (1.0f - ALPHA) * filtered_voltage;2、查表 + 分段判断
uint8_t Calculate_Battery_Level(float voltage) { if (voltage >= 4.15f) return 100; if (voltage >= 4.00f) return 90; if (voltage >= 3.90f) return 80; if (voltage >= 3.80f) return 70; if (voltage >= 3.70f) return 60; if (voltage >= 3.60f) return 50; if (voltage >= 3.50f) return 40; if (voltage >= 3.45f) return 30; if (voltage >= 3.40f) return 20; if (voltage >= 3.35f) return 10; if (voltage >= 3.30f) return 5; return 0; }3、结构体数组 + 插值法
typedef struct { float voltage; uint8_t level; } soc_point_t; const soc_point_t battery_curve[] = { {4.20f, 100}, {3.90f, 80}, {3.70f, 50}, {3.50f, 20}, {3.30f, 0} }; #define CURVE_SIZE (sizeof(battery_curve)/sizeof(battery_curve[0])) uint8_t interpolate_soc(float voltage) { if (voltage >= battery_curve[0].voltage) return 100; if (voltage <= battery_curve[CURVE_SIZE-1].voltage) return 0; for (int i = 0; i < CURVE_SIZE - 1; i++) { if (voltage > battery_curve[i+1].voltage) { float ratio = (voltage - battery_curve[i+1].voltage) / (battery_curve[i].voltage - battery_curve[i+1].voltage); return battery_curve[i+1].level + (uint8_t)(ratio * (battery_curve[i].level - battery_curve[i+1].level)); } } return 0; }4、迟滞机制(电量一直在跳是噪声干扰或负载波动导致电压抖动)
#define BATT_HYSTERESIS 2 // ±2%以内不更新 if (abs(new_level - displayed_level) >= BATT_HYSTERESIS) { Update_Display(new_level); displayed_level = new_level; }5、低功耗采样建议
- 用定时器触发ADC,避免CPU轮询
- 平时关闭ADC时钟,采样时再开启
- 在Stop Mode下通过RTC唤醒,完成一次采样后继续睡眠、
6、升级
- 加NTC测温,做温度补偿
- 接入充电管理芯片的状态中断
- 实现简易库仑积分(用电流×时间估算耗电)
- 结合蓝牙上报历史电量曲线,做健康度分析
7、电压型迟滞回差(Hysteresis)电量判断(四格电量显示)
简单一句话:升档用高电压门槛,降档用更低的电压门槛,防止电压在临界点小幅抖动时电量格来回闪
核心参数
#define BATT_HYSTERESIS_MV 30U //回差30mV代码示例
/** * @brief 根据毫伏值获取电池格数 (0-4格),增加全域迟滞回差 H=20mV * @param voltage_mv 滤波之后毫伏值 (3000-4200mV) */ uint16_t textVbat = 0; #define BATT_HYSTERESIS_MV 20U //回差 uint8_t Get_Battery_Levels(uint16_t voltage_mv) { // static保存上一次输出电量等级,实现迟滞回差 static uint8_t last_level = 0; const float K = (47.0f + 24.0f) / 24.0f; //电阻分压比 uint16_t real_vbat = (uint16_t)(voltage_mv * K + 0.5f); textVbat = real_vbat; //升格阈值 const uint16_t LVL4_UP = 3950; const uint16_t LVL3_UP = 3700U; const uint16_t LVL2_UP = 3450U; const uint16_t LVL1_UP = 3200U; //降格阈值 = 升格阈值 - 回差 const uint16_t LVL4_DOWN = LVL4_UP - BATT_HYSTERESIS_MV; const uint16_t LVL3_DOWN = LVL3_UP - BATT_HYSTERESIS_MV;//3700U-20=3780U const uint16_t LVL2_DOWN = LVL2_UP - BATT_HYSTERESIS_MV; const uint16_t LVL1_DOWN = LVL1_UP - BATT_HYSTERESIS_MV; //先计算候选档位(原始阈值) uint8_t candidate; if(real_vbat >= LVL4_UP) candidate = 4; else if(real_vbat >= LVL3_UP) candidate = 3; else if(real_vbat >= LVL2_UP) candidate = 2; else if(real_vbat >= LVL1_UP) candidate = 1; else candidate = 0; uint8_t new_level = last_level; //迟滞回差状态机 switch(last_level) { case 4: //4格往下掉,必须小于LVL4_DOWN才允许降级 if(real_vbat < LVL4_DOWN) { new_level = candidate; } break; case 3: //可以升4格;或者电压足够低才降级 if(real_vbat >= LVL4_UP) { new_level = 4; } else if(real_vbat < LVL3_DOWN) { new_level = candidate; } break; case 2: if(real_vbat >= LVL3_UP) { new_level = 3; } else if(real_vbat < LVL2_DOWN) { new_level = candidate; } break; case 1: if(real_vbat >= LVL2_UP) { new_level = 2; } else if(real_vbat < LVL1_DOWN) { new_level = candidate; } break; case 0: if(real_vbat >= LVL1_UP) { new_level = 1; } break; default: new_level = candidate; break; } last_level = new_level; return last_level; }