实现STM32读取INA226电流值并通过串口发送给HMI串口屏显示

系统连接与工作原理

整个系统的数据流动如下:

硬件连接

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, &reg, 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, &reg, 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, &reg, 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, &reg, 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

调试与优化建议

  1. I2C通信调试

    • 如果读取不到INA226的数据,先用逻辑分析仪或示波器检查I2C信号。
    • 确认INA226的地址是否正确(A0和A1引脚电平决定地址)。
    • 检查I2C线路上是否有适当的上拉电阻(通常4.7kΩ)。
  2. 电流测量校准

    • INA226的测量精度高度依赖校准寄存器的设置。校准公式为:
      CAL = 0.00512 / (Current_LSB × Rshunt)
      其中Current_LSB = 最大预期电流 / 32768
    • 可以用万用表测量实际电流,与INA226读数对比,微调校准值。
  3. 串口通信调试

    • 确保STM32与HMI屏的波特率、数据位、停止位和校验位设置一致。
    • HMI指令必须以0xFF 0xFF 0xFF结尾。
  4. 抗干扰处理

    • 电流检测路径(特别是分流电阻连接)应尽量短而直接,减少噪声干扰。
    • 在INA226的电源引脚附近添加去耦电容(100nF)。
  5. 功能扩展

    • 可以增加功率计算电能累计功能。
    • 添加阈值报警功能,当电流超过设定值时,在HMI屏上显示警告。
相关推荐
云数据构建师7 小时前
TB67S579FTG(O,EL)这是一款非常经典和流行的 “双极步进电机驱动器IC”,主要用于控制步进电机。
单片机·嵌入式硬件
jumu2027 小时前
模型预测控制(MPC):混动汽车能量管理的革新之道
嵌入式硬件
星期天27 小时前
1.6中断系统原理和硬件连接
stm32·单片机·嵌入式硬件·stm32江科大
兆龙电子单片机设计7 小时前
【STM32项目开源】STM32单片机智能心率手环系统
stm32·单片机·物联网·开源·毕业设计
崇山峻岭之间7 小时前
STM32F030CxT6学习记录
stm32·嵌入式硬件·学习
1+2单片机电子设计8 小时前
STM32F103 实现温湿度数据采集并上传机智云的完整方案
stm32·单片机·嵌入式硬件
码上上岸8 小时前
基于STM32的农业大棚温湿度自动调控系统
stm32·单片机·嵌入式硬件
痴长几岁8 小时前
开发日志:一个属性前缀,为stm32程序节省 500KB Flash 空间
stm32·单片机·嵌入式硬件
是大强8 小时前
jtag和sw的区别
嵌入式硬件