当前位置: 首页 > news >正文

零知开源——基于STM32F407VET6和INA219的功率监测器设计与实现

  ✔零知IDE 是一个真正属于国人自己的开源软件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!

✔访问零知实验室,获取更多实战项目和教程资源吧!

www.lingzhilab.com

(1)项目概述

        本教程详细介绍了如何使用零知增强板(STM32F407VET6主控)和INA219电流/功率传感器构建一个高精度LED灯功率监测系统。项目包含实时波形显示、数据滤波处理、串口数据输出等功能,并通过ST7789显示屏直观展示测量结果。文章将从硬件选型、软件实现到精度优化进行全面讲解。

(2)项目亮点

        >通过配置INA219为16V/400mA高精度模式,实现±0.1mA电流精度
        >采用多通道波形显示技术,支持自动缩放
        >滑动平均滤波算法有效降低噪声干扰
        >优化刷新策略,降低系统功耗
        >精心设计的UI布局,信息展示直观清晰

(3)项目难点及解决方案

问题描述:小电流测量精度不足,在测量mA级电流时,传感器读数存在偏差(约0.15mA)且波动较大

解决方案:

        >配置INA219为高精度模式(16V量程,400mA量程)
        >启用128次采样平均,显著降低噪声
        >在软件中增加零点校准功能(在无负载时自动计算偏移量)
        >添加滑动平均滤波算法

一、硬件系统设计

1.1 硬件清单

组件型号数量备注
主控板零知增强板(STM32F407VET6)1主控制器
电流传感器INA2191电流/功率测量
显示屏ST7789 TFT (240x320)1数据显示
连接线杜邦线若干硬件连接

1.2 接线方案

零知增强板(STM32F407VET6)INA219 (I2C)ST7789(SPI)引脚功能说明
3.3V/VCC3.3V电源
5VVCC/5V电源
GNDGNDGND接地
SCLSCL/21/I2C时钟
SDASDA/20/I2C数据
53/CS片选
2/DC数据/命令选择
51/SDA主出从入
52/SCL时钟
4/RES复位

1.3 连接硬件图

1.4 实物连接图

二、软件架构设计

2.1 库文件导入

#include <Wire.h>        //与INA219进行I2C协议通信
#include <Adafruit_INA219.h>        //电流、电压传感器库文件
#include <Adafruit_GFX.h>        //核心图形库文件
#include <Adafruit_ST7789.h>        //显示屏驱动文件
#include <SPI.h>    //显示屏SPI通信协议库文件

2.2 初始化设置

void setup(void) {Serial.begin(9600);// 显示屏初始化tft.init(240, 320);tft.invertDisplay(true);tft.setRotation(1); // 横屏模式// 显示开机画面showSplashScreen();delay(1500);// 传感器初始化if (!sensor219.begin()) {Serial.println("Failed to find INA219 chip");while (1);}// 滤波数组初始化for (int i = 0; i < numReadings; i++) {currentReadings[i] = 0;}// 历史数据初始化for (int i = 0; i < HISTORY_SIZE; i++) {voltageHistory[i] = 0;currentHistory[i] = 0;powerHistory[i] = 0;}// 绘制静态UIdrawStaticUI();
}

2.3 主循环处理

void loop(void) {float busVoltage = sensor219.getBusVoltage_V();float current = sensor219.getCurrent_mA() - 0.05;float power = busVoltage * (current/1000);// 电流滤波处理currentTotal -= currentReadings[readIndex];currentReadings[readIndex] = current;currentTotal += currentReadings[readIndex];readIndex = (readIndex + 1) % numReadings;currentAvg = currentTotal / numReadings;// 更新历史数据voltageHistory[historyIndex] = busVoltage;currentHistory[historyIndex] = currentAvg;powerHistory[historyIndex] = power * 1000; // 转换为mW// 更新显示屏updateUI(busVoltage, currentAvg, power * 1000);// 移动历史索引historyIndex = (historyIndex + 1) % HISTORY_SIZE;// 串口打印数据Serial.print("Bus Voltage:  "); Serial.print(busVoltage, 3); Serial.println(" V");  Serial.print("Current:      "); Serial.print(currentAvg, 3); Serial.println(" mA");Serial.print("Power:        "); Serial.print(power * 1000,3); Serial.println(" mW");Serial.println("------------------------");delay(1000); // 1000ms刷新率
}

        >获取电压、电流值并计算得到功率值

        >通过10点滑动滤波处理电流数据

        >数据传输到ST7789显示屏波形展示/串口打印输出

        >每秒刷新一次

