INA226是一路电压电流功率检测器,可以检测线电压,分流电阻的电压和分流电阻电流。
具体实现要看INA226数据手册。
INA226.c:
#include "INA226.h" INA226 INA226_data; static void delay_nns(uint16_t D) //30纳秒ns 根据手册要用到IIC的HS高速模式 { while(--D); } void delay_nms(uint16_t ms) //毫秒 { uint16_t i; uint32_t M = 0;//720W for(i = 0;i < ms; i++) for(M=12000;M > 0;M--); } void delay_nus(uint16_t us)//微秒 { uint16_t i; uint16_t M = 0;//720W for(i = 0;i < us; i++) for(M=72;M > 0;M--); } /****************IIC***************************/ void INA226_IIC_Init(void) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟 //PC11,12初始化设置 GPIO_Initure.Pin=GPIO_PIN_10|GPIO_PIN_11;//PB10SCL PB11SDA GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //高速 HAL_GPIO_Init(GPIOB,&GPIO_Initure); IIC_SDA_H; IIC_SCL_H; delay_nms(5); } void INA226_IIC_Start(void) { IIC_SDA_H; IIC_SCL_H; delay_nns(5); IIC_SDA_L;//START:when CLK is high,DATA change form high to low delay_nns(5); IIC_SCL_L;//钳住I2C总线,准备发送或接收数据 delay_nns(5); } void INA226_IIC_Stop(void) { IIC_SDA_L;//STOP:when CLK is high DATA change form low to high delay_nns(5); IIC_SCL_H; delay_nns(5); IIC_SDA_H;//发送I2C总线结束信号 delay_nns(5); } void INA226_IIC_Ack(void) { IIC_SDA_L; delay_nns(5); IIC_SCL_H; delay_nns(5); IIC_SCL_L; delay_nns(5); IIC_SDA_H; } void INA226_IIC_NAck(void) { IIC_SDA_H; delay_nns(5); IIC_SCL_H; delay_nns(5); IIC_SCL_L; delay_nns(5); IIC_SDA_L; } uint8_t INA226_IIC_Wait_Ack(void) { uint8_t ucErrTime=0; //SDA_IN(); //SDA设置为输入 IIC_SDA_H; delay_nns(5); IIC_SCL_H; delay_nns(5); while(READ_SDA) { ucErrTime++; if(ucErrTime>250) { INA226_IIC_Stop(); return 1; } } IIC_SCL_L;//时钟输出0 return 0; } void INA226_IIC_Send_Byte(uint8_t txd) { IIC_SCL_L;//拉低时钟开始数据传输 for(uint8_t i = 0;i < 8;i++) { if(txd&0x80) IIC_SDA_H; else IIC_SDA_L; txd<<=1; IIC_SCL_H; delay_nns(5); IIC_SCL_L; delay_nns(5); } // IIC_SDA_H; // IIC_SCL_H; //当去掉wait_ack时的时候添加 // delay_nns(5); //IIC_SCL_L; } uint8_t INA226_IIC_Read_Byte(unsigned char ack) { uint8_t TData=0,i; for(i=0;i<8;i++) { IIC_SCL_H; delay_nns(5); TData=TData<<1; //if(GPIOB->IDR& GPIO_IDR_IDR7) //判断SDA是否为高 if(SDA_READ) { TData|=0x01; } IIC_SCL_L; delay_nns(5); } if(!ack) INA226_IIC_NAck(); else INA226_IIC_Ack(); // IIC_SCL_L; // delay_nns(5); // IIC_SDA_L; // delay_nns(5); //ACK // IIC_SCL_H; // delay_nns(5); // IIC_SCL_L; // delay_nns(5); // IIC_SDA_H; return TData; } /**********************IIC_END*************************/ void INA226_Init(void) { INA226_IIC_Init(); HAL_Delay(10); // INA226_SendData(INA226_ADDR1,CFG_REG,0xC000); // HAL_Delay(10); //uint16_t cfg_reg_value = 0x4000|(3<<9)|(4<<6)|(4<<3)|7; // INA226_SendData(INA226_ADDR1,CFG_REG,0x484f); // INA226_SendData(INA226_ADDR1,CAL_REG,0x0012); INA226_SendData(INA226_ADDR1,0x00,0x4727); INA226_SendData(INA226_ADDR1,0x05,0x800);//A00 } void INA226_SendData(uint8_t addr,uint8_t reg,uint16_t data) { uint8_t temp = 0; INA226_IIC_Start(); INA226_IIC_Send_Byte(addr); INA226_IIC_Wait_Ack(); INA226_IIC_Send_Byte(reg); INA226_IIC_Wait_Ack(); temp = (uint8_t)(data>>8); INA226_IIC_Send_Byte(temp); INA226_IIC_Wait_Ack(); temp = (uint8_t)(data&0x00FF); INA226_IIC_Send_Byte(temp); INA226_IIC_Wait_Ack(); INA226_IIC_Stop(); } void INA226_SetRegPointer(uint8_t addr,uint8_t reg) { INA226_IIC_Start(); INA226_IIC_Send_Byte(addr); INA226_IIC_Wait_Ack(); INA226_IIC_Send_Byte(reg); INA226_IIC_Wait_Ack(); INA226_IIC_Stop(); } uint16_t INA226_ReadData(uint8_t addr) { uint16_t temp=0; INA226_IIC_Start(); INA226_IIC_Send_Byte(addr+1); INA226_IIC_Wait_Ack(); temp = INA226_IIC_Read_Byte(1); temp<<=8; temp |= INA226_IIC_Read_Byte(0); INA226_IIC_Stop(); return temp; } long INA226_GetShunt_Current(uint8_t addr) { long temp=0; INA226_SetRegPointer(addr,CUR_REG); temp = INA226_ReadData(addr); if(temp&0x8000) { temp = ~(temp - 1); temp = (uint16_t)temp - 2 * (uint16_t)temp; } return temp; } //获取 id uint16_t INA226_Get_ID(uint8_t addr) { uint32_t temp=0; INA226_SetRegPointer(addr,INA226_GET_ADDR); temp = INA226_ReadData(addr); return (uint16_t)temp; } //获取校准值 uint16_t INA226_GET_CAL_REG(uint8_t addr) { uint32_t temp=0; INA226_SetRegPointer(addr,CAL_REG); temp = INA226_ReadData(addr); return (uint16_t)temp; } //1.25mV/bit uint32_t INA226_GetVoltage(uint8_t addr) { uint32_t temp=0; INA226_SetRegPointer(addr,BV_REG); temp = INA226_ReadData(addr); return (uint32_t)temp; } //2.5uV/bit,感觉这个值是测不准的,所以下面改成2.2了 uint32_t INA226_GetShuntVoltage(uint8_t addr) { uint32_t temp=0; INA226_SetRegPointer(addr,SV_REG); temp = INA226_ReadData(addr); if(temp&0x8000) temp = ~(temp - 1); return (uint32_t)temp; } uint16_t INA226_Get_Power(uint8_t addr) { int16_t temp=0; INA226_SetRegPointer(addr,PWR_REG); temp = INA226_ReadData(addr); return (uint16_t)temp; } void GetVoltage(float *Voltage)//mV { Voltage[0] = INA226_GetVoltage(INA226_ADDR1)*1.25f; printf("ina226 v = %.2f\r\n", Voltage[0]); } void Get_Shunt_voltage(float *Voltage)//uV { Voltage[0] = (INA226_GetShuntVoltage(INA226_ADDR1)*2.2);//这里原来乘的系数是2.5 } void Get_Shunt_Current(float *Current)//mA { Current[0] = (INA226_GetShunt_Current(INA226_ADDR1)* 2.5f); } void GetPower()//W { GetVoltage(&INA226_data.voltageVal); //mV Get_Shunt_voltage(&INA226_data.Shunt_voltage); //uV Get_Shunt_Current(&INA226_data.Shunt_Current); //mA INA226_data.powerVal=INA226_data.voltageVal*0.001f * INA226_data.Shunt_Current*0.001f; } uint16_t read_dat; float read_vol; float GetV(void) { //电压采样 INA226_IIC_Start(); INA226_IIC_Send_Byte(0x80); INA226_IIC_Wait_Ack(); INA226_IIC_Send_Byte(0x00); INA226_IIC_Wait_Ack(); INA226_IIC_Send_Byte(0x47); INA226_IIC_Wait_Ack(); INA226_IIC_Send_Byte(0x27); INA226_IIC_Wait_Ack(); INA226_IIC_Stop(); HAL_Delay(1); INA226_IIC_Start(); INA226_IIC_Send_Byte(0x81); INA226_IIC_Wait_Ack(); read_dat = INA226_IIC_Read_Byte(1)<<8; //IIC_Wait_Ack(); read_dat = read_dat + INA226_IIC_Read_Byte(0); read_vol = 0.00125*read_dat; INA226_IIC_Stop(); return read_vol; }
INA226.h:
#ifndef _INA226_H #define _INA226_H #include "main.h" #define CFG_REG 0x00 // #define SV_REG 0x01 //分流电压, 此处分流电阻为 0.1欧 #define BV_REG 0x02 //总线电压 #define PWR_REG 0x03 //电源功率 #define CUR_REG 0x04 //电流 #define CAL_REG 0x05 //校准,设定满量程范围以及电流和功率测数的 //#define ONFF_REG 0x06 //屏蔽 使能 警报配置和转换准备就绪 //#define AL_REG 0x07 //包含与所选警报功能相比较的限定值 #define INA226_GET_ADDR 0XFF //包含唯一的芯片标识号 #define INA226_ADDR1 0x80 //IO操作 #define IIC_SCL_H HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET) //SCL H #define IIC_SCL_L HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET) //SCL H #define IIC_SDA_H HAL_GPIO_WritePin(GPIOB,GPIO_PIN_11,GPIO_PIN_SET) //SDA_H #define IIC_SDA_L HAL_GPIO_WritePin(GPIOB,GPIO_PIN_11,GPIO_PIN_RESET) //SDA_L #define READ_SDA HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11) //输入SDA #define SDA_READ GPIOB->IDR& GPIO_IDR_IDR11 typedef struct { float voltageVal; //mV float Shunt_voltage; //uV float Shunt_Current; //mA float powerVal; }INA226; static void delay_nns(uint16_t D); void delay_nms(uint16_t ms); void delay_nus(uint16_t us); void INA226_IIC_Init(void); void INA226_IIC_Start(void); void INA226_IIC_Stop(void); void INA226_IIC_Ack(void); void INA226_IIC_NAck(void); uint8_t INA226_IIC_Wait_Ack(void); void INA226_IIC_Send_Byte(uint8_t txd); uint8_t INA226_IIC_Read_Byte(unsigned char ack); void INA226_Init(void); void INA226_SendData(uint8_t addr,uint8_t reg,uint16_t data); void INA226_SetRegPointer(uint8_t addr,uint8_t reg); uint16_t INA226_ReadData(uint8_t addr); long INA226_GetShunt_Current(uint8_t addr); uint16_t INA226_Get_ID(uint8_t addr); uint16_t INA226_GET_CAL_REG(uint8_t addr); uint32_t INA226_GetVoltage(uint8_t addr); uint32_t INA226_GetShuntVoltage(uint8_t addr); uint16_t INA226_Get_Power(uint8_t addr); void GetVoltage(float *Voltage); void Get_Shunt_voltage(float *Voltage); void Get_Shunt_Current(float *Current); void GetPower(); extern INA226 INA226_data; float GetV(void); #endif
IIC协议参考之前那份。
由于这个电路参考电压是负值,所以在计算电压时需要减去这个负值,所以以后用的时候最好是接地。
参考电路接法: