上一篇文章我们讲了如何测试电流,但是INA226有一个非常典型的问题,那就是误差比较大,因为采样电阻非常小,我的开发板用的是100mΩ的采样电阻,在设定中我也用的是这个采样电阻值,但事实上,测试得到的偏差会超过10%,因为采样电阻本身有误差,焊接的工艺,焊锡膏的成分也有带来误差,甚至PCB上的布局和连线也会导致误差!所以,在实际场景中,想要达到比较精确的值,这个采样电阻,绝对不适合采用过小的电阻,比如10mΩ左右的电阻,因为积累误差甚至会超过电阻本身的的值。
对这个问题,我的思考是只能通过某些特定的办法进行补偿,比如通过对采样电阻值的修正,达到更精确的测量目的。修正的原理也很简单,我们已知总线电压(Vbus,INA226测量总线电压非常方便),找一个非常精确的电阻(RL)作为负载,比如1000欧姆。然后设定采样电阻(Rs)的值就等于其标称值,这样我们能得到一个精准的参考电流值;然后我们再通过INA226测量电流值,得到一个测量电流值,这样,我们就可以通过下面的办法来计算实际的采样电阻偏差是多少:
令测量电流是 Is,Vx = Is * ( RL + Rs ),得到一个误差总线电压值;用 Vx - Vbus,得到误差电压ΔV,用ΔV / Vbus,就得到了误差值 r,而采样电阻修正值 Rf = Rs * r,给采样电阻加上这个值之后,重新设定校准寄存器,就可以得到比较精确的电流了。但是这个只是基于对采样电阻值的假设,所以,实际电流和采样电流值之间还是存在一定的误差,只是这个误差比较小而已。
double INA226Compensation(double load_resisitor, double shunt_resistor)
{
uint16_t current = 0, voltage = 0;
i2c_write_blocking(i2c_default, 0x40, & current_register, sizeof(current_register), true );
i2c_read_blocking (i2c_default, 0x40, (uint8_t *) & current, sizeof(current), false );
current = current >> 8 | current << 8;
double i2 = current * current_lsb;
i2c_write_blocking(i2c_default, 0x40, & bus_voltage_register, sizeof(bus_voltage_register), true );
i2c_read_blocking (i2c_default, 0x40, (uint8_t *) & voltage, sizeof(voltage), false );
voltage = voltage >> 8 | voltage << 8;
double bus = voltage * 0.00125;
double i1 = bus / ( load_resisitor + shunt_resistor );
double vx = i2 * ( load_resisitor + shunt_resistor );
double ratio = ( vx - bus ) / bus;
double r = ratio * shunt_resistor;
Serial.printf( "%f, %f, %fV, %f, %f\n", i1, i2, bus, ratio, r );
return r;
}
代码里面有测量电流和总线电压的计算,总线电压非常容易计算,获取到总线电压寄存器的值之后,乘以0.00125就是电压值,这个值非常的精确。
在调用这个函数之前,需要等待约1秒钟,因为第一次设定校准寄存器之后,需要一定的时间,才能得到采样的电流和总线电压值。
double rs = 0.1;
double ie = 0.512;
uint16_t cal = INA226Calibration( rs, ie );
uint8_t data_2[3];
data_2[0] = calibration_register;
data_2[1] = cal >> 8;
data_2[2] = cal & 0x00ff;
i2c_write_blocking(i2c_default, 0x40, data_2, sizeof(data_2), false );
delay( 1000 );
// fix
double rf = INA226Compensation(1011, rs);
cal = INA226Calibration( rs + rf, ie );
data_2[0] = calibration_register;
data_2[1] = cal >> 8;
data_2[2] = cal & 0x00ff;
i2c_write_blocking(i2c_default, 0x40, data_2, sizeof(data_2), false );
这个偏差值可以保存下来,在发布版启动的时候,直接使用。