基于 INA226 的电流检测与功率检测发送程序

基于 INA226 的电流检测与功率检测发送程序

一、系统设计概述

┌─────────────────────────────────────────────────────────────┐
│                    INA226 功率检测发送系统                  │
├─────────────────────────────────────────────────────────────┤
│  INA226 传感器  │  微控制器     │  通信接口     │  上位机    │
│                │               │              │           │
│  • 电流检测    │  • I2C 读取   │  • UART/USB  │  • 数据显示 │
│  • 电压检测    │  • 功率计算   │  • CAN总线   │  • 数据记录 │
│  • 功率检测    │  • 数据处理   │  • RS485     │  • 报警监控 │
│  • 温度检测    │  • 发送控制   │  • LoRa/WiFi │  • 远程控制 │
└─────────────────────────────────────────────────────────────┘

二、硬件连接设计

2.1 INA226 硬件连接

INA226 引脚连接 (STM32F103):
┌─────────────┐    ┌─────────────┐
│   INA226    │    │  STM32F103  │
├─────────────┤    ├─────────────┤
│ VBUS (1)    │←──│ 负载电压输入 │  (检测电压)
│ IN+  (2)    │←──│ 分流电阻高端 │
│ IN-  (3)    │←──│ 分流电阻低端 │
│ GND  (4)    │──→│ GND         │
│ SDA  (5)    │──→│ PB7 (I2C1)  │
│ SCL  (6)    │──→│ PB6 (I2C1)  │
│ ADDR (7)    │──→│ GND (地址0x80)│
│ ALERT(8)    │──→│ PA0 (中断)  │
└─────────────┘    └─────────────┘

分流电阻:0.01Ω (10mΩ), 精度1%
最大电流:±15A (根据需求调整)

2.2 通信接口选择

接口类型 波特率/速率 适用场景
UART 115200 bps 调试、简单应用
RS485 9600-115200 bps 工业现场、长距离
CAN 500 kbps 汽车电子、工业控制
LoRa 自适应 无线远程监控

三、完整程序实现

3.1 INA226 驱动头文件 (ina226.h)

#ifndef __INA226_H
#define __INA226_H

#include "stm32f10x.h"
#include <stdint.h>
#include <math.h>

// INA226 I2C 地址 (ADDR接地)
#define INA226_ADDR         0x80    // 7位地址
#define INA226_ADDR_READ    0x81    // 读地址
#define INA226_ADDR_WRITE   0x80    // 写地址

// INA226 寄存器地址
#define INA226_REG_CONFIG   0x00    // 配置寄存器
#define INA226_REG_SHUNT    0x01    // 分流电压寄存器
#define INA226_REG_BUS      0x02    // 总线电压寄存器
#define INA226_REG_POWER    0x03    // 功率寄存器
#define INA226_REG_CURRENT  0x04    // 电流寄存器
#define INA226_REG_CALIB    0x05    // 校准寄存器
#define INA226_REG_MASK     0x06    // 屏蔽寄存器
#define INA226_REG_ALERT    0x07    // 报警限值寄存器
#define INA226_REG_DIE_ID   0xFF    // 芯片ID寄存器

// 配置寄存器位定义
#define INA226_CONFIG_RESET     0x8000  // 复位位
#define INA226_CONFIG_AVG_1     0x0000  // 平均次数: 1
#define INA226_CONFIG_AVG_4     0x0200  // 平均次数: 4
#define INA226_CONFIG_AVG_16    0x0400  // 平均次数: 16
#define INA226_CONFIG_AVG_64    0x0600  // 平均次数: 64
#define INA226_CONFIG_VBUSCT_140 0x0000  // 电压转换时间: 140us
#define INA226_CONFIG_VBUSCT_204 0x0040  // 电压转换时间: 204us
#define INA226_CONFIG_VBUSCT_332 0x0080  // 电压转换时间: 332us
#define INA226_CONFIG_VSHCT_140 0x0000   // 分流电压转换时间: 140us
#define INA226_CONFIG_VSHCT_204 0x0008   // 分流电压转换时间: 204us
#define INA226_CONFIG_VSHCT_332 0x0010   // 分流电压转换时间: 332us
#define INA226_CONFIG_MODE_SHUTDOWN 0x0000 // 关闭模式
#define INA226_CONFIG_MODE_TRIG_SHUNT 0x0001 // 触发分流电压
#define INA226_CONFIG_MODE_TRIG_BUS 0x0002   // 触发总线电压
#define INA226_CONFIG_MODE_TRIG_SHUNT_BUS 0x0003 // 触发分流+总线
#define INA226_CONFIG_MODE_CONT_SHUNT 0x0005   // 连续分流电压
#define INA226_CONFIG_MODE_CONT_BUS 0x0006     // 连续总线电压
#define INA226_CONFIG_MODE_CONT_SHUNT_BUS 0x0007 // 连续分流+总线

// 报警屏蔽寄存器位定义
#define INA226_MASK_SOL      0x8000  // 分流过压报警
#define INA226_MASK_SUL      0x4000  // 分流欠压报警
#define INA226_MASK_BOL      0x2000  // 总线过压报警
#define INA226_MASK_BUL      0x1000  // 总线欠压报警
#define INA226_MASK_POL      0x0800  // 功率过限报警
#define INA226_MASK_CNVR     0x0400  // 转换就绪报警

// 系统参数定义
#define SHUNT_RESISTANCE     0.01f   // 分流电阻值 (10mΩ)
#define MAX_EXPECTED_CURRENT 15.0f   // 最大预期电流 (15A)
#define CURRENT_LSB          (MAX_EXPECTED_CURRENT / 32768.0f) // 电流LSB
#define POWER_LSB            (CURRENT_LSB * 25.0f)  // 功率LSB (固定值)

// 数据结构体
typedef struct {
    float shunt_voltage;     // 分流电压 (V)
    float bus_voltage;       // 总线电压 (V)
    float current;          // 电流 (A)
    float power;            // 功率 (W)
    float temperature;      // 温度 (°C) - 可选
    uint8_t alert_status;   // 报警状态
    uint32_t timestamp;     // 时间戳
} INA226_Data_t;

// 报警限值结构体
typedef struct {
    float shunt_over_limit;  // 分流过压限值 (V)
    float shunt_under_limit;// 分流欠压限值 (V)
    float bus_over_limit;   // 总线过压限值 (V)
    float bus_under_limit;  // 总线欠压限值 (V)
    float power_over_limit; // 功率过限限值 (W)
} INA226_Alert_t;

// 函数声明
void INA226_Init(void);
void INA226_Configure(void);
void INA226_SetCalibration(float shunt_res, float max_current);
void INA226_SetAlertLimits(INA226_Alert_t *alert);
float INA226_ReadShuntVoltage(void);
float INA226_ReadBusVoltage(void);
float INA226_ReadCurrent(void);
float INA226_ReadPower(void);
void INA226_GetData(INA226_Data_t *data);
uint8_t INA226_CheckAlert(void);
void INA226_Reset(void);

#endif /* __INA226_H */

3.2 INA226 驱动核心 (ina226.c)

#include "ina226.h"
#include "i2c.h"

// I2C 底层函数声明
void I2C_WriteByte(uint8_t addr, uint8_t reg, uint8_t data);
uint8_t I2C_ReadByte(uint8_t addr, uint8_t reg);
uint16_t I2C_ReadWord(uint8_t addr, uint8_t reg);
void I2C_WriteWord(uint8_t addr, uint8_t reg, uint16_t data);

// 初始化 INA226
void INA226_Init(void) {
    // 复位 INA226
    INA226_Reset();
    Delay_ms(10);
    
    // 配置 INA226
    INA226_Configure();
    
    // 设置校准值
    INA226_SetCalibration(SHUNT_RESISTANCE, MAX_EXPECTED_CURRENT);
}

// 配置 INA226 寄存器
void INA226_Configure(void) {
    uint16_t config = 0;
    
    // 配置平均次数、转换时间、工作模式
    config = INA226_CONFIG_AVG_64 |           // 64次平均
             INA226_CONFIG_VBUSCT_332 |        // 总线电压转换时间 332us
             INA226_CONFIG_VSHCT_332 |         // 分流电压转换时间 332us
             INA226_CONFIG_MODE_CONT_SHUNT_BUS; // 连续分流+总线电压模式
    
    I2C_WriteWord(INA226_ADDR, INA226_REG_CONFIG, config);
}

// 设置校准寄存器
void INA226_SetCalibration(float shunt_res, float max_current) {
    uint16_t calibration;
    float current_lsb;
    
    // 计算电流 LSB (最小分辨率)
    current_lsb = max_current / 32768.0f;  // 15A / 32768 ≈ 0.00045776 A/bit
    
    // 计算校准值
    // CAL = 0.00512 / (Current_LSB * Shunt_Resistance)
    calibration = (uint16_t)(0.00512f / (current_lsb * shunt_res));
    
    // 写入校准寄存器
    I2C_WriteWord(INA226_ADDR, INA226_REG_CALIB, calibration);
}

// 设置报警限值
void INA226_SetAlertLimits(INA226_Alert_t *alert) {
    uint16_t mask = 0;
    uint16_t limit;
    
    // 配置报警屏蔽寄存器
    mask = INA226_MASK_SOL | INA226_MASK_SUL | 
           INA226_MASK_BOL | INA226_MASK_BUL | 
           INA226_MASK_POL | INA226_MASK_CNVR;
    
    I2C_WriteWord(INA226_ADDR, INA226_REG_MASK, mask);
    
    // 设置报警限值寄存器
    // 分流电压限值 (转换为16位有符号整数)
    limit = (uint16_t)(alert->shunt_over_limit / 0.0025f);  // 2.5mV/LSB
    I2C_WriteWord(INA226_ADDR, INA226_REG_ALERT, limit);
}

// 读取分流电压
float INA226_ReadShuntVoltage(void) {
    int16_t raw_value;
    float voltage;
    
    raw_value = (int16_t)I2C_ReadWord(INA226_ADDR, INA226_REG_SHUNT);
    voltage = raw_value * 0.0025f;  // 2.5mV/LSB
    
    return voltage;
}

// 读取总线电压
float INA226_ReadBusVoltage(void) {
    uint16_t raw_value;
    float voltage;
    
    raw_value = I2C_ReadWord(INA226_ADDR, INA226_REG_BUS);
    voltage = (raw_value >> 3) * 0.00125f;  // 1.25mV/LSB, 右移3位
    
    return voltage;
}

// 读取电流
float INA226_ReadCurrent(void) {
    int16_t raw_value;
    float current;
    
    raw_value = (int16_t)I2C_ReadWord(INA226_ADDR, INA226_REG_CURRENT);
    current = raw_value * CURRENT_LSB;  // 使用计算的电流LSB
    
    return current;
}

// 读取功率
float INA226_ReadPower(void) {
    uint16_t raw_value;
    float power;
    
    raw_value = I2C_ReadWord(INA226_ADDR, INA226_REG_POWER);
    power = raw_value * POWER_LSB;  // 使用计算的功率LSB
    
    return power;
}

// 获取所有数据
void INA226_GetData(INA226_Data_t *data) {
    data->shunt_voltage = INA226_ReadShuntVoltage();
    data->bus_voltage = INA226_ReadBusVoltage();
    data->current = INA226_ReadCurrent();
    data->power = INA226_ReadPower();
    data->timestamp = Get_SystemTime();  // 获取系统时间戳
}

// 复位 INA226
void INA226_Reset(void) {
    uint16_t config = INA226_CONFIG_RESET;
    I2C_WriteWord(INA226_ADDR, INA226_REG_CONFIG, config);
}

// 检查报警状态
uint8_t INA226_CheckAlert(void) {
    uint16_t alert_reg;
    
    alert_reg = I2C_ReadWord(INA226_ADDR, INA226_REG_ALERT);
    
    if (alert_reg & 0x8000) {  // 报警标志位
        return 1;  // 有报警
    }
    
    return 0;  // 无报警
}

3.3 功率数据发送程序 (power_transmitter.c)

#include "power_transmitter.h"
#include "ina226.h"
#include "uart.h"
#include "rs485.h"
#include "can.h"

// 发送数据格式定义
typedef struct {
    uint8_t header[4];        // 帧头 "PWR"
    uint32_t timestamp;       // 时间戳
    float bus_voltage;        // 总线电压 (V)
    float current;           // 电流 (A)
    float power;             // 功率 (W)
    float shunt_voltage;     // 分流电压 (V)
    uint8_t alert_status;    // 报警状态
    uint16_t checksum;       // 校验和
} PowerDataFrame_t;

// 通信协议选择
typedef enum {
    COMM_UART = 0,
    COMM_RS485,
    COMM_CAN,
    COMM_LORA
} CommProtocol_t;

// 全局变量
static CommProtocol_t current_protocol = COMM_UART;
static uint32_t send_interval = 1000;  // 发送间隔 (ms)
static uint8_t device_id = 0x01;       // 设备ID

// 初始化发送器
void PowerTransmitter_Init(void) {
    // 初始化各种通信接口
    UART_Init(115200);
    RS485_Init(9600);
    CAN_Init(500000);
    
    // 初始化 INA226
    INA226_Init();
    
    printf("Power Transmitter Initialized\r\n");
}

// 计算校验和
uint16_t CalculateChecksum(uint8_t *data, uint16_t length) {
    uint16_t checksum = 0;
    uint16_t i;
    
    for (i = 0; i < length; i++) {
        checksum += data[i];
    }
    
    return checksum;
}

// 打包功率数据
void PackagePowerData(PowerDataFrame_t *frame, INA226_Data_t *ina_data) {
    frame->header[0] = 'P';
    frame->header[1] = 'W';
    frame->header[2] = 'R';
    frame->header[3] = device_id;
    
    frame->timestamp = ina_data->timestamp;
    frame->bus_voltage = ina_data->bus_voltage;
    frame->current = ina_data->current;
    frame->power = ina_data->power;
    frame->shunt_voltage = ina_data->shunt_voltage;
    frame->alert_status = ina_data->alert_status;
    
    // 计算校验和
    frame->checksum = CalculateChecksum((uint8_t*)frame, sizeof(PowerDataFrame_t) - 2);
}

// 通过UART发送数据
void SendData_UART(PowerDataFrame_t *frame) {
    uint8_t *data = (uint8_t*)frame;
    uint16_t length = sizeof(PowerDataFrame_t);
    
    // 发送帧头
    UART_SendData(frame->header, 4);
    
    // 发送数据
    UART_SendData(&frame->timestamp, sizeof(uint32_t));
    UART_SendData((uint8_t*)&frame->bus_voltage, sizeof(float));
    UART_SendData((uint8_t*)&frame->current, sizeof(float));
    UART_SendData((uint8_t*)&frame->power, sizeof(float));
    UART_SendData((uint8_t*)&frame->shunt_voltage, sizeof(float));
    UART_SendData(&frame->alert_status, sizeof(uint8_t));
    UART_SendData((uint8_t*)&frame->checksum, sizeof(uint16_t));
    
    // 发送换行符
    UART_SendByte('\r');
    UART_SendByte('\n');
}

// 通过RS485发送数据
void SendData_RS485(PowerDataFrame_t *frame) {
    // 设置RS485为发送模式
    RS485_SetTxMode();
    
    // 发送数据
    RS485_SendData((uint8_t*)frame, sizeof(PowerDataFrame_t));
    
    // 等待发送完成
    Delay_ms(1);
    
    // 切换回接收模式
    RS485_SetRxMode();
}

// 通过CAN总线发送数据
void SendData_CAN(PowerDataFrame_t *frame) {
    CAN_TxHeaderTypeDef tx_header;
    uint8_t tx_data[8];
    
    // 配置CAN帧头
    tx_header.StdId = 0x100 + device_id;  // 标准ID
    tx_header.ExtId = 0;
    tx_header.IDE = CAN_ID_STD;
    tx_header.RTR = CAN_RTR_DATA;
    tx_header.DLC = 8;  // 8字节数据
    
    // 打包数据到CAN帧
    memcpy(tx_data, &frame->timestamp, 4);
    memcpy(tx_data + 4, &frame->power, 4);
    
    // 发送CAN帧
    CAN_SendMessage(&tx_header, tx_data);
}

// 发送功率数据
void PowerTransmitter_SendData(INA226_Data_t *ina_data) {
    PowerDataFrame_t frame;
    
    // 打包数据
    PackagePowerData(&frame, ina_data);
    
    // 根据选择的协议发送
    switch (current_protocol) {
        case COMM_UART:
            SendData_UART(&frame);
            break;
            
        case COMM_RS485:
            SendData_RS485(&frame);
            break;
            
        case COMM_CAN:
            SendData_CAN(&frame);
            break;
            
        default:
            SendData_UART(&frame);
            break;
    }
}

