I2C原理+INA226功率监测模块原理+STM32CubeMx驱动INA226

在这里插入图片描述

大家好我是 杰哥编程

最近在做项目时需要stm32f103监测系统用电功率电压电流,硬件使用到INA226模块,软件采用HAL库+CubeMX方式配置32的I2C通信,特来分享一下。其中参考了2篇别的博客 根据手上资料进行汇总整理。

欢迎关注我的Gitee仓库:https://gitee.com/wrj12138/embedSummary

I2C原理+INA226功率监测模块原理+STM32CubeMx驱动INA226

本次项目使用1个stm32f103c8t6单片机、一个5VDC-DC升压稳压电源模块板、一个18650锂电池、一个INA226(IIC接口)电压模块

在这里插入图片描述

IIC通信协议

I2C通讯协议(Inter-Integrated Circuit)

i2c物理层概念的一些概念

  • I2C最少只需要两根线,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

  • I2C的数据传输速率位于串口和SPI之间,大部分I2C设备支持100KHz和400KHz模式。实际具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模下可达3.4Mbit/s,但目前大多I2C设备尚不支持高速模式。

  • 使用I2C传输数据会有一些额外消耗:每发送8bits数据,就需要额外1bit的元数据(ACK或NACK)。

  • I2C支持双向数据交换,由于仅有一根数据线,故通信是半双工的。硬件复杂度也位于串口和SPI之间,而软件实现可以相当简单。

  • 和异步串口类似,但可以支持多个slave设备。一个I2C理论上最多可挂载127个设备,但除去保留地址,最多可挂载112个设备。同时支持多个通讯主机及多个通讯从机。允许有多个master并且每个master都可以与所有的slaves通信(master之间不可通过I2C通信,并且每个master只能轮流使用I2C总线)。

  • 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

  • 电气特性:总线通过上拉电阻接到电源。当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。

在这里插入图片描述

i2c协议层的一些概念

  • 空闲状态?

SDA没事的时候是高电平 SCL是时钟上下上下的跳

  • 什么时候开始启动和停止?

起始信号:在SCL为高电平的时候,SDA由高电平向低电平跳变。
结束信号:SCL为高电平的时候,SDA由低电平向高电平跳变。
在这里插入图片描述

  • 应答信号?

    I2C的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。

作为数据接收端时,当设备(无论主从机)接收到I2C传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号,发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号,发送方接收到该信号后会产生一个停止信号,结束信号传输。

在这里插入图片描述

  • 数据发送有效?

    在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。

进行数据传送时,在SCL呈现高电平期间,SDA上的电平必须保持稳定,低电平为数据0,高电平为数据1。只有在SCL为低电平期间,才允许SDA上的电平改变状态。逻辑0的电平为低电压,而逻辑1则为高电平。

没找到图 自己画 哭!!!!55555

红线为c时钟线高电平时能实际有效采集到数据位 d数据线为高则采集数据位为1反之为0,
粉框为c时钟线低电平时,d数据线允许切换高低电平(也可以不切换),以供下一次时钟高电平时采集数据位

在这里插入图片描述

有了上面的空闲 起始 数据位 应答 结束等信号 设备就可以通过i2c传输协议就可以做一些数据交互了!!!

简单来说我要开始水了!!!
就将通俗易懂的 能快速理解的讲完 进入下一篇章
(以下只讲基础的简单的细致的后面会复制粘贴出来 愿意深入了解的可以逐字观看)
1 i2c传输帧首字节有个control byte 用来寻址决定数据传输方向 不管
2既然是多从机的传输协议就要有指定传输目标的功能 也就是地址 地址一般为7位 然后再加一位读写位 有10位的地址 也不难 分成两帧
3指定从机通信后 要实际数据交互 分为两种写时序和读时序
4写时序 写到哪 写到某个8bit的储存单元地址 写什么 某些个8位数据 能连续写的叫页写
在这里插入图片描述

