> 技术文档 > 【STM32】一文搞懂INA226,实战应用,HAL库

【STM32】一文搞懂INA226,实战应用,HAL库

测试效果如图所示,设置电流阈值1A,紫色的alert灯被点亮

一、工程链接

INA226实战应用,基于STM32单片机HAL库资源-CSDN下载

二、简单介绍

INA226支持高边或者低边测量,内置乘法器,可以直接读取功率值,可编程的校准值和转换次数,平均值

准备好基础的读写寄存器接口后就可以操作INA226的寄存器。在开始之前介绍一下INA226的原理,有助于对这个芯片更好地使用

原理

INA226有两个测量设备,一个测量总线电压,另一个测量shunt电压,后者用来计算总线电流。

在读取总线电压后就立刻读取shunt电压并通过公式计算电流,检测顺序如下,先测量shunt电压得到电流,再读取总线电压,再计算功率

转换完毕后寄存器的值会被更新

电压测量

电压寄存器本身支持最大40.96V

INA226只能测量正电压,一个LSB是1.25mV

calib寄存器

电流的计算公式为

这个分式的的分子有一个系数叫calibrationRegister,是这样得到的

得到的电流值也被用作计算功率,公式为

INA226只是采集IN+和IN-两个引脚的电压值,要获取电流值,需要写入calib寄存器告诉INA226分辨率。芯片内部的功率寄存器默认乘上了25作为增益系数

完成这些动作后,这些值会被存放在累加器里面,直到累加器存满了,就会进行取平均操作,并更新电压电流功率寄存器的值

在笔者的使用场景中,最大期待电流是6A,Current_LSB=6A/32768=183uA,由于INA226最大shunt电压为81.92mV

就选取0.012欧姆的采样电阻,这样0.012*6=0.072V<81.92mV

CAL=0.00512/(0.000183 * 0.012) = 2331.5

选取2332即为0x91C

这样当通过1A电流时,shuntvolt为0.012V,寄存器值为4800

总线电压为5V时,busvolt=4000

current = 4800*2332/2048=5465,注意这里是寄存器的值,前面说过现在一个LSB是183uA,那么电流就是1.000095A

5465*183uA = 1000095uA

功率值使用如下公式

5465*4000/20000=1093

还要乘以25*183uW=5000475uW=5.000475W

使用的时候要铭记自己设定的电流一个LSB代表多少A和功率的一个LSB代表多少W

不然读取到电流和功率寄存器的值也只能干瞪眼

如果校准寄存器没有值的话,电流寄存器的值就一直是0,功率寄存器的值也会是0

警告提示

如果这个引脚不使用,可以悬空

如果寄存器中多个位都是1,那么响应高位的

16位的寄存器里用到了高6位和低5位

单片机检测到alert变化后去读这个寄存器,其中AFF用来分辨是故障还是转换完毕造成的alert变化

SOL

Shunt Voltage Over-Voltage

SUL

Shunt Voltage Under-Voltage

BOL

Bus Voltage Over-Voltage

BUL

Bus Voltage Under-Voltage

POL

Power Over-Limit

表格里的5个故障共用同一个limit寄存器,因此同一时间只能设置一种故障

OVF是1的话表明数据溢出了,此次计算结果无效

APOL表示高电平还是低电平有效,默认低电平

LEN设置是否要latch还是故障消失后自动恢复,默认自动恢复

芯片ID

分为Manufacturer ID和Die ID

两个都是只读的

转换时间

可以灵活配置shunt电压和总线电压的转换时间和平均采样次数。有时候总线电压变化不大,可以适当减少总线电压转换时间

例如,当两个电压的转换时间都是588us时,采样4次需要588*2*4=4704us差不多4.7ms

转换时间的影响

总线地址

可以支持1MHz的I2C

三、模块与连接

此处将A0和A1均短地,查表可知设备地址为0x80,因为后面还有一位表示读取还是写入用的,实际在iic总线上发送的是0x80或者0x81

直接将SCL和SDA与单片机对应的引脚相连即可。

四、cubeMX配置

硬件I2C

开启I2C,笔者这个芯片的I2C时钟可以到1MHz,由于笔者使用ST7735驱动的屏幕作为显示输出,还开启了SPI,与INA226交互的主要就是I2C,大家按自己需求操作即可。

内部时钟

开调试口等不赘述了

五、驱动编写

写寄存器

写word(双字节)时需在地址后加寄存器指针用来定位要写的寄存器的地址,然后跟上要写入的word

static void INA226_WR_Reg(INA226_AddrType addr, uint16_t value){ uint8_t temp[2]; temp[0] = value >> 8; temp[1] = value & 0x0F; HAL_I2C_Mem_Write(&INA226_I2C, INA226_ADDR, addr, 1, temp, 2, 0x100);}

