[外设驱动]INA226驱动(电流功率监测器)

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

该驱动测试过能够使用,但不同型号的单片机需要自己更改相应的一些函数。

  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值