5读时序 读哪 读某8bit的单元地址 主机发个control byte虚晃一下 为啥?我也不知道 就这么规定 你就照办 从机应答后发主机想读的数据 想连续读 你主机得给人家从机一个ack亲亲 不然以为你高冷 不需要连续读呢
在这里插入图片描述

i2c一些详细的概念 都是copy过来的

想细致了解的看看 或者跳过看后面的stm32控制INA226篇章

  • 帧地址:I2C总线上的每个设备都有自己的独立地址,主机发起通讯时,通过SDA信号线发送设备地址(SLAVE_ADDRESS)来查找从机。I2C协议规定设备地址可以是7位或10位,实际中7位的地址应用比较广泛。
  • 应答信号:I2C总线上的所有数据都是以8位字节传送的,发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功,对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
  • 写时序:开始信号:主机+从设备地址+写命令,从机应答,应答成功,表示有这个设备,然后主机+设备内部寄存器地址,此时不用再加写命令控制字,从机应答,应答成功,表示设备内有这个地址,主机写入数据,从机应答,是否继续发送,不发送的话,发送停止信号P。
  • 读时序:要想读设备,首先要知道将要所读取设备的地址告诉从设备,从设备才能将数据放到(发送)SDA上使主设备读取,从设备将数据放入SDA上的过程,由硬件主动完成,不用人为的写入。所以首先先写入从机地址,然后+写控制命令,从机应答,应答成功,表示有这个设备,然后写入内部寄存器地址,此时不用再加写命令控制字,从机应答,应答成功,表示设备内有这个地址。然后主机继续发出:写入从机地址,然后+读命令,从机应答,应答成功,此时便可以读取数据了,从设备已经将数据放入到SDA上了。地址跟设备已经验证了,不用再进行验证。
  • 启动信号:在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号,它标志着一次数据传输的开始。启动信号是一种电平跳变时序信号,而不是一个电平信号。启动信号是由主控器主动建立的,在建立该信号之前I2C总线必须处于空闲状态。
  • 重启动信号:在主控器控制总线期间完成了一次数据通信(发送或接收)之后,如果想继续占用总线再进行一次数据通信(发送或接收),而又不释放总线,就需要利用重启动Sr信号时序。重启动信号Sr既作为前一次数据传输的结束,又作为后一次数据传输的开始。利用重启动信号的优点是,在前后两次通信之间主控器不需要释放总线,这样就不会丢失总线的控制权,即不让其他主器件节点抢占总线。
    停止信号:在时钟线SCL保持高电平期间,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号,它标志着一次数据传输的终止。停止信号也是一种电平跳变时序信号,而不是一个电平信号,停止信号也是由主控器主动建立的,建立该信号之后,I2C总线将返回空闲状态。不是在数据有效性中规定在SDA只能在SCL的低电平的时候变化,为何STAR,STOP不一样?首先STAR和STOP不是数据,所以可以不遵守数据有效性中的规定,其它数据都遵守,而STAR和STOP“不遵守”导致STAR和STOP更容易被识别。这样不是不遵守而是更有优势。起始和停止条件一般由主机产生,总线在起始条件后被认为处于忙的状态,在停止条件的某段时间后总线被认为再次处于空闲状态。如果产生重复起始(Sr) 条件而不产生停止条件,总线会一直处于忙的状态。此时的起始条件(S)和重复起始(Sr) 条件在功能上是一样的。如果连接到总线的器件合并了必要的接口硬件,那么用它们检测起始和停止条件十分简便。但是没有这种接口的微控制器在每个时钟周期至少要采样SDA 线两次来判别有没有发生电平切换。
  • 数据位传送:在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。进行数据传送时,在SCL呈现高电平期间,SDA上的电平必须保持稳定,低电平为数据0,高电平为数据1。只有在SCL为低电平期间,才允许SDA上的电平改变状态。逻辑0的电平为低电压,而逻辑1的电平取决于器件本身的正电源电压VDD(当使用独立电源时)。数据位的传输是边沿触发。
  • 应答信号:I2C总线上的所有数据都是以8位字节传送的,发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
  • 插入等待时间:如果被控器需要延迟下一个数据字节开始传送的时间,则可以通过把时钟线SCL电平拉低并且保持,使主控器进入等待状态。一旦被控器释放时钟线,数据传输就得以继续下去,这样就使得被控器得到足够时间转移已经收到的数据字节,或者准备好即将发送的数据字节。带有CPU的被控器在对收到的地址字节做出应答之后,需要一定的时间去执行中断服务子程序,来分析或比较地址码,其间就把SCL线钳位在低电平上,直到处理妥当后才释放SCL线,进而使主控器继续后续数据字节的发送
  • 总线封锁状态:在特殊情况下,如果需要禁止所有发生在I2C总线上的通信活动,封锁或关闭总线是一种可行途径,只要挂接于该总线上的任意一个器件将时钟线SCL锁定在低电平上即可。