// 设置发送间隔
void PowerTransmitter_SetInterval(uint32_t interval_ms) {
    send_interval = interval_ms;
}

// 设置通信协议
void PowerTransmitter_SetProtocol(CommProtocol_t protocol) {
    current_protocol = protocol;
}

// 主循环处理
void PowerTransmitter_Process(void) {
    static uint32_t last_send_time = 0;
    INA226_Data_t ina_data;
    
    // 检查是否到达发送时间
    if (Get_SystemTime() - last_send_time >= send_interval) {
        // 读取 INA226 数据
        INA226_GetData(&ina_data);
        
        // 检查报警状态
        ina_data.alert_status = INA226_CheckAlert();
        
        // 发送数据
        PowerTransmitter_SendData(&ina_data);
        
        // 更新发送时间
        last_send_time = Get_SystemTime();
        
        // 打印调试信息
        printf("Power: %.2fW, Voltage: %.2fV, Current: %.2fA\r\n", 
               ina_data.power, ina_data.bus_voltage, ina_data.current);
    }
}

3.4 主程序 (main.c)

#include "stm32f10x.h"
#include "ina226.h"
#include "power_transmitter.h"
#include "uart.h"
#include "systick.h"

// 系统初始化
void System_Init(void) {
    // 初始化系统时钟
    SystemClock_Init();
    
    // 初始化延时
    Delay_Init();
    
    // 初始化串口
    UART_Init(115200);
    
    // 初始化 INA226
    INA226_Init();
    
    // 初始化功率发送器
    PowerTransmitter_Init();
    
    // 设置发送间隔为1秒
    PowerTransmitter_SetInterval(1000);
    
    // 选择UART通信协议
    PowerTransmitter_SetProtocol(COMM_UART);
    
    printf("System Initialized Successfully!\r\n");
}

int main(void) {
    // 系统初始化
    System_Init();
    
    printf("Power Monitoring System Started\r\n");
    printf("================================\r\n");
    
    while (1) {
        // 处理功率数据发送
        PowerTransmitter_Process();
        
        // 其他任务处理
        // ...
        
        // 延时
        Delay_ms(10);
    }
}

参考代码 功率检测发送程序 www.youwenfan.com/contentcsu/60494.html

