实现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屏上显示警告。
相关推荐
码农小韩1 小时前
基于Linux的C++学习——动态数组容器vector
linux·c语言·开发语言·数据结构·c++·单片机·学习
匠在江湖2 小时前
裸机单片机任务调度器实现:基于规范分层(COM/APP/SRV/DRV)架构,(附 任务调度器 / 微秒延时函数 / 串口重定向 源码)
单片机·嵌入式硬件·架构
点灯小铭2 小时前
基于单片机的智能洗碗机控制系统设计
单片机·嵌入式硬件·毕业设计·课程设计
清风6666664 小时前
基于单片机的电加热炉智能温度与液位PID控制系统设计
单片机·嵌入式硬件·mongodb·毕业设计·课程设计·期末大作业
一路往蓝-Anbo4 小时前
第五篇:硬件接口的生死劫 —— GPIO 唤醒与测量陷阱
c语言·驱动开发·stm32·单片机·嵌入式硬件
逑之5 小时前
C语言笔记16:文件操作
c语言·笔记·单片机
2401_863326115 小时前
基于单片机智能光控路灯设计
单片机·嵌入式硬件
清风6666666 小时前
基于单片机的球类比赛专用计分与暂停管理系统设计
单片机·嵌入式硬件·毕业设计·课程设计
Y1rong6 小时前
STM32之时钟
stm32·单片机·嵌入式硬件
yuanmenghao7 小时前
自动驾驶中间件iceoryx - 同步与通知机制(二)
开发语言·单片机·中间件·自动驾驶·信息与通信