INA226功率监测模块原理

在这里插入图片描述

介绍

INA226是具有I2C™或SMBUS兼容接口的电流分流器和功率监控器。该设备同时监视并联电压降和总线电源电压。可编程的校准值,转换时间和平均值与内部乘法器结合使用,可以直接读取以安培为单位的电流和以瓦特为单位的功率。
INA226感应共模总线电压上的电流,该电压可在0 V至36 V之间变化,与电源电压无关。该器件采用2.7V至5.5V单电源供电,典型功耗为330 µA。该器件的额定工作温度范围为–40°C至125 \ xC2°C,并且在I 2 C兼容接口上具有多达16个可编程地址。
接线方式为:INPUT接电源正极,GND接电源负极,OUTPUT接用电器件(我没接)的电源正极输入口

相关寄存器和设备地址

首先,为了使用I2C读取模块数据,需要先通过传感器数据手册来确定从机地址和所需寄存器地址。

  1. INA226模块一共有10个寄存器(0x0~0x7 还有两个设备ID不管)

在这里插入图片描述

  1. 根据原理图可知从机地址A1 A0 = 00,再参考官方技术文档可知模块设备地址为:0x40

在这里插入图片描述

tnnd 以前没深入了解过i2c 所以这边踩坑了   
这是个7位的地址 stm32用i2c的时候地址填写的是1个byte,  
然后我们了解到i2c指定从机通信的时候7位地址后面还有1个读写位  
所以0x40左移一位等于0x80   (0x40<<1 == 0x80)  
所以stm32用i2c通信的时候,从机地址要写0x80  

#define INA226_ADDRESS 0x80 /*INA226的地址*/

  1. 重点关注的寄存器0x0 0x2 0x3 0x4 0x5

0x0

用于配置芯片的采样速度,采样模式,采样滤波周期等,默认值是0x4127
0x5
校准寄存器 看手册↓ 直接搜索找到计算方式 在这里插入图片描述
理解不了的可以看看下面示例代码中arduino是如何控制INA226模块的↓↓↓↓↓↓

// Calibrate INA226. Rshunt = 0.01 ohm, Max excepted current = 4A
//我买的ina226模块采样电阻型号r010是0.01欧姆 假如我们的电路预期最大电流是4安培
//计算公式:
//Current_LSB = 预期最大电流4A / 2^15 = 0.0001220703125
//CAL = 0.00512/(Current_LSBR)=0.00512/0.0001220703125=42=0x2A 
//当然如果你想让单片机自己算直接移植下面的函数到你的工程里就行
bool INA226::calibrate(float rShuntValue, float iMaxExpected)
{
    uint16_t calibrationValue;
    rShunt = rShuntValue;

    float iMaxPossible, minimumLSB;

    iMaxPossible = vShuntMax / rShunt;

    minimumLSB = iMaxExpected / 32767;

    currentLSB = (uint16_t)(minimumLSB * 100000000);
    currentLSB /= 100000000;
    currentLSB /= 0.0001;
    currentLSB = ceil(currentLSB);
    currentLSB *= 0.0001;

    powerLSB = currentLSB * 25;

    calibrationValue = (uint16_t)((0.00512) / (currentLSB * rShunt));

    writeRegister16(INA226_REG_CALIBRATION, calibrationValue);

    return true;
}
arduino简直是神器 集成了大量的模块的驱动逻辑编写 遇到常见or相似模块 直接去arduino拿来用

0x2 0x3 0x4

测电压 功率 电流
这个直接i2c读取寄存器就可以了

32CubeMx驱动INA226程序设计编写

1 用CubeMX建立工程

这里采用的是常用的STM32F103C8T6芯片,选择外部高频时钟,SWD调试.
在这里插入图片描述
在这里插入图片描述

设置主时钟为72MHz
在这里插入图片描述

配置i2c接口
在这里插入图片描述

2 生成代码 这个不用我教了吧

在这里插入图片描述
在这里插入图片描述

生成代码GENERATE CODE

4 业务逻辑代码编写原理

arduino用cpp语法实现了完整的逻辑
arduino的INA226链接:https://www.jarzebski.pl/arduino/czujniki-i-sensory/cyfrowy-czujnik-pradu-mocy-ina226.html

可以参考arduino也可以看我的
h头文件

#ifndef INC_IIC_INA226_H_
#define INC_IIC_INA226_H_

void INA226_init(void);
//仅使用了获取电压电流功率3个功能
float INA226_GetBusV(void);
float INA226_GetCurrent(void);
float INA226_GetPower(void);

#endif /* INC_IIC_INA226_H_ */

c驱动源文件

#include "i2c.h"

uint8_t INA226_SetConfig(uint16_t ConfigWord);
uint8_t INA226_SetCalibrationReg(uint16_t ConfigWord);

uint16_t INA226_GetBusVReg(void);
uint16_t INA226_GetPowerReg(void);
uint16_t INA226_GetCurrentReg(void);

#define INA226_COM_PORT	hi2c1		/*通讯使用的IIC接口*/

#define INA226_ADDRESS 		0x80	/*INA226的地址*/
#define INA226_I2C_TIMEOUT 	10		/*IIC通讯超时*/

#define INA226_CALIB_VAL 1024
#define INA226_CURRENTLSB 0.5F // mA/bit
#define INA226_CURRENTLSB_INV 1/INA226_CURRENTLSB // bit/mA
#define INA226_POWERLSB_INV 1/(INA226_CURRENTLSB*25) // bit/mW

#define INA226_CONFIG 	0x00 // Configuration Register (R/W)初始值4127
#define INA226_SHUNTV 	0x01 // Shunt Voltage (R)初始值0,分流电压测量值
#define INA226_BUSV 	0x02 // Bus Voltage (R)初始值0,总线电压测量值
#define INA226_POWER 	0x03 // Power (R)初始值0,输出功率测量值
#define INA226_CURRENT 	0x04 // Current (R)初始值0,分流电阻电流计算值
#define INA226_CALIB 	0x05 // Calibration (R/W),设置全量程和电流LSB
#define INA226_MASK 	0x06 // Mask/Enable (R/W),报警设置和转换准备标志
#define INA226_ALERTL 	0x07 // Alert Limit (R/W),报警阈值
#define INA226_MANUF_ID 0xFE // Manufacturer ID (R),0x5449
#define INA226_DIE_ID 	0xFF // Die ID (R),0x2260

#define INA226_MODE_POWER_DOWN 			(0<<0) // Power-Down
#define INA226_MODE_TRIG_SHUNT_VOLTAGE 	(1<<0) // Shunt Voltage, Triggered
#define INA226_MODE_TRIG_BUS_VOLTAGE 	(2<<0) // Bus Voltage, Triggered
#define INA226_MODE_TRIG_SHUNT_AND_BUS 	(3<<0) // Shunt and Bus, Triggered
#define INA226_MODE_POWER_DOWN2 		(4<<0) // Power-Down
#define INA226_MODE_CONT_SHUNT_VOLTAGE 	(5<<0) // Shunt Voltage, Continuous
#define INA226_MODE_CONT_BUS_VOLTAGE 	(6<<0) // Bus Voltage, Continuous
#define INA226_MODE_CONT_SHUNT_AND_BUS 	(7<<0) // Shunt and Bus, Continuous

// Shunt Voltage Conversion Time
#define INA226_VSH_140uS 	(0<<3)
#define INA226_VSH_204uS 	(1<<3)
#define INA226_VSH_332uS 	(2<<3)
#define INA226_VSH_588uS 	(3<<3)
#define INA226_VSH_1100uS 	(4<<3)
#define INA226_VSH_2116uS 	(5<<3)
#define INA226_VSH_4156uS 	(6<<3)
#define INA226_VSH_8244uS 	(7<<3)

// Bus Voltage Conversion Time (VBUS CT Bit Settings[6-8])
#define INA226_VBUS_140uS 	(0<<6)
#define INA226_VBUS_204uS 	(1<<6)
#define INA226_VBUS_332uS 	(2<<6)
#define INA226_VBUS_588uS 	(3<<6)
#define INA226_VBUS_1100uS 	(4<<6)
#define INA226_VBUS_2116uS 	(5<<6)
#define INA226_VBUS_4156uS 	(6<<6)
#define INA226_VBUS_8244uS 	(7<<6)

// Averaging Mode (AVG Bit Settings[9-11])
#define INA226_AVG_1 	(0<<9)
#define INA226_AVG_4 	(1<<9)
#define INA226_AVG_16 	(2<<9)
#define INA226_AVG_64 	(3<<9)
#define INA226_AVG_128 	(4<<9)
#define INA226_AVG_256 	(5<<9)
#define INA226_AVG_512 	(6<<9)
#define INA226_AVG_1024 (7<<9)

// Reset Bit (RST bit [15])
#define INA226_RESET_ACTIVE 	(1<<15)
#define INA226_RESET_INACTIVE 	(0<<15)

// Mask/Enable Register
#define INA226_MER_SOL 	(1<<15) // Shunt Voltage Over-Voltage
#define INA226_MER_SUL 	(1<<14) // Shunt Voltage Under-Voltage
#define INA226_MER_BOL 	(1<<13) // Bus Voltagee Over-Voltage
#define INA226_MER_BUL 	(1<<12) // Bus Voltage Under-Voltage
#define INA226_MER_POL 	(1<<11) // Power Over-Limit
#define INA226_MER_CNVR (1<<10) // Conversion Ready
#define INA226_MER_AFF 	(1<<4) // Alert Function Flag
#define INA226_MER_CVRF (1<<3) // Conversion Ready Flag
#define INA226_MER_OVF 	(1<<2) // Math Overflow Flag
#define INA226_MER_APOL (1<<1) // Alert Polarity Bit
#define INA226_MER_LEN 	(1<<0) // Alert Latch Enable

#define INA226_MANUF_ID_DEFAULT 	0x5449
#define INA226_DIE_ID_DEFAULT 		0x2260


void INA226_init(void)
{
	/*
	* 设置转换时间8.244ms,求平均值次数16,设置模式为分流和总线连续模式
	* 总数据转换时间 = 8.244*16 = 131.9ms
	*/
    INA226_SetConfig(0x45FF);

	/*
	* 分流电阻最大电压 = 32768 * 0.0000025V = 0.08192V
	* 设置分流电压转电流转换参数:电阻0.01R,分辨率0.2mA
	* 公式1
	* Current_LSB = 预期最大电流 / 2^15
	* Current_LSB = 5 / 32768 = 0.000152A ,选0.2ma
	* 公式2
	* CAL = 0.00512/(Current_LSB*R)
	* CAL = 0.00512/(0.0002*0.01)=2560 = 0x0a00
	*/
    INA226_SetCalibrationReg(0x0a00);

}
/*
**************************************************
* 说明:读取BUS电压,并转换为浮点数据
**************************************************
*/
float INA226_GetBusV(void)
{
	uint16_t regData;
	float fVoltage;
    regData = INA226_GetBusVReg();
	fVoltage = regData * 0.00125f;/*电压的LSB = 1.25mV*/
	return fVoltage;
}
/*
**************************************************
* 说明:读取电流,并转换为浮点数据
**************************************************
*/
float INA226_GetCurrent()
{
	uint16_t regData;
	float fCurrent;
	regData = INA226_GetCurrentReg();
	if(regData >= 0x8000)	regData = 0;
	fCurrent = regData * 0.0002f;/*电流的LSB = 0.2mA,由用户配置*/
	return fCurrent;
}
/*
**************************************************
* 说明:读取功率,并转换为浮点数据
**************************************************
*/
float INA226_GetPower()
{
	uint16_t regData;
	float fPower;
	regData = INA226_GetPowerReg();
	fPower = regData * 0.005f;/*功率的LSB = 电流的LSB*25*/
	return fPower;
}

uint8_t INA226_SetConfig(uint16_t ConfigWord)
{
    uint8_t SentTable[3];
    SentTable[0] = INA226_CONFIG;
    SentTable[1] = (ConfigWord & 0xFF00) >> 8;
    SentTable[2] = (ConfigWord & 0x00FF);
    return HAL_I2C_Master_Transmit(&INA226_COM_PORT, INA226_ADDRESS, SentTable, 3, INA226_I2C_TIMEOUT);
}

// uint16_t INA226_GetConfig()
// {
//     uint8_t SentTable[1] = {INA226_CONFIG};
//     uint8_t ReceivedTable[2];
//     HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
//     if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
//     else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
// }

// uint16_t INA226_GetShuntV()
// {
//     uint8_t SentTable[1] = {INA226_SHUNTV};
//     uint8_t ReceivedTable[2];
//     HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
//     if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
//     else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
// }

uint16_t INA226_GetBusVReg()
{
    uint8_t SentTable[1] = {INA226_BUSV};
    uint8_t ReceivedTable[2];
    HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
    if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
    else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
}

uint8_t INA226_SetCalibrationReg(uint16_t ConfigWord)
{
    uint8_t SentTable[3];
    SentTable[0] = INA226_CALIB;
    SentTable[1] = (ConfigWord & 0xFF00) >> 8;
    SentTable[2] = (ConfigWord & 0x00FF);
    return HAL_I2C_Master_Transmit(&INA226_COM_PORT, INA226_ADDRESS, SentTable, 3, INA226_I2C_TIMEOUT);
}

// uint16_t INA226_GetCalibrationReg()
// {
//     uint8_t SentTable[1] = {INA226_CALIB};
//     uint8_t ReceivedTable[2];
//     HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
//     if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
//     else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
// }

uint16_t INA226_GetPowerReg()
{
    uint8_t SentTable[1] = {INA226_POWER};
    uint8_t ReceivedTable[2];
    HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
    if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
    else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
}

uint16_t INA226_GetCurrentReg()
{
    uint8_t SentTable[1] = {INA226_CURRENT};
    uint8_t ReceivedTable[2];
    HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
    if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
    else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
}

// uint16_t INA226_GetManufID()
// {
//     uint8_t SentTable[1] = {INA226_MANUF_ID};
//     uint8_t ReceivedTable[2];

//     HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
//     if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
//     else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
// }

// uint16_t INA226_GetDieID()
// {
//     uint8_t SentTable[1] = {INA226_DIE_ID};
//     uint8_t ReceivedTable[2];
//     HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
//     if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
//     else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
// }

// uint8_t INA226_SetMaskEnable(uint16_t ConfigWord)
// {
//     uint8_t SentTable[3];
//     SentTable[0] = INA226_MASK;
//     SentTable[1] = (ConfigWord & 0xFF00) >> 8;
//     SentTable[2] = (ConfigWord & 0x00FF);
//     return HAL_I2C_Master_Transmit(&INA226_COM_PORT, INA226_ADDRESS, SentTable, 3, INA226_I2C_TIMEOUT);
// }

