基于 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 硬件测试步骤
- 连接检查: 确认 INA226 与 STM32 的 I2C 连接正确
- 电源测试: 测量 INA226 的供电电压 (3.3V)
- 分流电阻: 确认分流电阻值正确连接
- 负载测试: 接入已知负载验证测量准确性
6.2 软件测试命令
# 编译程序
make clean
make all
# 烧录到STM32
st-flash write build/power_monitor.bin 0x08000000
# 使用Python接收数据
python power_receiver.py