INA226简介
INA226是一款数字电流感测放大器,具有I2C™和SMBus兼容接口。它是一款分流/功率监视器,能够监视分流压降和总线电源电压。INA226采用了一个低阻值的电流检测电阻和一个高速差分放大器,基于欧姆定律实时监测电流、电压等信号,并输出数字信号。
INA226具有可编程校准值、转换时间和取平均值功能,与内部乘法器相结合,可以实现电流值(单位为安培)和功率值(单位为瓦)的直接读取。其最高失调电压为10μV,最大增益误差为0.1%。INA226能够在0V至36V的共模总线电压范围内感测电流,与电源电压无关。
此外,INA226由一个2.7V至5.5V的单电源供电,电源电流典型值为330μA。其额定工作温度范围为-40°C至125°C,I2C兼容接口具有多达16个可编程地址。
总的来说,INA226是一款完整的16位单芯片解决方案,能够为数字I2C接口的电流、电压及电源提供全面可编程测量,适用于需要精确控制系统中精确决策的应用场景。
INA226驱动代码
该驱动主要将INA266初始化时需要的参数配置做了简化,对参数做了直观的描述,使用时直接将需要的参数填入而无需查看数据手册。
C文件:
#include "ina226.h"
INA226_DATA ina226_data0,ina226_data1;
void delay_nms(uint16_t ms) //毫秒
{
//根据不同芯片替换
}
void delay_nus(uint16_t us)//微秒
{
//根据不同芯片替换
}
void INA226_GPIO_Init(void){
/*
HS_HAL_GPIO_INIT_PARAM_S initParam;
initParam.pin = PIN_SCL;
initParam.mode = HS_HAL_GPIO_DUALDIRECT;
initParam.intType = HS_HAL_GPIO_INT_NONE;
initParam.pull = HS_HAL_GPIO_NOPULL;
initParam.func = GPIO;
HS_HAL_GPIO_Init(&initParam);
initParam.pin = PIN_SDA;
HS_HAL_GPIO_Init(&initParam);
根据不同芯片替换 */
IIC_SDA_H;
IIC_SCL_H;
delay_nms(5);
}
void INA226_IIC_Start(void){
IIC_SDA_H;
IIC_SCL_H;
delay_nus(2);
IIC_SDA_L;
delay_nus(2);
IIC_SCL_L;
}
void INA226_IIC_Stop(void){
IIC_SCL_L;
IIC_SDA_L;
delay_nus(2);
IIC_SCL_H;
delay_nus(2);
IIC_SDA_H;
}
u8 INA226_Wait_Ack(void){
u8 ucErrTime=0;
IIC_SDA_H;delay_nus(2);
IIC_SCL_H;delay_nus(2);
while(READ_SDA){
ucErrTime++;
if(ucErrTime > 250){
INA226_IIC_Stop();
return 1;
}
}
IIC_SCL_L;
return 0;
}
void INA226_Ack(void){
IIC_SCL_L;
IIC_SDA_L;
delay_nus(2);
IIC_SCL_H;
delay_nus(2);
IIC_SCL_L;
}
void INA226_NAck(void){
IIC_SCL_L;
IIC_SDA_H;
delay_nus(2);
IIC_SCL_H;
delay_nus(2);
IIC_SCL_L;
}
void INA226_Send_Byte(u8 tdata){
u8 t;
IIC_SCL_L;
for(t = 0;t < 8;t++){
if((tdata&0x80)>>7)
IIC_SDA_H;
else
IIC_SDA_L;
tdata <<= 1;
delay_nus(2);
IIC_SCL_H;
delay_nus(2);
IIC_SCL_L;
delay_nus(2);
}
}
u8 INA226_Read_Byte(u8 ack){
u8 i,res = 0;
IIC_SDA_H;
for(i = 0;i < 8;i++){
IIC_SCL_L;
delay_nus(2);
IIC_SCL_H;
res <<= 1;
if(READ_SDA)res++;
delay_nus(2);
}
if(!ack)
INA226_NAck();
else
INA226_Ack();
return res;
}
u16 INA226_ReadData(u8 reg_addr,u8 w_addr,u8 r_addr)
{
u16 reg_data=0;
u16 temp=0;
INA226_IIC_Start();
INA226_Send_Byte(w_addr);
if(INA226_Wait_Ack())return 0;
INA226_Send_Byte(reg_addr);
if(INA226_Wait_Ack())return 0;
INA226_IIC_Start();
INA226_Send_Byte(r_addr);
if(INA226_Wait_Ack())return 0;
reg_data= INA226_Read_Byte(1);
reg_data=(reg_data<<8)&0xFF00;
temp=INA226_Read_Byte(0);
INA226_IIC_Stop();
reg_data|=temp;
return reg_data;
}
u8 INA226_WriteData(u8 reg_addr,u16 reg_data,u8 w_addr)
{
u8 data_high=(u8)((reg_data&0xFF00)>>8);
u8 data_low=(u8)reg_data&0x00FF;
INA226_IIC_Start();
INA226_Send_Byte(w_addr);
if(INA226_Wait_Ack())return 0;
INA226_Send_Byte(reg_addr );
if(INA226_Wait_Ack())return 0;
INA226_Send_Byte(data_high);
if(INA226_Wait_Ack())return 0;
INA226_Send_Byte(data_low);
if(INA226_Wait_Ack())return 0;
INA226_IIC_Stop();
delay_nms(2);
return 1;
}
void INA226_Init(AVG_NUM_E avg_num,VBUS_CHANGE_TIME_E vbus_cnum,VSH_CHANGE_TIME_E vsh_cnum,OPERATION_MODE_E mode,u8 w_addr){
u16 config_reg_data = 0x4000;
config_reg_data |= (avg_num << 9);
config_reg_data |= (vbus_cnum << 6);
config_reg_data |= (vsh_cnum << 3);
config_reg_data |= mode;
printf("config = %x calib = %x\r\n",config_reg_data,CAL);
INA226_WriteData(CONFIG_REG, config_reg_data,w_addr);
INA226_WriteData(CALIB_REG, CAL,w_addr);
}
//mV
void Get_Bus_Vol(void){
ina226_data0.bus_v = (float)INA226_ReadData(BUS_V_REG,CHIP1_WRITE_ADDR,CHIP1_READ_ADDR) * 1.25;
ina226_data1.bus_v = (float)INA226_ReadData(BUS_V_REG,CHIP2_WRITE_ADDR,CHIP2_READ_ADDR) * 1.25;
}
//mV
void Get_Shunt_Vol(void){
ina226_data0.shunt_v = (float)INA226_ReadData(SHUNT_V_REG,CHIP1_WRITE_ADDR,CHIP1_READ_ADDR) * 2.5 * 0.001;
ina226_data1.shunt_v = (float)INA226_ReadData(SHUNT_V_REG,CHIP2_WRITE_ADDR,CHIP2_READ_ADDR) * 2.5 * 0.001 * 0.98;
if(ina226_data0.shunt_v > 81.92) ina226_data0.shunt_v = 0;
if(ina226_data1.shunt_v > 81.92) ina226_data1.shunt_v = 0;
}
//mA
void Get_Current(void){
ina226_data0.cur = (float)INA226_ReadData(CURRENT_REG,CHIP1_WRITE_ADDR,CHIP1_READ_ADDR) * CURRENT_LSB / 1000;
ina226_data1.cur = (float)INA226_ReadData(CURRENT_REG,CHIP2_WRITE_ADDR,CHIP2_READ_ADDR) * CURRENT_LSB / 1000 * 0.98 ; //0.98是校准
if(ina226_data1.cur > 16384) ina226_data1.cur = 0;
if(ina226_data0.cur > 16384) ina226_data0.cur = 0;
}
//mW
void Get_Power(void){
ina226_data0.power = (float)INA226_ReadData(POWER_REG,CHIP1_WRITE_ADDR,CHIP1_READ_ADDR)* CURRENT_LSB / 1000 * 25;
ina226_data1.power = (float)INA226_ReadData(POWER_REG,CHIP2_WRITE_ADDR,CHIP2_READ_ADDR)* CURRENT_LSB / 1000 * 25 * 0.98 ;
}
void testINA226(void){
Get_Bus_Vol();
Get_Shunt_Vol();
Get_Current();
Get_Power();
printf("bus_in_vol = %.3fV bus_out_vol = %.3fV\r\n",ina226_data0.bus_v/1000,ina226_data1.bus_v/1000);
printf("shunt_in_vol = %.2fmV shunt_out_vol = %.2fmV \r\n",ina226_data0.shunt_v,ina226_data1.shunt_v);
printf("cur_in = %.3fA cur_out = %.3fA \r\n",ina226_data0.cur/1000,ina226_data1.cur/1000);
printf("power_in = %.3fW power_out = %.3fW \r\n",ina226_data0.power/1000,ina226_data1.power/1000);
printf("eff = %f\%\r\n",ina226_data1.power/ina226_data0.power);
}
H文件:
#ifndef __INA226_H
#define __INA226_H
#include "main.h"
#define PIN_SCL HS_HAL_PIN_GPIO43
#define PIN_SDA HS_HAL_PIN_GPIO44
#define IIC_SCL_H // HS_HAL_GPIO_WritePin(PIN_SCL,1) 根据不同芯片替换
#define IIC_SCL_L // HS_HAL_GPIO_WritePin(PIN_SCL,0)
#define IIC_SDA_H // HS_HAL_GPIO_WritePin(PIN_SDA ,1)
#define IIC_SDA_L // HS_HAL_GPIO_WritePin(PIN_SDA ,0)
#define READ_SDA // HS_HAL_GPIO_ReadPin(PIN_SDA)
#define CHIP1_WRITE_ADDR 0x80
#define CHIP1_READ_ADDR 0x81
#define CHIP2_WRITE_ADDR 0x82
#define CHIP2_READ_ADDR 0x83
#define CONFIG_REG 0x00 //配置寄存器
#define SHUNT_V_REG 0x01 //分流电压寄存器
#define BUS_V_REG 0x02 //总线电压寄存器
#define POWER_REG 0x03 //功率寄存器
#define CURRENT_REG 0x04 //电流寄存器
#define CALIB_REG 0x05 //较准寄存器
#define MASK_EN_REG 0x06 //屏蔽/使能寄存器
#define ALERT_REG 0x07 //警报限值寄存器
#define MAIN_ID_REG 0xFE //制造商id寄存器
#define CHIP_ID_REG 0xFF //芯片id寄存器
#define CURRENT_LSB 500 //单位uA
#define SHUNT_R 5 //单位mΩ
#define CAL (5120000 / CURRENT_LSB / SHUNT_R) //较准寄存器配置值
/*IN226数据*/
typedef struct{
float bus_v;
float shunt_v;
float cur;
float power;
}INA226_DATA;
/*取平均次数*/
typedef enum{
AVG_NUM_1, //缺省值
AVG_NUM_4,
AVG_NUM_16,
AVG_NUM_128,
AVG_NUM_256,
AVG_NUM_512,
AVG_NUM_1024,
}AVG_NUM_E;
/*总线电压转换时间 us */
typedef enum{
VBUS_CHANGE_TIME_140,
VBUS_CHANGE_TIME_204,
VBUS_CHANGE_TIME_332,
VBUS_CHANGE_TIME_588,
VBUS_CHANGE_TIME_1100, //缺省值
VBUS_CHANGE_TIME_2116,
VBUS_CHANGE_TIME_4156,
VBUS_CHANGE_TIME_8244,
}VBUS_CHANGE_TIME_E;
/*分流电压转换时间 us */
typedef enum{
VSH_CHANGE_TIME_140,
VSH_CHANGE_TIME_204,
VSH_CHANGE_TIME_332,
VSH_CHANGE_TIME_588,
VSH_CHANGE_TIME_1100, //缺省值
VSH_CHANGE_TIME_2116,
VSH_CHANGE_TIME_4156,
VSH_CHANGE_TIME_8244,
}VSH_CHANGE_TIME_E;
/*操作模式*/
typedef enum{
POWER_SAVE_MODE1,
VSH_TRIG_MODE,
VBUS_TRIG_MODE,
VSH_VBUS_TRIG_MODE,
POWER_SAVE_MODE2,
VSH_CONTINUE_MODE,
VBUS_CONTINUE_MODE,
VSH_VBUS_CONTINUE_MODE,//缺省值
}OPERATION_MODE_E;
extern INA226_DATA ina226_data0;
extern INA226_DATA ina226_data1;
void delay_nms(uint16_t ms);
void delay_nus(uint16_t us);
void INA226_GPIO_Init(void);
void INA226_IIC_Start(void);
void INA226_IIC_Stop(void);
u8 INA226_Wait_Ack(void);
void INA226_Ack(void);
void INA226_NAck(void);
void INA226_Send_Byte(u8 tdata);
u8 INA226_Read_Byte(u8 ack);
u16 INA226_Read2Data(u8 reg_addr,u8 w_addr,u8 r_addr);
u8 INA226_WriteData(u8 reg_addr,u16 reg_data,u8 w_addr);
void Get_Bus_Vol(void);
void Get_Shunt_Vol(void);
void Get_Current(void);
void Get_Power(void);
void testINA226(void);
void INA226_Init(AVG_NUM_E avg_num,VBUS_CHANGE_TIME_E vbus_cnum,VSH_CHANGE_TIME_E vsh_cnum,OPERATION_MODE_E mode,u8 w_addr);
#endif
该驱动测试过能够使用,但不同型号的单片机需要自己更改相应的一些函数。