【功率监测与控制系统DIY活动过程贴】功率计与LabVIEW数据采集
本文介绍了 NUCLEO-F411RE 开发板通过硬件 I2C 实现 INA219 功率传感器的驱动与 OLED 显示的功率计,并进一步结合 LabVIEW 上位机,通过串口中断采集功率数据的项目设计。
项目介绍
一、介绍 LabVIEW 软件及其关键组件、工具、模块、VISA 串口程序包等;
二、使用 STM32CubeMX 新建工程,并添加驱动工程代码、串口中断查询代码;
三、创建 LabVIEW 上位机,通过串口发送指令,获取 INA219 传感器数据功率信息;
四、运行 LabVIEW 上位机程序, OLED 实时显示电压、电流和功率信息,同时 LabVIEW 前面板显示功率演化曲线、数据保存,实现功率演化数据的采集。
LabVIEW
LabVIEW (Laboratory Virtual Instrument Engineering Workbench)是 National Instruments(NI)公司开发的一种图形化编程语言。主要用于数据采集、仪器控制、工业自动化以及测试测量系统的开发。
2023年,NI 被艾默生电气(Emerson)收购。
关键组件
1.前面板(Front Panel) 用户交互界面,包含按钮、图表、指示灯等控件。
2.程序框图(Block Diagram) 图形化编程区域,通过连线连接函数、结构和子VI。
3. VI(Virtual Instrument) LabVIEW程序的基本单元,每个VI包含前面板和程序框图,可嵌套使用。
4. 工具包与模块
DAQmx:数据采集驱动;
Vision Development Module:机器视觉处理;
LabVIEW NXG:新一代Web化设计工具。
详见:艾默生旗下测试和测量系统 - NI .
硬件连接
PB9 ---- SDA (INA219)
PB10 ---- SCL (INA219)
PB7 ---- SDA (OLED)
PB6 ---- SCL (OLED)
GND (INA219) ---- Negative (Motor) ---- Negative (Power Supply)
IN+ (INA219) ---- Positive (Power Supply)
IN- (INA219) ---- Positive (Motor)
示意图


实物连接


工程创建
实现 INA219 和 OLED 的硬件 IIC 驱动、串口中断查询信息。
这里使用 STM32CubeMX 快速创建工程。
1.打开 STM32CubeMX 软件,新建 ST 板卡工程;
2.时钟配置:采用默认设置,系统时钟频率 84MHz;
3. Pinout & Configuration 标签下选择 Connectivity - 使能 I2C1 和 I2C2 以及 USART2 ;
4. 勾选使能串口中断,以实现串口发送指令查询数据;


5.配置完成后,进入 Project Manager 标签栏,进行项目命名、保存路径设置、编译器选择等操作;
6.点击 Generate Code 按钮,使用 STM32CubeIDE 或 Keil 打开目标工程;
7.编译工程,0 error, 0 warning .
工程代码
结合前面关于 OLED 屏幕以及 INA219 传感器的硬件 IIC 驱动方案,添加 oled.h 、 oled.c 、 oledfont.h 、ina219.h、ina219.c 文件至指定路径。
添加代码实现 printf 重定向、串口输出浮点型数据
1.进入项目资源管理器,右键项目,选择属性;
2.在弹出的对话框中,选择 C/C++ Build ,展开 C/C++ Build 并选择 Settings ;
3.选择 Tool Settings - MCU Settings ;
4.勾选 Use float with printf from newlib-nano (-u printf float) ;
5.点击 Apply 应用自动重新构建项目,点击 Apply and Close 保存配置。
6.右键项目 - 属性 - C/C++ Build - Setting - Tool Settings - MCU GCC Linker - Miscellaneous - Other flags - 点击添加符号,输入 -u_printf_float ,应用并关闭。
详见:【功率监测与控制系统DIY活动过程贴】OLED显示 、【功率监测与控制系统DIY活动过程贴】INA219功率信息检测与实时显示 .
流程图


main.c 关键代码如下
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ina219.h"
#include "stdio.h"
#include "oled.h"
#include "string.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* -------- Private variables ------*/
#define CMD_LENGTH 3
uint8_t uart_rx_buffer[CMD_LENGTH]; // 接收指令缓冲区
uint8_t uart_rx_index = 0; // 接收索引
uint8_t command_received = 0; // 指令接收完成标志
/* USER CODE END PTD */
/* USER CODE BEGIN PD */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart2, (uint8_t*)&ch,1,HAL_MAX_DELAY);
return ch;
}
/* USER CODE END PD */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void process_command(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
// 串口接收回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2) {
uart_rx_index++;
if(uart_rx_index >= CMD_LENGTH) {
uart_rx_index = 0;
command_received = 1; // 设置指令接收完成标志
}
// 重新启动接收
HAL_UART_Receive_IT(&huart2, &uart_rx_buffer[uart_rx_index], 1);
}
}
// 处理接收到的指令
void process_command(void)
{
// 检查指令前缀是否为0x55 0xAA
if(uart_rx_buffer[0] == 0x55 && uart_rx_buffer[1] == 0xAA)
{
switch(uart_rx_buffer[2])
{
case 0x10: // 读取电压
{
float busVoltage = INA219_GetBusVoltage_V();
printf("%.2f\r\n",busVoltage);
break;
}
case 0x11: // 读取电流
{
float current = INA219_GetCurrent_mA();
printf("%.2f\r\n",current);
break;
}
case 0xFF: // 读取功率
{
float power = INA219_GetPower_mW();
printf("%.2f\r\n",power);
break;
}
default:
// 无效指令,可以发送错误码
uint8_t error_code = 0xEE;
HAL_UART_Transmit_IT(&huart2, &error_code, 1);
break;
}
}
command_received = 0; // 清除标志
}
void data_display()
{
float busVoltage = INA219_GetBusVoltage_V();
//float shuntVoltage = INA219_GetShuntVoltage_mV();
float current = INA219_GetCurrent_mA();
float power = INA219_GetPower_mW();
OLED_ClearLinePart(2, 45, 99);
OLED_ClearLinePart(3, 45, 99);
OLED_ShowDecimal(45,2,current,2,2,16,0);
OLED_ClearLinePart(4, 45, 99);
OLED_ClearLinePart(5, 45, 99);
OLED_ShowDecimal(45,4,busVoltage,2,2,16,0);
OLED_ClearLinePart(6, 45, 99);
OLED_ClearLinePart(7, 45, 99);
OLED_ShowDecimal(45,6,power,2,2,16,0);
}
/* USER CODE END 0 */
int main(void)
{
HAL_Init();
/* USER CODE BEGIN Init */
INA219_Init(&hi2c2);
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_I2C2_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
// 启动串口接收中断
HAL_UART_Receive_IT(&huart2, &uart_rx_buffer[0], 1);
// OLED display frame
OLED_Init();
OLED_Clear();
/* --- 1st row --- */
OLED_ShowString(0,0,"DIY",16,1); // DIY
OLED_ShowCHinese(24,0,0,1); // 功
OLED_ShowCHinese(39,0,1,1); // 率
OLED_ShowCHinese(54,0,2,1); // 监
OLED_ShowCHinese(69,0,3,1); // 测
OLED_ShowCHinese(84,0,4,1); // 与
OLED_ShowCHinese(99,0,5,1); // 控
OLED_ShowCHinese(113,0,6,1); // 制
/* --- 2nd row --- */
OLED_ShowCHinese(0,2,7,0); // 电
OLED_ShowCHinese(15,2,9,0); // 流
OLED_ShowChar(30,2,':',16,0);
OLED_ShowString(100,2,"mA",16,0);
/* --- 3rd row --- */
OLED_ShowCHinese(0,4,7,0); // 电
OLED_ShowCHinese(15,4,8,0); // 压
OLED_ShowChar(30,4,':',16,0);
OLED_ShowString(100,4,"V",16,0);
/* --- 4th row --- */
OLED_ShowCHinese(0,6,0,0); // 功
OLED_ShowCHinese(15,6,1,0); // 率
OLED_ShowChar(30,6,':',16,0);
OLED_ShowString(100,6,"mW",16,0);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE BEGIN 3 */
if(command_received)
{
process_command();
data_display();
}
HAL_Delay(0);
}
/* USER CODE END 3 */
}★ 注意用户自定义代码需写入 /* USER CODE BEGIN x */ 和 /* USER CODE END x */ 之间,确保CubeMX再次生成工程,代码不会被覆盖。
保存代码,编译工程,运行程序,则固件上传至 NUCLEO-F411RE 开发板,程序运行。
LabVIEW 上位机
介绍了 LabVIEW 上位机向开发板发送串口指令,获取 INA219 传感器电压和电流数据,并绘制功率数值演化曲线。
前面板
功能实现:
1.配置串口
2.运行程序
3.点击 Start 开始采集数据
4.点击 Stop 停止采集
5.点击 Terminate 终止程序。


程序框图
Page 1


Page 2


效果
打开串口调试助手,以十六进制发送 55 AA 10 获得电压信息,发送 55 AA 11 获得电流信息,发送 55 AA FF 获得功率信息。
LabVIEW 上位机演示
演示了开启电机瞬间的电压、电流以及功率的变化情况。


分析
可以看出,直接采集 INA219 传感器获取的数据存在较大的抖动,可采取 滤波算法 (软件滤波、低通滤波、滑动平均等)进行参数优化,使输出功率更为稳定、更符合实际情况。
总结
本文介绍了 NUCLEO-F411RE 开发板通过硬件 I2C 实现 INA219 功率传感器的驱动与 OLED 显示,并进一步结合 LabVIEW 上位机,通过串口中断采集功率数据的项目设计,为相关产品及项目的开发设计提供了参考。
我要赚赏金