// uint16_t INA226_GetMaskEnable()
// {
//     uint8_t SentTable[1] = {INA226_MASK};
//     uint8_t ReceivedTable[2];
//     HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
//     if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
//     else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
// }

// uint8_t INA226_SetAlertLimit(uint16_t ConfigWord)
// {
//     uint8_t SentTable[3];
//     SentTable[0] = INA226_ALERTL;
//     SentTable[1] = (ConfigWord & 0xFF00) >> 8;
//     SentTable[2] = (ConfigWord & 0x00FF);
//     return HAL_I2C_Master_Transmit(&INA226_COM_PORT, INA226_ADDRESS, SentTable, 3, INA226_I2C_TIMEOUT);
// }

// uint16_t INA226_GetAlertLimit()
// {
//     uint8_t SentTable[1] = {INA226_ALERTL};
//     uint8_t ReceivedTable[2];
//     HAL_I2C_Master_Transmit(&INA226_COM_PORT,INA226_ADDRESS, SentTable, 1, INA226_I2C_TIMEOUT);
//     if (HAL_I2C_Master_Receive(&INA226_COM_PORT,INA226_ADDRESS, ReceivedTable, 2, INA226_I2C_TIMEOUT) != HAL_OK) return 0xFF;
//     else return ((uint16_t)ReceivedTable[0]<<8 | ReceivedTable[1]);
// }

5 上主函数伪代码

main.c伪代码

int main(void)
{
  while (1)
  {
    batteryVolt  = INA226_GetBusV();//锂电池电压
    //单节18650电池
		if(batteryVolt>4.15)	//电压值对比
		{BatCap = 0.99;}//容量
		else if(batteryVolt<3.4)
		{BatCap =0;}
		else
		{BatCap = (batteryVolt-3.4)/(4.15-3.4);}//正常情况下计算比例 

		if(BatCap<0.45)
    {}//没电啦
		printf("B:%3.1fv Q:%02d%% ",batteryVolt,(int)(BatCap*100));		//打印
  }
}

本次分享到此为止,如有问题欢迎各位指出!!!

产品实物图

stm32追光储能系统实物图
在这里插入图片描述
在这里插入图片描述

  • 19
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
你可以使用STM32CubeMXINA226来实现电流和电压监测功能。STM32CubeMX是一款用于配置STM32微控制器的图形化工具,而INA226是一款集成了电流和电压监测功能的高精度电流/功率监测芯片。下面是一些具体的步骤和建议: 1. 打开STM32CubeMX并创建一个新的工程。 2. 选择你使用的STM32微控制器型号,并配置所需的时钟、引脚和其他外设。 3. 在"Peripherals"选项卡中找到I2C外设,并启用它。 4. 在"Pinout & Configuration"选项卡中,为I2C外设选择适当的引脚。 5. 在"Configuration"选项卡中,配置I2C外设的参数,如时钟频率和地址。 6. 在"Middleware"选项卡中,找到并启用I2C库。 7. 保存并生成代码,将生成的代码导入到你的工程中。 接下来,你需要配置INA226芯片。以下是一些基本步骤: 1. 连接INA226芯片到STM32微控制器的I2C总线上。 2. 使用I2C库函数在代码中初始化I2C总线,并设置适当的时钟频率和地址。 3. 使用I2C库函数与INA226进行通信,配置所需的寄存器和参数。这包括设置电流和电压的量程、采样时间和校准系数等。 4. 使用I2C库函数读取INA226芯片的寄存器,获取电流和电压数据。 5. 根据需要进行数据处理和显示。 以上只是一个简单的示例,具体的实现方式和代码会根据你的具体需求和硬件配置而有所不同。你可以参考STM32CubeMXINA226的官方文档和示例代码来获得更详细的信息和指导。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值