系统连接与工作原理
整个系统的数据流动如下:

硬件连接
1. INA226 与 STM32 连接 (I2C接口)
| INA226 引脚 | STM32 引脚 | 说明 |
|---|---|---|
| VCC | 3.3V | 电源正极 |
| GND | GND | 电源地 |
| SCL | PB6 (或其它I2C SCL引脚) | I2C时钟线 |
| SDA | PB7 (或其它I2C SDA引脚) | I2C数据线 |
| A0 | GND或VCC | 地址选择引脚0 |
| A1 | GND或VCC | 地址选择引脚1 |
INA226的I2C地址由A0和A1引脚决定:
- 两个都接地(GND):0x40 (7位地址)
- 在代码中,HAL库通常需要将7位地址左移1位(0x40 << 1 = 0x80)
2. HMI串口屏与STM32连接 (UART接口)
| HMI串口屏引脚 | STM32 引脚 | 说明 |
|---|---|---|
| RX | PA2 (USART2_TX) | 串口接收数据 |
| TX | PA3 (USART2_RX) | 串口发送数据(可选) |
| GND | GND | 共同地线 |
| VCC | 5V或3.3V | 电源(根据屏规格) |
3. INA226 与被测电路连接
| INA226 引脚 | 被测电路连接 | 说明 |
|---|---|---|
| V+ | 电源正极 | 测量总线电压 |
| V- | 负载输入正极 | |
| S+ | 电源正极 | 电流检测正 |
| S- | 负载输入正极 | 电流检测负 |
注意 :需要在S+和S-之间连接一个分流电阻(Shunt Resistor),例如0.1Ω/1W的精密电阻。电流通过测量该电阻两端的压降计算得出。
STM32代码实现 (HAL库)
1. INA226驱动代码 (ina226.c / ina226.h)
首先,我们需要编写INA226的驱动程序。
ina226.h
c
#ifndef INA226_H
#define INA226_H
#include "stm32f1xx_hal.h" // 根据你的STM32系列调整
// INA226寄存器地址
#define INA226_CONFIG_REG 0x00
#define INA226_SHUNT_VOLTAGE_REG 0x01
#define INA226_BUS_VOLTAGE_REG 0x02
#define INA226_POWER_REG 0x03
#define INA226_CURRENT_REG 0x04
#define INA226_CALIBRATION_REG 0x05
#define INA226_MASK_ENABLE_REG 0x06
#define INA226_ALERT_LIMIT_REG 0x07
#define INA226_MANUFACTURER_ID_REG 0xFE
#define INA226_DIE_ID_REG 0xFF
// INA226默认I2C地址(A0和A1接地)
#define INA226_ADDRESS 0x80 // (0x40 << 1)
// 配置寄存器设置(根据你的需求调整)
#define INA226_CONFIG_DEFAULT 0x4727 // 0100 0111 0010 0111
// 函数声明
void INA226_Init(I2C_HandleTypeDef *hi2c);
float INA226_ReadBusVoltage(void);
float INA226_ReadShuntVoltage(void);
float INA226_ReadCurrent(void);
float INA226_ReadPower(void);
uint16_t INA226_ReadManufacturerID(void);
uint16_t INA226_ReadDieID(void);
extern I2C_HandleTypeDef hi2c1; // 你的I2C句柄
#endif
ina226.c
c
#include "ina226.h"
#include <math.h>
// I2C句柄
I2C_HandleTypeDef *ina226_i2c;
// 校准值(需要根据你的分流电阻计算)
static uint16_t calibrationValue = 0; // 将在Init中计算
void INA226_Init(I2C_HandleTypeDef *hi2c) {
ina226_i2c = hi2c;
// 验证器件ID
uint16_t manufID = INA226_ReadManufacturerID();
uint16_t dieID = INA226_ReadDieID();
// 预期值:制造商ID应为0x5449,芯片ID应为0x2260
if (manufID != 0x5449 || dieID != 0x2260) {
// 器件识别失败,处理错误
Error_Handler();
}
// 计算校准值(示例:分流电阻0.1Ω,最大预期电流2A)
// 公式:Cal = 0.00512 / (Current_LSB * Rshunt)
// Current_LSB = 最大预期电流 / 2^15
float maxExpectedCurrent = 2.0; // 2A
float rShunt = 0.1; // 0.1Ω
float currentLSB = maxExpectedCurrent / 32768.0;
calibrationValue = (uint16_t)(0.00512 / (currentLSB * rShunt));
// 写入校准寄存器
uint8_t calibData[3] = {INA226_CALIBRATION_REG,
(uint8_t)(calibrationValue >> 8),
(uint8_t)(calibrationValue & 0xFF)};
HAL_I2C_Master_Transmit(ina226_i2c, INA226_ADDRESS, calibData, 3, HAL_MAX_DELAY);
// 写入配置寄存器
uint8_t configData[3] = {INA226_CONFIG_REG,
(uint8_t)(INA226_CONFIG_DEFAULT >> 8),
(uint8_t)(INA226_CONFIG_DEFAULT & 0xFF)};
HAL_I2C_Master_Transmit(ina226_i2c, INA226_ADDRESS, configData, 3, HAL_MAX_DELAY);
}
// 读取总线电压(单位:伏特)
float INA226_ReadBusVoltage() {
uint8_t reg = INA226_BUS_VOLTAGE_REG;
uint8_t data[2];
HAL_I2C_Master_Transmit(ina226_i2c, INA226_ADDRESS, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(ina226_i2c, INA226_ADDRESS, data, 2, HAL_MAX_DELAY);
uint16_t voltageRaw = (data[0] << 8) | data[1];
return voltageRaw * 0.00125; // 1.25mV/LSB
}
// 读取电流值(单位:安培)
float INA226_ReadCurrent() {
uint8_t reg = INA226_CURRENT_REG;
uint8_t data[2];
HAL_I2C_Master_Transmit(ina226_i2c, INA226_ADDRESS, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(ina226_i2c, INA226_ADDRESS, data, 2, HAL_MAX_DELAY);
int16_t currentRaw = (data[0] << 8) | data[1];
// 计算Current_LSB
float maxExpectedCurrent = 2.0; // 与初始化时一致
float currentLSB = maxExpectedCurrent / 32768.0;
return currentRaw * currentLSB;
}
// 读取其他数据的函数类似实现...
uint16_t INA226_ReadManufacturerID() {
uint8_t reg = INA226_MANUFACTURER_ID_REG;
uint8_t data[2];
HAL_I2C_Master_Transmit(ina226_i2c, INA226_ADDRESS, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(ina226_i2c, INA226_ADDRESS, data, 2, HAL_MAX_DELAY);
return (data[0] << 8) | data[1];
}
uint16_t INA226_ReadDieID() {
uint8_t reg = INA226_DIE_ID_REG;
uint8_t data[2];
HAL_I2C_Master_Transmit(ina226_i2c, INA226_ADDRESS, ®, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(ina226_i2c, INA226_ADDRESS, data, 2, HAL_MAX_DELAY);
return (data[0] << 8) | data[1];
}
2. 主程序代码 (main.c)
c
#include "main.h"
#include "stm32f1xx_hal.h"
#include "ina226.h"
#include <stdio.h>
#include <string.h>
// 全局变量
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart2;
// 函数声明
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART2_UART_Init(void);
void SendToHMI(const char *variable, float value);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART2_UART_Init();
// 初始化INA226
INA226_Init(&hi2c1);
// 给INA226和HMI屏一点启动时间
HAL_Delay(100);
char msg[50];
sprintf(msg, "System Started\r\n");
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
while (1) {
// 读取电流值
float current = INA226_ReadCurrent();
// 发送到HMI串口屏
SendToHMI("current", current);
// 可选:读取并发送其他值
float voltage = INA226_ReadBusVoltage();
SendToHMI("voltage", voltage);
// 每秒更新一次(可根据需要调整)
HAL_Delay(1000);
}
}
// 发送数据到HMI串口屏的函数
void SendToHMI(const char *variable, float value) {
char buffer[50];
if (strcmp(variable, "current") == 0) {
// 发送电流值到HMI的n0组件(数值显示)
sprintf(buffer, "n0.val=%d\xFF\xFF\xFF", (int)(value * 1000)); // 转换为毫安
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
// 可选:同时发送到文本组件显示更详细的信息
sprintf(buffer, "t0.txt=\"%.2fA\"\xFF\xFF\xFF", value);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
}
else if (strcmp(variable, "voltage") == 0) {
// 发送电压值到HMI的n1组件
sprintf(buffer, "n1.val=%d\xFF\xFF\xFF", (int)(value * 1000)); // 转换为毫伏
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
sprintf(buffer, "t1.txt=\"%.2fV\"\xFF\xFF\xFF", value);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
}
}
// 系统时钟配置
void SystemClock_Config(void) {
// 根据你的STM32型号配置
}
// I2C初始化
static void MX_I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000; // 400kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c1);
}
// USART2初始化(用于HMI串口屏)
static void MX_USART2_UART_Init(void) {
huart2.Instance = USART2;
huart2.Init.BaudRate = 9600; // 或115200,根据你的HMI屏设置
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart2);
}
// GPIO初始化
static void MX_GPIO_Init(void) {
// GPIO初始化代码
}
HMI串口屏配置
HMI串口屏通常使用USART HMI或类似的软件进行配置。
1. 在HMI屏上创建显示元件
- 添加一个数值显示元件(如n0)用于显示电流值
- 添加一个文本显示元件(如t0)用于显示带单位的电流值
2. HMI屏指令格式
STM32需要按照HMI屏的协议格式发送数据:
指令格式:组件ID.属性=值[0xFF 0xFF 0xFF]
示例:n0.val=1000\xFF\xFF\xFF(设置n0组件的值为1000)
参考代码 STM32读取INA226的电流值 并用串口发送给HMI串口屏显示 www.3dddown.com/csa/56677.html
调试与优化建议
-
I2C通信调试:
- 如果读取不到INA226的数据,先用逻辑分析仪或示波器检查I2C信号。
- 确认INA226的地址是否正确(A0和A1引脚电平决定地址)。
- 检查I2C线路上是否有适当的上拉电阻(通常4.7kΩ)。
-
电流测量校准:
- INA226的测量精度高度依赖校准寄存器的设置。校准公式为:
CAL = 0.00512 / (Current_LSB × Rshunt)
其中Current_LSB = 最大预期电流 / 32768 - 可以用万用表测量实际电流,与INA226读数对比,微调校准值。
- INA226的测量精度高度依赖校准寄存器的设置。校准公式为:
-
串口通信调试:
- 确保STM32与HMI屏的波特率、数据位、停止位和校验位设置一致。
- HMI指令必须以
0xFF 0xFF 0xFF结尾。
-
抗干扰处理:
- 电流检测路径(特别是分流电阻连接)应尽量短而直接,减少噪声干扰。
- 在INA226的电源引脚附近添加去耦电容(100nF)。
-
功能扩展:
- 可以增加功率计算 和电能累计功能。
- 添加阈值报警功能,当电流超过设定值时,在HMI屏上显示警告。