读寄存器

在iic地址后紧随的就是数据了,这里使用I2C_Mem_Read函数

static int16_t INA226_RD_Reg(INA226_AddrType addr){ uint8_t temp[2]; HAL_I2C_Mem_Read(&INA226_I2C, INA226_ADDR, addr, 1, temp, 2, 0xFFFF); return temp[1] + temp[0] * 256;}

初始化函数

uint8_t INA226_Init(){ uint8_t ret = 0; if (INA226_RD_Reg(INA226_ADDR_DIE_ID) != 0x2260) { ret = 1; } else { } uint16_t config = INA226_MODE_SHUNTBUS_CONTINUE | (INA226_SHUNT_CT_2M116 << 3) \\ | (INA226_BUS_CT_204U << 6) | (INA226_AVERAGES_64 << 9); INA226_WR_Reg(INA226_ADDR_CONFIG, config); INA226_WR_Reg(INA226_ADDR_CALIB, CURRENT_CALIB_B_GENERAL);#if INA226_SOL /* 1A OC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x8000); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_OC * R_SHUNT / INA226_VSHUNT_LSB);#elif INA226_SUL /* 1A UC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x4000); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_UC * R_SHUNT / INA226_VSHUNT_LSB);#elif INA226_BOL /* 1A OC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x2000); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_OV / INA226_VBUS_LSB);#elif INA226_BUL /* 1A UC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x1000); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_UV / INA226_VBUS_LSB);#elif INA226_POL /* 1A UC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x0800); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_OP / INA226_POWER_LSB);#endif return ret;}

监测函数

void INA226_ReadInfo(){ INA226_Info.shuntcurrent = (float)(INA226_RD_Reg(INA226_ADDR_SHUNT_VOLT) * INA226_VSHUNT_LSB) / R_SHUNT; INA226_Info.vbus = INA226_RD_Reg(INA226_ADDR_BUS_VOLT) * INA226_VBUS_LSB; INA226_Info.current = INA226_RD_Reg(INA226_ADDR_CURRENT) * INA226_CURRENT_LSB; INA226_Info.power = INA226_RD_Reg(INA226_ADDR_POWER) * INA226_POWER_LSB;}

六、驱动附录

INA226.c

#include \"INA226.h\"INA226_InfoType INA226_Info;static int16_t INA226_RD_Reg(INA226_AddrType addr){ uint8_t temp[2]; HAL_I2C_Mem_Read(&INA226_I2C, INA226_ADDR, addr, 1, temp, 2, 0xFFFF); return temp[1] + temp[0] * 256;}static void INA226_WR_Reg(INA226_AddrType addr, uint16_t value){ uint8_t temp[2]; temp[0] = value >> 8; temp[1] = value & 0xFF; HAL_I2C_Mem_Write(&INA226_I2C, INA226_ADDR, addr, 1, temp, 2, 0x100);}uint8_t INA226_Init(){ uint8_t ret = 0; if (INA226_RD_Reg(INA226_ADDR_DIE_ID) != 0x2260) { ret = 1; } else { } uint16_t config = INA226_MODE_SHUNTBUS_CONTINUE | (INA226_SHUNT_CT_2M116 << 3) \\ | (INA226_BUS_CT_204U << 6) | (INA226_AVERAGES_64 << 9); INA226_WR_Reg(INA226_ADDR_CONFIG, config); INA226_WR_Reg(INA226_ADDR_CALIB, CURRENT_CALIB_B_GENERAL);#if INA226_SOL /* 1A OC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x8000); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_OC * R_SHUNT / INA226_VSHUNT_LSB);#elif INA226_SUL /* 1A UC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x4000); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_UC * R_SHUNT / INA226_VSHUNT_LSB);#elif INA226_BOL /* 1A OC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x2000); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_OV / INA226_VBUS_LSB);#elif INA226_BUL /* 1A UC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x1000); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_UV / INA226_VBUS_LSB);#elif INA226_POL /* 1A UC */ INA226_WR_Reg(INA226_ADDR_MASK, 0x0800); INA226_WR_Reg(INA226_ADDR_ALERT, INA226_OP / INA226_POWER_LSB);#endif return ret;}void INA226_ReadInfo(){ INA226_Info.shuntcurrent = (float)(INA226_RD_Reg(INA226_ADDR_SHUNT_VOLT) * INA226_VSHUNT_LSB) / R_SHUNT; INA226_Info.vbus = INA226_RD_Reg(INA226_ADDR_BUS_VOLT) * INA226_VBUS_LSB; INA226_Info.current = INA226_RD_Reg(INA226_ADDR_CURRENT) * INA226_CURRENT_LSB; INA226_Info.power = INA226_RD_Reg(INA226_ADDR_POWER) * INA226_POWER_LSB;}

INA226.h

#ifndef INA226_H#define INA226_H#include \"main.h\"#include \"i2c.h\"#include \"stdint.h\"#define INA226_I2C hi2c2#define INA226_ADDR 0x80#define MAX_CURRRENT 6.0f /* 6A */#define R_SHUNT 0.012f /* 0.012 ohm */#define CURRENT_CALIB_B_GENERAL (uint16_t)(0.00512f / (MAX_CURRRENT / 32768.0f) / R_SHUNT)#define INA226_VBUS_LSB 0.00125f /* 0.00125V/bit */#define INA226_VSHUNT_LSB 0.0000025f#define INA226_CURRENT_LSB (MAX_CURRRENT / 32768.0f)#define INA226_POWER_LSB (INA226_CURRENT_LSB * 25.0f)#define INA226_SOL 1#if INA226_SOL #define INA226_OC 1.0f /* 5A */#endif#define INA226_SUL 0#if INA226_SUL #define INA226_UC 1.0f /* 1A */#endif#define INA226_BOL 0#if INA226_BOL #define INA226_OV 5.0f /* 5V */#endif#define INA226_BUL 0#if INA226_BUL #define INA226_UV 5.0f /* 5V */#endif#define INA226_POL 0#if INA226_POL #define INA226_OP 1.0f /* 1W */#endiftypedef enum {INA226_ADDR_CONFIG,INA226_ADDR_SHUNT_VOLT,INA226_ADDR_BUS_VOLT,INA226_ADDR_POWER,INA226_ADDR_CURRENT,INA226_ADDR_CALIB,INA226_ADDR_MASK,INA226_ADDR_ALERT,INA226_ADDR_MAN_ID = 0xFE,INA226_ADDR_DIE_ID = 0xFF,}INA226_AddrType;typedef enum {INA226_AVERAGES_1, INA226_AVERAGES_4, INA226_AVERAGES_16, INA226_AVERAGES_64, INA226_AVERAGES_128, INA226_AVERAGES_256, INA226_AVERAGES_512, INA226_AVERAGES_1024,}INA226_AVGType;typedef enum {INA226_BUS_CT_140U,INA226_BUS_CT_204U,INA226_BUS_CT_332U,INA226_BUS_CT_588U,INA226_BUS_CT_1M1,INA226_BUS_CT_2M116,INA226_BUS_CT_4M156,INA226_BUS_CT_8M244,}INA226_VBUSCType;typedef enum { INA226_SHUNT_CT_140U, INA226_SHUNT_CT_204U, INA226_SHUNT_CT_332U, INA226_SHUNT_CT_588U, INA226_SHUNT_CT_1M1, INA226_SHUNT_CT_2M116, INA226_SHUNT_CT_4M156, INA226_SHUNT_CT_8M244,}INA226_VSHCType;typedef enum { INA226_MODE_SHUTDOWN, INA226_MODE_SHUNT_TG, INA226_MODE_VBUS_TG, INA226_MODE_SHUNTBUS_TG, INA226_MODE_SHUTDOWN1, INA226_MODE_SHUNT_CONTINUE, INA226_MODE_VBUS_CONTINUE, INA226_MODE_SHUNTBUS_CONTINUE,}INA226_MODEType;/*Setting this bit high configures the Alert pin to be asserted if the XXXXXX measurement following a conversion exceeds the value programmed in the Alert Limit Register.*/typedef enum { INA226_MASK_SOL, /*Shunt Voltage Over-Voltage*/ INA226_MASK_SUL, /*Shunt Voltage Under-Voltage*/ INA226_MASK_BOL, /*Bus Voltage Over-Voltage*/ INA226_MASK_BUL, /*Bus Voltage Under-Voltage*/ INA226_MASK_POL, /*Power Over-Limit*/ INA226_MASK_CNVR, /*Conversion Ready*/ INA226_MASK_AFF, /*Alert Function Flag*/ INA226_MASK_CVRF, /*Conversion Ready Flag*/ INA226_MASK_OVF, /*Math Overflow Flag*/ INA226_MASK_APOL, /*Alert Polarity bit; sets the Alert pin polarity.1 = Inverted (active-high open collector) 0 = Normal (active-low open collector) (default)*/ INA226_MASK_LEN, /*Alert Latch Enable; configures the latching feature of the Alert pin and Alert Flag bits.*/}INA226_MASKType;typedef struct{ float vbus; float current; float shuntcurrent; float power;}INA226_InfoType;extern INA226_InfoType INA226_Info;uint8_t INA226_Init();void INA226_ReadID();void INA226_ReadInfo();#endif