文章目录
-
- 一、技术背景与实现目标
- 二、硬件准备与开发环境搭建
-
- [2.1 硬件清单(零基础适配)](#2.1 硬件清单(零基础适配))
- [2.2 开发环境搭建步骤](#2.2 开发环境搭建步骤)
- 三、整体实现流程(Mermaid流程图)
- 四、详细代码实现
-
- [4.1 代码文件结构](#4.1 代码文件结构)
- [4.2 头文件定义(phm_monitor.h)](#4.2 头文件定义(phm_monitor.h))
- [4.3 核心实现代码(phm_monitor.c)](#4.3 核心实现代码(phm_monitor.c))
- [4.4 主函数实现(main.c)](#4.4 主函数实现(main.c))
- 五、代码烧录与测试步骤
-
- [5.1 代码烧录](#5.1 代码烧录)
- [5.2 测试步骤](#5.2 测试步骤)
- 六、功能扩展建议
- 七、常见问题与解决方法
一、技术背景与实现目标
故障预测与健康管理(PHM, Prognostics and Health Management)是通过实时采集设备运行状态参数,结合算法分析实现故障早期预警的技术体系。本文以STM32G4系列单片机为核心,实现对芯片自身核心健康参数的实时监控,包括:
- 芯片内核温度(内置温度传感器)
- 供电电压(VDD/VREFINT参考电压校准)
- Flash读写次数(模拟存储寿命计数)
- 系统运行时长与异常复位次数
通过阈值判断实现早期故障预警,最终输出可视化的健康状态报告,为嵌入式设备的预防性维护提供依据。
二、硬件准备与开发环境搭建
2.1 硬件清单(零基础适配)
| 硬件名称 | 型号/规格 | 数量 | 用途 |
|---|---|---|---|
| 开发板 | STM32G431RBT6-Nucleo | 1块 | 核心控制单元 |
| USB数据线 | Type-C | 1根 | 烧录程序+串口通信 |
| 杜邦线 | 公对公/公对母 | 若干 | 可选扩展外设 |
| 电源 | 5V/1A | 1个 | 开发板供电(可选) |
2.2 开发环境搭建步骤
步骤1:安装STM32CubeIDE
- 下载地址:https://www.st.com/en/development-tools/stm32cubeide.html
- 安装流程:
- 运行安装包,选择安装路径(建议非中文路径,如
D:\STM32CubeIDE_1.15.0) - 勾选"STM32CubeMX Integration",完成安装
- 首次启动需配置编译器路径,默认路径无需修改
- 运行安装包,选择安装路径(建议非中文路径,如
步骤2:安装STM32G4固件库
- 打开STM32CubeIDE,点击菜单栏
Help->STM32Cube MCU Package Installer - 在搜索框输入
STM32G4,勾选STM32Cube FW_G4 V1.6.0(最新稳定版) - 点击
Install Now,等待固件库下载安装完成
步骤3:配置串口终端(用于查看监控数据)
- 下载串口工具:SSCOM5.13(免费开源)
- 配置参数:波特率115200、数据位8、停止位1、无校验、无流控
三、整体实现流程(Mermaid流程图)
否
是
是
否
系统初始化
参数采集模块初始化
采集周期到?
采集内核温度
采集供电电压
读取Flash寿命计数
统计系统运行状态
阈值判断与异常标记
是否触发预警?
输出预警信息到串口
输出正常健康状态
存储历史数据到Flash
四、详细代码实现
4.1 代码文件结构
PHM_Project/
├── Core/
│ ├── Inc/
│ │ ├── main.h // 主函数头文件
│ │ ├── phm_monitor.h // PHM监控模块头文件
│ │ ├── stm32g4xx_hal_conf.h // HAL配置文件
│ │ └── stm32g4xx_it.h // 中断服务函数头文件
│ └── Src/
│ ├── main.c // 主函数(核心逻辑)
│ ├── phm_monitor.c // PHM监控模块实现
│ ├── stm32g4xx_hal_msp.c // MSP初始化
│ └── sysmem.c // 系统内存配置
└── STM32G431RBTx_FLASH.ld // 链接脚本
4.2 头文件定义(phm_monitor.h)
文件名:phm_monitor.h
c
#ifndef __PHM_MONITOR_H
#define __PHM_MONITOR_H
#include "stm32g4xx_hal.h"
#include <stdint.h>
#include <stdbool.h>
// 健康参数阈值配置(可根据实际需求调整)
#define TEMP_WARNING_THRESHOLD 60.0f // 温度预警阈值(℃)
#define TEMP_ERROR_THRESHOLD 85.0f // 温度故障阈值(℃)
#define VDD_WARNING_LOW_THRESHOLD 2.9f // 电压低预警阈值(V)
#define VDD_WARNING_HIGH_THRESHOLD 3.4f // 电压高预警阈值(V)
#define FLASH_CYCLE_WARNING 10000 // Flash读写次数预警阈值
#define RESET_ERROR_THRESHOLD 5 // 异常复位次数阈值
// 健康状态枚举
typedef enum {
PHM_STATUS_NORMAL = 0, // 正常
PHM_STATUS_WARNING, // 预警
PHM_STATUS_ERROR // 故障
} PHM_StatusTypeDef;
// 设备健康数据结构体
typedef struct {
float core_temperature; // 内核温度(℃)
float vdd_voltage; // VDD供电电压(V)
uint32_t flash_write_count; // Flash写入次数
uint32_t system_run_time; // 系统运行时间(秒)
uint8_t reset_count; // 异常复位次数
PHM_StatusTypeDef overall_status; // 整体健康状态
} PHM_DataStruct;
// 函数声明
void PHM_Monitor_Init(void); // 监控模块初始化
void PHM_Collect_All_Parameters(void); // 采集所有参数
void PHM_Check_Health_Status(void); // 检查健康状态
void PHM_Print_Health_Info(void); // 打印健康信息
void PHM_Save_History_Data(void); // 保存历史数据
float PHM_Get_Core_Temperature(void); // 获取内核温度
float PHM_Get_VDD_Voltage(void); // 获取VDD电压
uint32_t PHM_Get_Flash_Write_Count(void); // 获取Flash写入次数
void PHM_Increment_Flash_Write_Count(void); // 增加Flash写入次数
void PHM_Increment_Reset_Count(void); // 增加复位次数
#endif /* __PHM_MONITOR_H */
4.3 核心实现代码(phm_monitor.c)
文件名:phm_monitor.c
c
#include "phm_monitor.h"
#include "stm32g4xx_hal_adc.h"
#include "stm32g4xx_hal_flash.h"
// 全局变量定义
static PHM_DataStruct phm_data = {0};
static ADC_HandleTypeDef hadc1; // ADC句柄(用于温度/电压采集)
static TIM_HandleTypeDef htim6; // 定时器句柄(用于定时采集)
// Flash存储地址定义(选择未使用的Flash区域,需匹配芯片容量)
#define FLASH_DATA_ADDR 0x0801FC00 // STM32G431RBT6 Flash末尾区域
#define FLASH_PAGE_SIZE 2048 // STM32G4 Flash页大小
/**
* @brief ADC初始化(用于温度传感器和VREFINT采集)
* @note 零基础适配:ADC1通道16=温度传感器,通道17=VREFINT
*/
static void MX_ADC1_Init(void)
{
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
// ADC基础配置
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; // 扫描模式(多通道)
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换模式
hadc1.Init.NbrOfConversion = 2; // 2个通道(温度+VREFINT)
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
// 多模式配置(单ADC模式)
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
// 通道16配置(温度传感器)
sConfig.Channel = ADC_CHANNEL_16;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5; // 长采样时间保证精度
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
// 通道17配置(VREFINT参考电压)
sConfig.Channel = ADC_CHANNEL_17;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
// 启用温度传感器和VREFINT
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
__HAL_ADC_ENABLE(&hadc1);
}
/**
* @brief 定时器6初始化(1秒定时,用于参数采集周期)
*/
static void MX_TIM6_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim6.Instance = TIM6;
htim6.Init.Prescaler = 8399; // 84MHz/8400=10kHz
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 9999; // 10kHz/10000=1Hz(1秒)
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
// 启动定时器中断
HAL_TIM_Base_Start_IT(&htim6);
}
/**
* @brief 获取内核温度
* @retval 温度值(℃)
*/
float PHM_Get_Core_Temperature(void)
{
uint32_t adc_temp_value = 0;
float temperature = 0.0f;
// 启动ADC转换
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100); // 等待转换完成(超时100ms)
// 读取温度传感器ADC值
adc_temp_value = HAL_ADC_GetValue(&hadc1);
// STM32G4温度计算公式:Temp(℃) = (Vtemp - V25)/Avg_Slope + 25
// V25=0.76V, Avg_Slope=2.5mV/℃, Vtemp=ADC值*3.3/4095
temperature = ((adc_temp_value * 3.3f / 4095.0f) - 0.76f) / 0.0025f + 25.0f;
HAL_ADC_Stop(&hadc1);
return temperature;
}
/**
* @brief 获取VDD供电电压
* @retval 电压值(V)
*/
float PHM_Get_VDD_Voltage(void)
{
uint32_t adc_vrefint_value = 0;
float vdd_voltage = 0.0f;
// 切换到VREFINT通道并启动转换
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
HAL_ADC_GetValue(&hadc1); // 跳过第一个通道(温度)
adc_vrefint_value = HAL_ADC_GetValue(&hadc1); // 读取VREFINT值
// VREFINT校准值(从芯片内部读取)
uint16_t vrefint_cal = *(__IO uint16_t *)(0x1FFF75AA);
// VDD计算公式:VDD = 3.3f * (VREFINT_CAL / ADC_VREFINT_VALUE)
vdd_voltage = 3.3f * ((float)vrefint_cal / (float)adc_vrefint_value);
HAL_ADC_Stop(&hadc1);
return vdd_voltage;
}
/**
* @brief 读取Flash写入次数
* @retval 写入次数
*/
uint32_t PHM_Get_Flash_Write_Count(void)
{
uint32_t write_count = 0;
// 从指定Flash地址读取计数
write_count = *(__IO uint32_t *)(FLASH_DATA_ADDR);
// 首次读取时初始化计数
if (write_count == 0xFFFFFFFF)
{
write_count = 0;
PHM_Increment_Flash_Write_Count();
}
return write_count;
}
/**
* @brief 增加Flash写入次数
*/
void PHM_Increment_Flash_Write_Count(void)
{
uint32_t write_count = PHM_Get_Flash_Write_Count() + 1;
FLASH_EraseInitTypeDef erase_init = {0};
uint32_t page_error = 0;
// 解锁Flash
HAL_FLASH_Unlock();
// 擦除Flash页
erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
erase_init.Page = (FLASH_DATA_ADDR - FLASH_BASE) / FLASH_PAGE_SIZE;
erase_init.NbPages = 1;
if (HAL_FLASHEx_Erase(&erase_init, &page_error) != HAL_OK)
{
Error_Handler();
}
// 写入新的计数
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_DATA_ADDR, write_count);
// 锁定Flash
HAL_FLASH_Lock();
}
/**
* @brief 增加异常复位次数
*/
void PHM_Increment_Reset_Count(void)
{
uint32_t reset_count = phm_data.reset_count + 1;
FLASH_EraseInitTypeDef erase_init = {0};
uint32_t page_error = 0;
HAL_FLASH_Unlock();
erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
erase_init.Page = (FLASH_DATA_ADDR + 4) / FLASH_PAGE_SIZE;
erase_init.NbPages = 1;
HAL_FLASHEx_Erase(&erase_init, &page_error);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_DATA_ADDR + 4, reset_count);
HAL_FLASH_Lock();
phm_data.reset_count = reset_count;
}
/**
* @brief 采集所有参数
*/
void PHM_Collect_All_Parameters(void)
{
// 采集温度
phm_data.core_temperature = PHM_Get_Core_Temperature();
// 采集电压
phm_data.vdd_voltage = PHM_Get_VDD_Voltage();
// 读取Flash计数
phm_data.flash_write_count = PHM_Get_Flash_Write_Count();
// 更新运行时间
phm_data.system_run_time++;
// 打印调试信息(可选)
HAL_Delay(10);
}
/**
* @brief 检查健康状态
*/
void PHM_Check_Health_Status(void)
{
phm_data.overall_status = PHM_STATUS_NORMAL;
// 温度判断
if (phm_data.core_temperature >= TEMP_ERROR_THRESHOLD)
{
phm_data.overall_status = PHM_STATUS_ERROR;
}
else if (phm_data.core_temperature >= TEMP_WARNING_THRESHOLD)
{
phm_data.overall_status = PHM_STATUS_WARNING;
}
// 电压判断
if (phm_data.vdd_voltage < VDD_WARNING_LOW_THRESHOLD || phm_data.vdd_voltage > VDD_WARNING_HIGH_THRESHOLD)
{
phm_data.overall_status = PHM_STATUS_WARNING;
}
// Flash计数判断
if (phm_data.flash_write_count >= FLASH_CYCLE_WARNING)
{
phm_data.overall_status = PHM_STATUS_WARNING;
}
// 复位次数判断
if (phm_data.reset_count >= RESET_ERROR_THRESHOLD)
{
phm_data.overall_status = PHM_STATUS_ERROR;
}
}
/**
* @brief 打印健康信息到串口
*/
void PHM_Print_Health_Info(void)
{
char info_buf[256] = {0};
// 拼接健康信息
sprintf(info_buf, "=== STM32G4 PHM Status ===\r\n");
sprintf(info_buf + strlen(info_buf), "System Run Time: %d s\r\n", phm_data.system_run_time);
sprintf(info_buf + strlen(info_buf), "Core Temperature: %.2f ℃\r\n", phm_data.core_temperature);
sprintf(info_buf + strlen(info_buf), "VDD Voltage: %.2f V\r\n", phm_data.vdd_voltage);
sprintf(info_buf + strlen(info_buf), "Flash Write Count: %d\r\n", phm_data.flash_write_count);
sprintf(info_buf + strlen(info_buf), "Reset Count: %d\r\n", phm_data.reset_count);
// 状态描述
switch (phm_data.overall_status)
{
case PHM_STATUS_NORMAL:
sprintf(info_buf + strlen(info_buf), "Overall Status: NORMAL\r\n");
break;
case PHM_STATUS_WARNING:
sprintf(info_buf + strlen(info_buf), "Overall Status: WARNING (Early Alert)\r\n");
break;
case PHM_STATUS_ERROR:
sprintf(info_buf + strlen(info_buf), "Overall Status: ERROR (Fault Detected)\r\n");
break;
default:
break;
}
sprintf(info_buf + strlen(info_buf), "==========================\r\n\r\n");
// 串口输出
HAL_UART_Transmit(&huart2, (uint8_t *)info_buf, strlen(info_buf), 1000);
}
/**
* @brief 保存历史数据到Flash
*/
void PHM_Save_History_Data(void)
{
// 简化实现:仅保存最新状态(可扩展为历史日志)
FLASH_EraseInitTypeDef erase_init = {0};
uint32_t page_error = 0;
HAL_FLASH_Unlock();
erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
erase_init.Page = (FLASH_DATA_ADDR + 8) / FLASH_PAGE_SIZE;
erase_init.NbPages = 1;
HAL_FLASHEx_Erase(&erase_init, &page_error);
// 保存温度和电压
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, FLASH_DATA_ADDR + 8, (uint16_t)(phm_data.core_temperature * 100));
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, FLASH_DATA_ADDR + 10, (uint16_t)(phm_data.vdd_voltage * 100));
HAL_FLASH_Lock();
}
/**
* @brief PHM监控模块初始化
*/
void PHM_Monitor_Init(void)
{
// 初始化ADC(温度/电压采集)
MX_ADC1_Init();
// 初始化定时器(1秒采集周期)
MX_TIM6_Init();
// 初始化Flash计数
phm_data.flash_write_count = PHM_Get_Flash_Write_Count();
// 读取复位次数
phm_data.reset_count = *(__IO uint32_t *)(FLASH_DATA_ADDR + 4);
if (phm_data.reset_count == 0xFFFFFFFF)
{
phm_data.reset_count = 0;
PHM_Increment_Reset_Count();
}
// 串口打印初始化完成信息
char init_info[] = "PHM Monitor Initialized Successfully!\r\n";
HAL_UART_Transmit(&huart2, (uint8_t *)init_info, strlen(init_info), 1000);
}
/**
* @brief 定时器6中断服务函数(1秒触发一次参数采集)
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM6)
{
// 采集参数
PHM_Collect_All_Parameters();
// 检查健康状态
PHM_Check_Health_Status();
// 打印信息
PHM_Print_Health_Info();
// 保存数据
PHM_Save_History_Data();
}
}
/**
* @brief 错误处理函数
*/
void Error_Handler(void)
{
// 点亮LED(可选)+ 串口输出错误信息
char error_info[] = "PHM Monitor Error Occurred!\r\n";
HAL_UART_Transmit(&huart2, (uint8_t *)error_info, strlen(error_info), 1000);
while(1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // Nucleo板LED引脚
HAL_Delay(500);
}
}
4.4 主函数实现(main.c)
文件名:main.c
c
#include "main.h"
#include "phm_monitor.h"
UART_HandleTypeDef huart2;
/**
* @brief 主函数
* @retval int
*/
int main(void)
{
// 1. 初始化HAL库
HAL_Init();
// 2. 配置系统时钟(84MHz)
SystemClock_Config();
// 3. 初始化GPIO(LED、串口等)
MX_GPIO_Init();
// 4. 初始化串口(USART2,用于输出监控信息)
MX_USART2_UART_Init();
// 5. 初始化PHM监控模块
PHM_Monitor_Init();
// 6. 主循环(空循环,所有逻辑在定时器中断中执行)
while (1)
{
// 可添加其他业务逻辑
HAL_Delay(100);
}
}
/**
* @brief 系统时钟配置函数
* @note STM32G431RBT6 - 84MHz
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 配置电源电压缩放
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
// 配置HSE振荡器
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 42;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
// 配置系统时钟
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief USART2初始化(串口输出)
*/
void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO初始化(LED等)
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 启用GPIO时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
// 配置LED引脚(Nucleo板PA5)
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 默认关闭LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
五、代码烧录与测试步骤
5.1 代码烧录
- 打开STM32CubeIDE,导入上述代码工程
- 连接STM32G4 Nucleo开发板到电脑USB口
- 点击IDE右上角
Run->Debug Configurations - 选择
STM32 Debugging,点击New创建新配置 - 配置
Target Configuration为STM32G431RBTx,调试器选择ST-LINK - 点击
Debug开始烧录代码,烧录完成后自动进入调试模式
5.2 测试步骤
- 打开串口工具SSCOM5.13,选择对应串口(设备管理器查看COM口)
- 配置串口参数:波特率115200、8N1、无流控,点击
打开串口 - 复位开发板(按Nucleo板上的RESET按钮)
- 串口终端会输出初始化信息,随后每秒输出一次健康状态数据
- 测试验证:
- 用手触摸芯片表面,观察温度值上升,超过60℃时触发预警
- 调整供电电压(可选),观察电压预警逻辑
- 多次复位开发板,观察复位次数增加,超过5次触发故障
六、功能扩展建议
- 数据存储扩展:增加Flash历史日志存储,保存最近100条健康数据
- 无线传输:添加ESP8266/ESP32模块,将健康数据上传到云端
- 阈值动态调整:通过串口指令远程修改预警阈值
- 多参数扩展:增加GPIO状态、外设通信状态等监控项
- LCD显示:外接LCD屏幕,本地可视化显示健康状态
七、常见问题与解决方法
- 串口无输出 :
- 检查串口COM口是否正确
- 确认串口参数配置为115200 8N1
- 检查USART2引脚映射(Nucleo板PA2/PA3)
- 温度值异常 :
- 确认ADC初始化中启用了温度传感器
- 检查采样时间是否足够(建议≥640个ADC周期)
- Flash写入失败 :
- 确认Flash地址未被程序占用
- 检查Flash解锁/锁定流程是否正确
总结
- 本教程基于STM32G4实现了故障预测与健康管理的核心功能,通过采集芯片温度、电压、Flash寿命、复位次数等参数,结合阈值判断实现早期预警,代码可直接落地使用。
- 核心实现流程包括:系统初始化→定时参数采集→健康状态判断→预警输出→数据存储,所有步骤均提供了零基础适配的详细代码和操作指南。
- 代码采用模块化设计,可通过扩展Flash日志、无线传输、LCD显示等功能,满足不同场景的PHM需求。