2.46 INA226 电压电流功率检测模块(来自云胡不喜的贡献)
2.46.1 模块来源
采购链接: https://item.taobao.com/item.htm?spm=a230r.1.14.13.2b9a4f227uc568&id=595926354111&ns=1&abbucket=10#detail 资料下载:(基于该模块的资料,百度云链接等) 链接:http://pan.baidu.com/s/1c0DbuXa 密码:3p2j
**实物展示图**2.46.2 规格参数
工作电压:2.7 V -5.5 V工作电流:典型值为 330μA通信方式:I2C (时钟速率 1k-2.94M)引脚数量:10 (还有其他关于该模块的一些重要参数,例如温度传感器需要知道温度的检测范围,屏幕需要知道像素等等。)1.感测的总线电压范围: 0V 至 36V (高侧或低侧感测) 2.高精度: 0.1% 增益误差(最大值) 10μV 偏移(最大值)3.可配置的取平均值选项 4.16 个可编程地址 (放相关的资料文件,例如数据手册、产品说明书、规格书、使用手册等)
2.46.3 模块原理
INA226 是一种高精度、低功耗的电流/电压监测芯片,它采用集成电流传感器和差分放大器电路,用于测量和监控电流和电压。INA226 的工作原理如下:
- 电流测量:INA226 内置了一个电流传感器,该传感器是基于霍尔效应或电阻的。当电流通过芯片的输入引脚时,传感器将产生一个与电流成正比的电压信号。
- 电压测量:INA226 可以通过测量两个端口之间的电压差来实现电压测量。它采用差分放大器电路,将输入端口的电压与内部参考电压进行比较,并产生一个与输入电压差值成正比的电压信号。
- AD 转换:INA226 将电流和电压信号转换为数字信号。它包含一个内置的模数转换器(ADC),用于将模拟信号转换为数字形式。ADC 将连续的模拟信号分割成离散的数字级别,并输出对应的数字值。
- 数据处理:转换后的数字信号被送入 INA226 的数字信号处理部分。在这里,它们经过放大、滤波和校准等处理,以产生准确的电流和电压测量结果。
- 数据输出:INA226 通过接口(I2C)将测量结果输出给主控制器或其他外部设备。主控制器可以读取和解释这些测量结果,从而实现对电流和电压的监控和控制。
总之,INA226 通过集成电流传感器和差分放大器电路,以及内部的模数转换器和数字信号处理部分,实现对电流和电压的高精度测量和监控。
2.46.4 移植工程
讲解移植到立创梁山派的大致步骤,并基于该模块移植的代码实现什么功能。
2.46.4-2 移植步骤
将厂家提供的代码移植到立创·梁山派的步骤,图文并茂。如果没有厂家代码,请将实现功能的代码粘贴至此目录下,并进行关键代码注释。
在本次INA226模块的测试中,使用的是贴片采样电阻R100,阻值为0.1欧姆。根据数据手册中的公式1和公式2进行计算。
首先,需要注意 Shunt Voltage Register 的值最大为 0x7FFF,每个 LSB 对应 2.5 微伏,全量程范围为 81.92 毫伏。
由于分流电阻的阻值为 0.1 欧姆,因此最大电流为 819.2 毫安(注意避免超过此范围,以免导致错误测量结果)。
在假设 Current_LSB 为 0.02 毫安的情况下,满足最大电流不能超过 819.2 毫安的条件。根据公式 1 计算得到,Calibration Register 的值为 0x0A00。
因此,在配置 INA226 时,应将 0x0A00 写入 Calibration Register 中。
请确保在实际应用中选择适合您的应用的电流范围和分辨率,并避免超出设备的量程,以确保测量结果的准确性。
1.使用 GPIO 实现模拟 I2C 时序。
GPIO 实现模拟 I2C 时序是一种在硬件资源有限的情况下的替代方法。虽然它具有灵活性和低硬件要求的优点,但也存在时序精度受限、速度较慢和资源占用较大等缺点。因此,在选择使用 GPIO 进行模拟 I2C 时序之前,需要权衡其优缺点,并根据具体应用的要求做出选择。
本代码封装了 I2C 设备读写数据函数,方便其他 I2C 模块调用。
代码1 GPIO实现模拟I2C时序代码
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: LC
* 修改日期: 2023年06月12日
* 功能介绍:
******************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:https://dri8c0qdfb.feishu.cn/docx/EGRVdxunnohkrNxItYTcrwAnnHe
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*********************************************************************************/
#include <stdio.h>
#include "main.h"
#include "driver_i2c.h"
#include "systick.h"
// I2C引脚定义
#define SCL_PIN GPIO_SCL // SCL引脚
#define SDA_PIN GPIO_SDA // SDA引脚
#define I2C_PORT PORT_SDA
/******************************************************************
* 函 数 名 称:I2C_GPIO_Init
* 函 数 说 明:I2C的引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void i2c_gpio_init(void)
{
/* 使能时钟 */
rcu_periph_clock_enable(RCU_SCL);
rcu_periph_clock_enable(RCU_SDA);
/* 配置SCL为输出模式 */
gpio_mode_set(PORT_SCL, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SCL);
/* 配置为推挽输出 50MHZ */
gpio_output_options_set(PORT_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_SCL);
/* 配置SDA为输出模式 */
gpio_mode_set(PORT_SDA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SDA);
/* 配置为推挽输出 50MHZ */
gpio_output_options_set(PORT_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_SDA);
gpio_bit_set(I2C_PORT, SDA_PIN);
gpio_bit_set(I2C_PORT, SCL_PIN);
}
/*********************************************************
* 函数名称:i2c_delay
* 函 数 说 明:I2C总线延时函数
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
*********************************************************/
void i2c_delay()
{
uint32_t delay = 200;
while (delay--)
{
__NOP();
}
}
/*********************************************************
* 函 数 名 称:i2c_start
* 函 数 说 明:产生I2C起始信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
*********************************************************/
static void i2c_start()
{
gpio_bit_set(I2C_PORT, SDA_PIN); // 确保数据线为高电平
gpio_bit_set(I2C_PORT, SCL_PIN); // 确保时钟线为高电平
i2c_delay();
gpio_bit_reset(I2C_PORT, SDA_PIN); // 拉低数据线,产生起始信号
i2c_delay();
gpio_bit_reset(I2C_PORT, SCL_PIN); // 拉低时钟线,准备发送数据
i2c_delay();
}
/*********************************************************
* 函 数 名 称:i2c_stop
* 函 数 说 明:产生I2C停止信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
*********************************************************/
static void i2c_stop()
{
gpio_bit_reset(I2C_PORT, SDA_PIN); // 确保数据线为低电平
gpio_bit_set(I2C_PORT, SCL_PIN); // 确保时钟线为高电平
i2c_delay();
gpio_bit_set(I2C_PORT, SDA_PIN); // 拉高数据线,产生停止信号
i2c_delay();
}
/*********************************************************
* 函 数 名 称:i2c_write_byte
* 函 数 说 明:向I2C总线写入一个字节,并读取ACK信号
* 函 数 形 参:data - 要写入的数据字节
* 函 数 返 回:uint8_t - ACK信号,0表示收到ACK,1表示收到NACK
* 作 者:LC
* 备 注:无
*********************************************************/
static uint8_t i2c_write_byte(uint8_t data)
{
uint8_t i, ack;
for (i = 0; i < 8; i++)
{
if (data & 0x80) // 检查数据的最高位
{
gpio_bit_set(I2C_PORT, SDA_PIN); // 将数据线拉高,写入1
}
else
{
gpio_bit_reset(I2C_PORT, SDA_PIN); // 将数据线拉低,写入0
}
gpio_bit_set(I2C_PORT, SCL_PIN); // 拉高时钟线,发送数据位
i2c_delay();
gpio_bit_reset(I2C_PORT, SCL_PIN); // 拉低时钟线,准备发送下一位数据
i2c_delay();
data <<= 1; // 左移一位,准备发送下一位数据
}
gpio_bit_set(I2C_PORT, SDA_PIN); // 拉高数据线,准备接收ACK信号
gpio_bit_set(I2C_PORT, SCL_PIN); // 拉高时钟线
i2c_delay();
ack = gpio_input_bit_get(I2C_PORT, SDA_PIN); // 读取ACK信号
gpio_bit_reset(I2C_PORT, SCL_PIN); // 拉低时钟线
i2c_delay();
return ack;
}
/*********************************************************
* 函 数 名 称:i2c_read_byte
* 函 数 说 明:从I2C总线读取一个字节,并发送ACK或NACK信号
* 函 数 形 参:ack - ACK信号,0表示发送ACK,1表示发送NACK
* 函 数 返 回:uint8_t - 读取到的数据字节
* 作 者:LC
* 备 注:无
*********************************************************/
static uint8_t i2c_read_byte(uint8_t ack)
{
uint8_t i, data = 0;
gpio_bit_set(I2C_PORT, SDA_PIN); // 确保数据线为高电平
for (i = 0; i < 8; i++)
{
data <<= 1; // 左移一位,准备接收数据位
gpio_bit_set(I2C_PORT, SCL_PIN); // 拉高时钟线,准备接收数据
i2c_delay();
if (gpio_input_bit_get(I2C_PORT, SDA_PIN)) // 检查数据线的状态
{
data |= 0x01; // 如果数据线为高电平,将最低位设置为1
}
gpio_bit_reset(I2C_PORT, SCL_PIN); // 拉低时钟线,准备接收下一位数据
i2c_delay();
}
if (ack)
{
gpio_bit_reset(I2C_PORT, SDA_PIN); // 拉低数据线,发送NACK信号
}
else
{
gpio_bit_set(I2C_PORT, SDA_PIN); // 拉高数据线,发送ACK信号
}
gpio_bit_set(I2C_PORT, SCL_PIN); // 拉高时钟线,准备发送ACK或NACK信号
i2c_delay();
gpio_bit_reset(I2C_PORT, SCL_PIN); // 拉低时钟线
i2c_delay();
return data; // 返回读取到的数据字节
}
/*********************************************************
* 函 数 名 称:i2c_write_data
* 函 数 说 明:向I2C设备写入数据
* 函 数 形 参:dev_addr - 设备地址
reg_addr - 寄存器地址
data - 要写入的数据数组指针
len - 数据长度
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
*********************************************************/
void i2c_write_data(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
i2c_start();
i2c_write_byte((dev_addr << 1) & 0xFE); // 写入设备地址
i2c_write_byte(reg_addr); // 写入寄存器地址
for (uint8_t i = 0; i < len; i++)
{
i2c_write_byte(data[i]); // 写入数据
}
i2c_stop();
}
/*********************************************************
* 函 数 名 称:i2c_read_data
* 函 数 说 明:从I2C设备读取数据
* 函 数 形 参:dev_addr - 设备地址
reg_addr - 寄存器地址
data - 存储读取数据的数组指针
len - 数据长度
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
*********************************************************/
void i2c_read_data(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
i2c_start();
i2c_write_byte((dev_addr << 1) & 0xFE); // 写入设备地址
i2c_write_byte(reg_addr); // 写入寄存器地址
i2c_start();
i2c_write_byte((dev_addr << 1) | 0x01); // 写入设备地址,读模式
for (uint8_t i = 0; i < len; i++)
{
if (i == len - 1)
{
data[i] = i2c_read_byte(0); // 读取最后一个字节,发送NACK
}
else
{
data[i] = i2c_read_byte(1); // 读取字节,发送ACK
}
}
i2c_stop();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
2.INA226 驱动主要包括以下功能
1.配置 INA226:使用 I2C 接口发送配置命令和参数给 INA226 芯片。这些参数包括采样时间、测量范围等。
2.读取电压电流等数据:使用 I2C 接口从 INA226 芯片读取电流、电压和功率等数据。可以根据需要设置不同的读取频率和精度。
3.处理数据:根据实际的电路和采样电阻,需要选择合适的计算公式对从 INA226 读取的数据进行处理。可以使用公式和系数将原始数据转换为实际物理量。
代码2 INA226初始化、获取电压、电流、功率代码
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: LC
* 修改日期: 2023年06月12日
* 功能介绍:
******************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:https://dri8c0qdfb.feishu.cn/docx/EGRVdxunnohkrNxItYTcrwAnnHe
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*********************************************************************************/
#include "bsp_ina226.h"
#include "driver_i2c.h"
/************************************************
* 函 数 名 称:ina226_init
* 函 数 说 明:INA226初始化配置
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
*************************************************/
void ina226_init()
{
uint8_t config_data[2] = {0x80, 0x00};
i2c_write_data(INA226Addr, 0x00, config_data, 2); //
config_data[0] = 0x45;
config_data[1] = 0x27;
i2c_write_data(INA226Addr, 0x00, config_data, 2); //
config_data[0] = 0x0A;
config_data[1] = 0x00;
i2c_write_data(INA226Addr, 0x05, config_data, 2); //
}
/************************************************
* 函 数 名 称:ina226_get_voltage
* 函 数 说 明:获取电压值
* 函 数 形 参:无
* 函 数 返 回:电压值(浮点数)
* 作 者:LC
* 备 注:无
*************************************************/
float ina226_get_voltage()
{
uint8_t voltage_data[2];
i2c_read_data(INA226Addr, 0x02, voltage_data, 2); //
uint16_t data = (voltage_data[0] << 8) | voltage_data[1];
float voltage = (float)data * 1.25 ;
return voltage;
}
/************************************************
* 函 数 名 称:ina226_get_current
* 函 数 说 明:获取电流值
* 函 数 形 参:无
* 函 数 返 回:电流值(浮点数)
* 作 者:LC
* 备 注:无
*************************************************/
float ina226_get_current()
{
uint8_t current_data[2];
i2c_read_data(INA226Addr, 0x04, current_data, 2); //
int16_t data = (current_data[0] << 8) | current_data[1];
float current = data * 0.02;
return current;
}
/************************************************
* 函 数 名 称:ina226_get_power
* 函 数 说 明:获取功率值
* 函 数 形 参:无
* 函 数 返 回:功率值(浮点数)
* 作 者:LC
* 备 注:无
*************************************************/
float ina226_get_power()
{
uint8_t power_data[2];
i2c_read_data(INA226Addr, 0x03, power_data, 2); //
uint16_t data = (power_data[0] << 8) | power_data[1];
float power = (float)data * 0.02 * 25;
return power;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
2.46.5 移植验证
讲解代码移植成功后的现象,贴上完成该模块相关功能的图片或者视频。将代码上传飞书分享。
示例:
案例现象:
使用了 120 欧姆水泥电阻作为负载,并使用了万用表和 INA226 来分别测量电压数据。在正确连接电路之后,打开串口助手连接到立创·梁山派的串口,获取了电压、电流和功率数据。整个过程的现象如图所示。
正确连接电路后连接成功之后,立创·梁山派的串口向串口助手发送电压电流功率数据,现象如图所示。
** 移植成功示例工程**