【功率监测与控制系统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 上位机,通过串口中断采集功率数据的项目设计,为相关产品及项目的开发设计提供了参考。