2.4 波形绘制实现

void updateUI(float voltage, float current, float power) {// 更新右侧面板数值updatePanelValues(voltage, current, power);// 清除图表区域 (保留坐标轴和边框)tft.fillRect(GRAPH_X + 1, GRAPH_Y + 1, GRAPH_WIDTH - 1, GRAPH_HEIGHT - 1, BACKGROUND);// 重绘坐标轴(因为部分可能被覆盖)drawAxes();// 查找最大值用于缩放float maxVal = 0.1;for (int i = 0; i < HISTORY_SIZE; i++) {if (voltageHistory[i] > maxVal) maxVal = voltageHistory[i];if (currentHistory[i] > maxVal) maxVal = currentHistory[i];if (powerHistory[i] > maxVal) maxVal = powerHistory[i];}// 添加15%的余量maxVal *= 1.15;// 绘制新的历史曲线 - 使用稀疏点绘制for (int i = 1; i < HISTORY_SIZE; i++) {int prevIndex = (historyIndex + i - 1) % HISTORY_SIZE;int currIndex = (historyIndex + i) % HISTORY_SIZE;// 计算X位置 - 每2像素一个点int x1 = GRAPH_X + (i-1) * 2;int x2 = GRAPH_X + i * 2;// 如果超出图表范围则停止绘制if (x2 > GRAPH_X + GRAPH_WIDTH) break;// 电压曲线int y1_voltage = GRAPH_Y + GRAPH_HEIGHT - constrain(voltageHistory[prevIndex] / maxVal * GRAPH_HEIGHT, 0, GRAPH_HEIGHT);int y2_voltage = GRAPH_Y + GRAPH_HEIGHT - constrain(voltageHistory[currIndex] / maxVal * GRAPH_HEIGHT, 0, GRAPH_HEIGHT);tft.drawLine(x1, y1_voltage, x2, y2_voltage, VOLTAGE_COLOR);// 电流曲线int y1_current = GRAPH_Y + GRAPH_HEIGHT - constrain(currentHistory[prevIndex] / maxVal * GRAPH_HEIGHT, 0, GRAPH_HEIGHT);int y2_current = GRAPH_Y + GRAPH_HEIGHT - constrain(currentHistory[currIndex] / maxVal * GRAPH_HEIGHT, 0, GRAPH_HEIGHT);tft.drawLine(x1, y1_current, x2, y2_current, CURRENT_COLOR);// 功率曲线int y1_power = GRAPH_Y + GRAPH_HEIGHT - constrain(powerHistory[prevIndex] / maxVal * GRAPH_HEIGHT, 0, GRAPH_HEIGHT);int y2_power = GRAPH_Y + GRAPH_HEIGHT - constrain(powerHistory[currIndex] / maxVal * GRAPH_HEIGHT, 0, GRAPH_HEIGHT);tft.drawLine(x1, y1_power, x2, y2_power, POWER_COLOR);}// 绘制Y轴刻度tft.setTextColor(0xAD75); // 浅灰色tft.setTextSize(1);// 最大值tft.setCursor(GRAPH_X + 2,GRAPH_Y + 5);tft.print(maxVal, 1);// 中间值tft.setCursor(GRAPH_X + 2,GRAPH_Y + GRAPH_HEIGHT/2 + 5);tft.print(maxVal/2, 1);// 最小值tft.setCursor(GRAPH_X - 5, GRAPH_Y + GRAPH_HEIGHT + 5);tft.print("0");
}void updatePanelValues(float voltage, float current, float power) {// 设置文本属性tft.setTextColor(TEXT_COLOR);tft.setTextSize(1);// 电压值 (只刷新数值部分)tft.fillRect(PANEL_X + 25, PANEL_Y + 65, 30, 12, PANEL_COLOR);tft.setCursor(PANEL_X + 25, PANEL_Y + 70);tft.print(voltage, 2);// 电流值tft.fillRect(PANEL_X + 25, PANEL_Y + 125, 30, 12, PANEL_COLOR);tft.setCursor(PANEL_X + 25, PANEL_Y + 130);tft.print(current, 2);// 功率值tft.fillRect(PANEL_X + 25, PANEL_Y + 185, 30, 12, PANEL_COLOR);tft.setCursor(PANEL_X + 25, PANEL_Y + 190);tft.print(power, 2);
}

        清除图表区域并将新的数据更新到右侧面板,绘制蓝色电压曲线、紫色电流曲线和红色功率曲线实时显示三通道波形,同时动态计算Y轴刻度

2.5 INA219库文件解析

(1)高精度模式配置

void Adafruit_INA219::init() {// 使用16V/400mA高精度模式setCalibration_16V_400mA();// 增强配置:启用128次采样平均Adafruit_BusIO_Register config_reg =Adafruit_BusIO_Register(i2c_dev, INA219_REG_CONFIG, 2, MSBFIRST);uint16_t config = INA219_CONFIG_BVOLTAGERANGE_16V |INA219_CONFIG_GAIN_1_40MV | INA219_CONFIG_BADCRES_12BIT |INA219_CONFIG_SADCRES_12BIT_128S_69MS | // 128次采样平均INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;config_reg.write(config, 2);
}

(2)16V/400mA校准模式详解

void Adafruit_INA219::setCalibration_16V_400mA() {// 配置参数:// 总线电压范围:16V// 增益:1(量程±40mV)// 分流电阻:0.1Ωina219_calValue = 8192;  // 校准寄存器值// 电流计算参数ina219_currentDivider_mA = 20; // 电流LSB = 50μA// 功率计算参数ina219_powerMultiplier_mW = 1.0f; // 功率LSB = 1mW// 写入校准寄存器Adafruit_BusIO_Register calibration_reg =Adafruit_BusIO_Register(i2c_dev, INA219_REG_CALIBRATION, 2, MSBFIRST);calibration_reg.write(ina219_calValue, 2);// 配置寄存器设置uint16_t config = INA219_CONFIG_BVOLTAGERANGE_16V |INA219_CONFIG_GAIN_1_40MV | INA219_CONFIG_BADCRES_12BIT |INA219_CONFIG_SADCRES_12BIT_1S_532US |INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;Adafruit_BusIO_Register config_reg =Adafruit_BusIO_Register(i2c_dev, INA219_REG_CONFIG, 2, MSBFIRST);config_reg.write(config, 2);
}

三、功能展示

3.1 显示屏界面

界面包含三个主要区域:

        波形显示区:左侧区域显示电压(蓝)、电流(紫)、功率(红)的实时波形
        数据面板:右侧显示实时测量值
        图例区:底部显示各波形对应的参数

3.2 万用表对比测试

>将万用表分别打到量程为20V的电压档以及20mA的电流档

参数万用表测量值系统测量值误差
电压3.25V3.20V-0.05V
电流2.66mA2.73mA+0.07mA
功率8.645mW8.984mW+0.339mW

注:万用表测量的功率值为两次万用表测量的电压和电流值乘积、系统测量的功率值为传感器获取到10次功率平均值。电压值和电流值误差在控制范围内

3.3 视频演示

(1)电压值获取

INA219获取电压值数据对比

传感器读取到的电压值3.22V,万用表获取到的电压值为3.27V

(2)电流值获取

INA219获取电流值数据对比

传感器读取到的电流值为2.74mA,万用表获取到的电流值为2.66mA

3.4 串口数据输出

        串口监视器输出电压、电流和功率数值和波形曲线

四、INA219检测技术解析

4.1 基础原理

        INA219检测电流的原理是计算电流经过采样电阻两端的压差,进行计算得到,整个过程由芯片自动计算,因此只需要确定好采样电阻、设置好寄存器即可获取到电流值。

根据芯片手册,经过分流电阻N(采样电阻)后,能够采集到的最低有效电压LSB为10uV。

电流公式:I_{current}=\frac{V_{shunt}}{R_{shunt}}

4.2 关键参数计算

(1)校准值计算 :Cal = \frac{0.04096}{Current_{LSB} \times R_{SHUNT}}       

  • 其中 Current_{LSB}为最小分辨率

(2)电流分辨率选择:Current{_{LSB}} = \tfrac{Expected\left ( I_{Max} \right ) }{32767}

  • 对于400mA量程:0.4A / 32767 ≈ 12.2μA