四、上位机接收程序 (Python示例)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
功率数据接收程序
"""

import serial
import struct
import time
import threading

class PowerDataReceiver:
    def __init__(self, port='COM3', baudrate=115200):
        self.port = port
        self.baudrate = baudrate
        self.serial_conn = None
        self.running = False
        
    def connect(self):
        """连接串口"""
        try:
            self.serial_conn = serial.Serial(
                port=self.port,
                baudrate=self.baudrate,
                timeout=1
            )
            print(f"Connected to {self.port}")
            return True
        except Exception as e:
            print(f"Connection failed: {e}")
            return False
    
    def parse_data(self, data):
        """解析功率数据帧"""
        if len(data) < 24:  # 最小帧长度
            return None
            
        # 检查帧头
        if data[0:4] != b'PWR':
            return None
            
        try:
            # 解析数据 (小端序)
            timestamp = struct.unpack('<I', data[4:8])[0]
            bus_voltage = struct.unpack('<f', data[8:12])[0]
            current = struct.unpack('<f', data[12:16])[0]
            power = struct.unpack('<f', data[16:20])[0]
            shunt_voltage = struct.unpack('<f', data[20:24])[0]
            alert_status = data[24]
            checksum = struct.unpack('<H', data[25:27])[0]
            
            return {
                'timestamp': timestamp,
                'bus_voltage': bus_voltage,
                'current': current,
                'power': power,
                'shunt_voltage': shunt_voltage,
                'alert_status': alert_status
            }
        except Exception as e:
            print(f"Parse error: {e}")
            return None
    
    def receive_loop(self):
        """接收数据循环"""
        buffer = b''
        
        while self.running:
            try:
                if self.serial_conn and self.serial_conn.in_waiting > 0:
                    data = self.serial_conn.read(self.serial_conn.in_waiting)
                    buffer += data
                    
                    # 查找完整帧
                    while len(buffer) >= 27:  # 完整帧长度
                        # 查找帧头
                        header_pos = buffer.find(b'PWR')
                        if header_pos == -1:
                            buffer = b''
                            break
                        
                        # 提取完整帧
                        if len(buffer) >= header_pos + 27:
                            frame = buffer[header_pos:header_pos + 27]
                            parsed_data = self.parse_data(frame)
                            
                            if parsed_data:
                                self.display_data(parsed_data)
                            
                            # 移除已处理的数据
                            buffer = buffer[header_pos + 27:]
                        else:
                            break
                
                time.sleep(0.01)
                
            except Exception as e:
                print(f"Receive error: {e}")
                time.sleep(1)
    
    def display_data(self, data):
        """显示数据"""
        print(f"[{data['timestamp']}] "
              f"Voltage: {data['bus_voltage']:.2f}V, "
              f"Current: {data['current']:.2f}A, "
              f"Power: {data['power']:.2f}W, "
              f"Alert: {data['alert_status']}")
    
    def start(self):
        """启动接收器"""
        if not self.connect():
            return False
            
        self.running = True
        thread = threading.Thread(target=self.receive_loop)
        thread.daemon = True
        thread.start()
        
        print("Power data receiver started...")
        return True
    
    def stop(self):
        """停止接收器"""
        self.running = False
        if self.serial_conn:
            self.serial_conn.close()

if __name__ == "__main__":
    receiver = PowerDataReceiver(port='COM3', baudrate=115200)
    
    if receiver.start():
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            print("\nStopping receiver...")
            receiver.stop()
    else:
        print("Failed to start receiver")

五、优化 扩展

5.1 数据滤波优化

// 滑动平均滤波
typedef struct {
    float buffer[10];
    uint8_t index;
    uint8_t count;
} MovingAverage_t;

float MovingAverage_Filter(MovingAverage_t *filter, float new_value) {
    filter->buffer[filter->index] = new_value;
    filter->index = (filter->index + 1) % 10;
    
    if (filter->count < 10) {
        filter->count++;
    }
    
    float sum = 0;
    for (uint8_t i = 0; i < filter->count; i++) {
        sum += filter->buffer[i];
    }
    
    return sum / filter->count;
}

5.2 报警功能扩展

// 功率报警检测
typedef struct {
    float power_warning_threshold;   // 功率警告阈值
    float power_alarm_threshold;    // 功率报警阈值
    float voltage_high_limit;       // 电压上限
    float voltage_low_limit;        // 电压下限
    float current_high_limit;       // 电流上限
    uint8_t alarm_active;           // 报警激活标志
} PowerAlarm_t;

void PowerAlarm_Check(PowerAlarm_t *alarm, INA226_Data_t *data) {
    alarm->alarm_active = 0;
    
    // 功率报警
    if (data->power > alarm->power_alarm_threshold) {
        alarm->alarm_active |= 0x01;  // 功率严重报警
    } else if (data->power > alarm->power_warning_threshold) {
        alarm->alarm_active |= 0x02;  // 功率警告
    }
    
    // 电压报警
    if (data->bus_voltage > alarm->voltage_high_limit) {
        alarm->alarm_active |= 0x04;  // 电压过高
    } else if (data->bus_voltage < alarm->voltage_low_limit) {
        alarm->alarm_active |= 0x08;  // 电压过低
    }
    
    // 电流报警
    if (fabs(data->current) > alarm->current_high_limit) {
        alarm->alarm_active |= 0x10;  // 电流过大
    }
}

六、部署与测试

6.1 硬件测试步骤

  1. 连接检查: 确认 INA226 与 STM32 的 I2C 连接正确
  2. 电源测试: 测量 INA226 的供电电压 (3.3V)
  3. 分流电阻: 确认分流电阻值正确连接
  4. 负载测试: 接入已知负载验证测量准确性

6.2 软件测试命令

# 编译程序
make clean
make all

# 烧录到STM32
st-flash write build/power_monitor.bin 0x08000000

# 使用Python接收数据
python power_receiver.py

专注于matlab/simulink,电子电路,编程