4、电流采样与霍尔传感器调试
电流采样,是BMS系统里最核心的环节之一。说白了,电池的SOC估算准不准,很大程度上就取决于电流测得好不好。我见过不少项目,电压采样做得漂漂亮亮,结果电流一塌糊涂,最后SOC飘得没法看。今天咱们就把这块掰开揉碎了讲清楚。
4.1 霍尔传感器选型与供电
霍尔传感器选型,我个人的习惯是先看量程。你想想看,如果电池包最大持续电流200A,你选个300A的传感器,那在小电流区域分辨率就太差了。反过来,选小了又容易饱和。
选型时重点关注这几个参数:
- 量程:建议取最大工作电流的1.2~1.5倍
- 带宽:至少1kHz以上,不然动态响应跟不上
- 线性度:0.5%以内,否则校准起来很麻烦
- 温度漂移:这个容易被忽略,我踩过坑
供电方面,霍尔传感器通常需要隔离电源。我建议用DC-DC隔离模块,输出纹波控制在50mV以内。供电电压不稳,直接反映在输出上,这个坑别踩。
4.2 电流采样电路调试
电流采样电路,常见的有两种:差分运放和隔离运放。我分别说说。
4.2.1 差分运放方案
差分运放电路,说白了就是把霍尔传感器输出的差分信号转成单端信号,同时做一级放大。电路结构不复杂,但调试时要注意共模电压。
// 典型差分放大电路参数
R1 = R3 = 10kΩ
R2 = R4 = 100kΩ
增益 = R2/R1 = 10倍
共模抑制比(CMRR) ≥ 80dB
调试步骤我一般这样走:
- 先不给电流,测量运放输出,应该接近0V
- 给一个已知小电流,比如10A,看输出是否对应
- 逐步加大电流,检查线性度
- 重点测一下正负半周是否对称
4.2.2 隔离运放方案
隔离运放,适合高压系统。比如800V平台,你总不能让采样电路和高压共地吧?隔离运放内部有磁隔离或容隔离,把高低压侧隔开。
调试隔离运放时,有个容易忽略的点:隔离侧的地和信号侧的地,不能直接连。我刚开始做的时候犯过这个错,一上电就把隔离芯片烧了。
4.3 电流零点漂移校准
零点漂移,是霍尔传感器的通病。为什么会这样?因为霍尔元件本身有残余电压,加上温度变化,零点就跑了。
校准方法,我推荐两步走:
- 硬件校准:在电路板上加一个调零电位器,或者用DAC输出一个反向偏置电压
- 软件校准:系统上电后,先判断电流为零(比如继电器断开时),采样此时的ADC值作为零点偏移
// 软件零点校准示例
#define ZERO_SAMPLE_COUNT 100
uint16_t zero_offset = 0;
void calibrate_zero_offset(void) {
uint32_t sum = 0;
for(int i = 0; i < ZERO_SAMPLE_COUNT; i++) {
sum += read_adc();
delay_ms(1);
}
zero_offset = sum / ZERO_SAMPLE_COUNT;
// 保存到EEPROM
save_to_eeprom(zero_offset);
}
int16_t get_corrected_current(void) {
int16_t raw = read_adc();
return raw - (int16_t)zero_offset;
}
4.4 充放电电流方向判断
电流方向判断,直接决定了你是充电还是放电。霍尔传感器输出有正负之分,但不同厂家的定义可能不一样。
我一般这样处理:
- 先确认传感器输出极性:正电流对应充电还是放电?
- 在代码里定义一个方向标志位
- 根据ADC值正负,设置充放电状态
typedef enum {
CURRENT_IDLE = 0,
CURRENT_CHARGE,
CURRENT_DISCHARGE
} current_dir_t;
current_dir_t get_current_direction(int16_t current) {
if(abs(current) < DEAD_ZONE) {
return CURRENT_IDLE; // 死区处理,防止抖动
}
return (current > 0) ? CURRENT_CHARGE : CURRENT_DISCHARGE;
}
这里有个细节:死区设置。如果电流很小,比如0.5A以内,你硬要判断方向,那就会频繁切换。我一般设个死区,小于这个值就当零电流处理。
4.5 电流积分与库仑计初始值设置
库仑计,说白了就是对电流做时间积分,算出充进去了多少电,放出来了多少电。公式很简单:
ΔSOC = (∫I dt) / 电池总容量
但实际做起来,坑不少。
4.5.1 积分算法实现
我推荐用梯形积分法,比矩形积分更准一些:
// 梯形积分法
float coulomb_count = 0.0f;
float previous_current = 0.0f;
uint32_t previous_time = 0;
void update_coulomb_count(float current, uint32_t timestamp_ms) {
float dt = (timestamp_ms - previous_time) / 1000.0f; // 转成秒
float avg_current = (current + previous_current) / 2.0f;
coulomb_count += avg_current * dt / 3600.0f; // 转成Ah
previous_current = current;
previous_time = timestamp_ms;
}
4.5.2 初始值设置
库仑计的初始值,不能随便设。我见过有人直接设成0,结果SOC从一开始就是错的。
正确的做法:
- 系统首次上电时,根据开路电压查表得到初始SOC
- 把这个SOC换算成对应的库仑计初始值
- 每次系统休眠前,保存当前库仑计值到EEPROM
- 下次唤醒时,从EEPROM恢复
知识体系总览
下面这张图,把电流采样与霍尔传感器调试的核心逻辑串起来了。你可以对照着看,心里有个全局概念。
好了,电流采样这块的内容就这些。记住一个原则:电流测不准,后面所有算法都是空中楼阁。所以调试时多花点时间,值得。