(3)实际配置:本项目采用0.1mA分辨率(平衡精度和量程)

4.3 精度影响因素

        分流电阻精度:建议使用0.1%精度的电阻
        ADC量化误差:12位ADC分辨率限制
        温度漂移:约±0.005%/℃
        噪声干扰:电源纹波和电磁干扰

可以采取的优化测量精度策略:使用高精度模式(降低量程)、增加采样平均次数、软件滤波处理、温度补偿

五、常见问题解答

Q1:为什么电流测量值总是有偏差?

A:可能原因及解决方案,

可能原因:

        零点偏移未校准

        分流电阻值不精确

        温度影响

解决方案:

        在无负载时进行零点校准
        使用精密分流电阻(0.1Ω±0.1%)
        添加软件补偿值

Q2:如何提高刷新率?

A:可采取的优化策略,

        减少历史数据点数(如从100减至50)
        降低采样平均次数(从128降至64)
        减少滤波窗口大小

Q3:显示屏出现花屏或者空白怎么办?

A:排查步骤,

        检查接线是否牢固(特别是RES、DC、CS引脚)
        确认电源稳定(3.3V电压足够)
        降低SPI时钟频率
        检查屏幕初始化代码(旋转方向、分辨率)

六、结论

        本项目成功实现了基于STM32F407VET6和INA219的高精度功率监测系统。通过精心设计的硬件配置和软件优化,系统达到了:

        电流测量精度:±0.1mA
        电压测量精度:±0.05V
        功率计算精度:±1mW

项目资源:

1.传感器库文件:INA219驱动库

2.传感器数据手册:INA219数据手册

3.STM32F407参考手册:STM32F4参考手册

本文所有代码均已在实际硬件平台测试通过,读者可根据需求自行调整参数!点击了解更多零知开发教程:

https://www.lingzhilab.com/freesources.html

http://www.lryc.cn/news/618146.html

相关文章:

  • ZKmall开源商城的容灾之道:多地域部署与故障切换如何守护电商系统
  • 【新启航】从人工偏差到机械精度:旋转治具让三维扫描重构数据重复精度提升至 ±0.01mm
  • 解决 HTTP 请求 RequestBody 只能被读取一次的问题
  • 医美产业科技成果展陈中心:连接微观肌肤世界与前沿科技的桥梁
  • 【机器学习】什么是DNN / MLP(全连接深度神经网络, Deep Neural Network / Multilayer Perceptron)?
  • 01. maven的下载与配置
  • http网页部署
  • 微算法科技(NASDAQ:MLGO)开发经典增强量子优化算法(CBQOA):开创组合优化新时代
  • 聆思duomotai_ap sdk适配dooiRobot
  • 基于SpringBoot的课程作业管理系统
  • 【论文阅读】从表面肌电信号中提取神经信息用于上肢假肢控制:新兴途径与挑战
  • iOS 签名证书全生命周期实战,从开发到上架的多阶段应用
  • 数据可视化交互深入理解
  • 论文阅读:Agricultural machinery automatic navigation technology
  • 【论文阅读】RestorerID: Towards Tuning-Free Face Restoration with ID Preservation
  • LeetCode 分割回文串
  • 增加vscode 邮件菜单
  • 论文阅读(九)Locality-Aware Zero-Shot Human-Object Interaction Detection
  • Openlayers基础教程|从前端框架到GIS开发系列课程(24)openlayers结合canva绘制矩形绘制线
  • iOS 签名证书实践日记,我的一次从申请到上架的亲历
  • Docker-10.Docker基础-自定义镜像
  • 医疗矫正流(MedRF)框架在数智化系统中的深度应用
  • 无人机在环保监测中的应用:低空经济发展的智能监测与高效治理
  • 云平台监控-云原生环境Prometheus企业级监控实战
  • .NET MAUI框架编译Android应用流程
  • 计算机视觉(7)-纯视觉方案实现端到端轨迹规划(思路梳理)
  • 《飞算Java AI:从安装到需求转实战项目详细教学》
  • 解决anaconda打包幻境是报错:ImportError: cannot import name ‘tarfile‘ from ‘backports‘
  • Java多线程基础总结
  • 云原生环境Prometheus企业级监控实战