2026/1/10 1:50:08
网站建设
项目流程
网站使用字体,建立一个网站大约要多少钱,母婴电子商务网站建设,包头seo目录
一、监护核心目标
二、通用监护基础设计
基础框架代码示例
三、分模块监护实现
1. 串口#xff08;UART#xff09;监护
关键监护策略
串口监护代码示例#xff08;以 UART1 为例#xff09;
2. 定时器监护
关键监护策略
定时器监护代码示例#xff08;以 …目录一、监护核心目标二、通用监护基础设计基础框架代码示例三、分模块监护实现1. 串口UART监护关键监护策略串口监护代码示例以 UART1 为例2. 定时器监护关键监护策略定时器监护代码示例以 TIM2 为例定时 1ms 触发任务3. ADC 监护关键监护策略ADC 监护代码示例以 ADC1 为例单次转换模式四、高效监护优化原则五、总结在 MCU 裸奔无操作系统程序中对串口、定时器及 ADC 进行安全监护故障检测、容错、恢复和高效监护低资源占用、不影响主功能是保障系统稳定性的关键。以下从监护目标、核心监护策略、分模块实现和优化原则四个维度给出具体的设计思路和代码示例以 STM32 为例适配主流 ARM Cortex-M 内核 MCU。一、监护核心目标故障检测快速识别模块异常如串口卡死、定时器溢出、ADC 数据越界容错处理对轻微异常进行自动恢复避免系统崩溃资源高效监护逻辑占用极少 CPU、内存资源不影响主程序实时性可追溯性记录故障信息如异常类型、发生时间便于问题定位。二、通用监护基础设计裸奔程序中需先搭建基础监护框架为各模块提供统一的故障处理和计时能力系统心跳定时器使用一个高优先级定时器如 SysTick 或 TIM1作为全局时间基准提供 ms 级计时用于超时检测、故障计时故障状态寄存器定义全局结构体记录各模块故障类型、次数、时间戳看门狗WDT/IWDG作为最后一道防线若监护逻辑失效看门狗复位系统硬件级保障临界区保护对故障状态的读写操作加关中断保护避免数据竞争。基础框架代码示例#include stm32f10x.h // 故障类型枚举 typedef enum { FAULT_UART_TX_TIMEOUT, // 串口发送超时 FAULT_UART_RX_OVERRUN, // 串口接收溢出 FAULT_TIMER_OVERFLOW, // 定时器异常溢出 FAULT_ADC_VALUE_INVALID,// ADC数据越界 FAULT_ADC_CONV_TIMEOUT // ADC转换超时 } FaultType; // 模块枚举 typedef enum { MODULE_UART1, MODULE_TIM2, MODULE_ADC1, MODULE_MAX } ModuleType; // 故障状态结构体 typedef struct { uint8_t fault_flag; // 故障标志bit位对应FaultType uint16_t fault_count; // 故障次数 uint32_t fault_timestamp;// 故障时间戳ms } ModuleFaultStatus; // 全局故障状态表 static ModuleFaultStatus fault_table[MODULE_MAX] {0}; // 系统心跳时间戳ms static volatile uint32_t sys_tick_ms 0; // SysTick中断1ms一次系统心跳 void SysTick_Handler(void) { sys_tick_ms; } // 初始化系统心跳1ms void SysTick_Init(uint32_t sysclk_mhz) { SysTick_Config(sysclk_mhz * 1000); // 系统时钟sysclk_mhz MHz1ms中断一次 } // 记录故障临界区保护 void fault_record(ModuleType module, FaultType fault) { __disable_irq(); // 关中断保护 fault_table[module].fault_flag | (1 fault); fault_table[module].fault_count; fault_table[module].fault_timestamp sys_tick_ms; __enable_irq(); } // 清除故障 void fault_clear(ModuleType module, FaultType fault) { __disable_irq(); fault_table[module].fault_flag ~(1 fault); __enable_irq(); } // 获取故障状态 ModuleFaultStatus fault_get_status(ModuleType module) { return fault_table[module]; }三、分模块监护实现1. 串口UART监护串口常见异常发送超时、接收溢出 / 帧错误、总线卡死需结合硬件中断和软件超时检测实现监护。关键监护策略接收异常利用 UART 的帧错误FE、** 溢出错误ORE** 中断检测硬件接收异常发送超时为串口发送函数设置软件超时如 10ms若发送未完成则判定为发送卡死数据合法性对接收的关键数据进行范围 / 校验和检查过滤无效数据自动恢复检测到异常后重新初始化 UART 并清除中断标志。串口监护代码示例以 UART1 为例#include stm32f10x_usart.h #define UART_TX_TIMEOUT_MS 10 // 发送超时时间 #define UART_RX_BUF_SIZE 64 uint8_t uart1_rx_buf[UART_RX_BUF_SIZE]; uint16_t uart1_rx_idx 0; // UART1中断服务函数处理接收和错误 void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_ORE) ! RESET) { // 溢出错误 USART_ClearITPendingBit(USART1, USART_IT_ORE); fault_record(MODULE_UART1, FAULT_UART_RX_OVERRUN); // 恢复清除接收缓冲区 uart1_rx_idx 0; } if (USART_GetITStatus(USART1, USART_IT_FE) ! RESET) { // 帧错误 USART_ClearITPendingBit(USART1, USART_IT_FE); fault_record(MODULE_UART1, FAULT_UART_RX_OVERRUN); } if (USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { // 正常接收 USART_ClearITPendingBit(USART1, USART_IT_RXNE); if (uart1_rx_idx UART_RX_BUF_SIZE) { uart1_rx_buf[uart1_rx_idx] USART_ReceiveData(USART1); } else { fault_record(MODULE_UART1, FAULT_UART_RX_OVERRUN); uart1_rx_idx 0; // 缓冲区满重置 } } } // 带超时的串口发送函数 uint8_t uart1_send(uint8_t *data, uint16_t len) { uint32_t start_ms sys_tick_ms; for (uint16_t i 0; i len; i) { // 等待发送寄存器为空同时检测超时 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET) { if ((sys_tick_ms - start_ms) UART_TX_TIMEOUT_MS) { fault_record(MODULE_UART1, FAULT_UART_TX_TIMEOUT); // 恢复重新初始化UART1 USART_DeInit(USART1); UART1_Init(); // 调用原有初始化函数 return 0; // 发送失败 } } USART_SendData(USART1, data[i]); } // 等待发送完成 while (USART_GetFlagStatus(USART1, USART_FLAG_TC) RESET) { if ((sys_tick_ms - start_ms) UART_TX_TIMEOUT_MS) { fault_record(MODULE_UART1, FAULT_UART_TX_TIMEOUT); USART_DeInit(USART1); UART1_Init(); return 0; } } fault_clear(MODULE_UART1, FAULT_UART_TX_TIMEOUT); // 清除超时故障 return 1; // 发送成功 } // UART1初始化含中断配置 void UART1_Init(uint32_t baudrate) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // TX:PA9 推挽输出 GPIO_InitStruct.GPIO_Pin GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStruct); // RX:PA10 浮空输入 GPIO_InitStruct.GPIO_Pin GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStruct); USART_InitStruct.USART_BaudRate baudrate; USART_InitStruct.USART_WordLength USART_WordLength_8b; USART_InitStruct.USART_StopBits USART_StopBits_1; USART_InitStruct.USART_Parity USART_Parity_No; USART_InitStruct.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, USART_InitStruct); // 使能接收和错误中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_ERR, ENABLE); NVIC_InitStruct.NVIC_IRQChannel USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority 0; NVIC_InitStruct.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStruct); USART_Cmd(USART1, ENABLE); }2. 定时器监护定时器常见异常定时溢出异常如预期的定时未触发、PWM 输出异常、计数器卡死需结合软件计时和硬件状态检测实现监护。关键监护策略定时任务超时检测为定时器触发的任务设置软件超时若任务未在预期时间内执行则判定异常计数器状态检测周期性检查定时器计数器值若长时间未变化则判定计数器卡死自动恢复检测到异常后重新初始化定时器并重启计数。定时器监护代码示例以 TIM2 为例定时 1ms 触发任务#include stm32f10x_tim.h #define TIM2_TASK_INTERVAL_MS 1 // TIM2定时周期 #define TIM2_TIMEOUT_MS 5 // 任务超时时间 volatile uint8_t tim2_task_flag 0; // 定时任务标志 uint32_t tim2_last_trigger_ms 0; // 上次触发时间戳 // TIM2中断服务函数1ms触发 void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); tim2_task_flag 1; // 设置任务标志 tim2_last_trigger_ms sys_tick_ms; // 更新时间戳 } } // TIM2初始化1ms定时 void TIM2_Init(uint32_t sysclk_mhz) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 定时1msPrescaler7200-1CounterModeUpPeriod10-172MHz时钟 TIM_TimeBaseStruct.TIM_Prescaler 7200 - 1; TIM_TimeBaseStruct.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseStruct.TIM_Period 10 - 1; TIM_TimeBaseStruct.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseStruct.TIM_RepetitionCounter 0; TIM_TimeBaseInit(TIM2, TIM_TimeBaseStruct); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 使能更新中断 NVIC_InitStruct.NVIC_IRQChannel TIM2_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority 2; NVIC_InitStruct.NVIC_IRQChannelSubPriority 0; NVIC_InitStruct.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStruct); TIM_Cmd(TIM2, ENABLE); // 启动定时器 } // 定时器监护任务在主循环中调用 void tim2_monitor(void) { // 检测定时任务是否超时 if (tim2_task_flag 0) { if ((sys_tick_ms - tim2_last_trigger_ms) TIM2_TIMEOUT_MS) { fault_record(MODULE_TIM2, FAULT_TIMER_OVERFLOW); // 恢复重新初始化TIM2 TIM_DeInit(TIM2); TIM2_Init(72); // 72MHz系统时钟 tim2_last_trigger_ms sys_tick_ms; } } else { fault_clear(MODULE_TIM2, FAULT_TIMER_OVERFLOW); // 清除故障 tim2_task_flag 0; // 清除任务标志 } // 检测计数器是否卡死可选 static uint16_t last_cnt 0; uint16_t curr_cnt TIM_GetCounter(TIM2); if (curr_cnt last_cnt TIM_GetFlagStatus(TIM2, TIM_FLAG_UPDATE) RESET) { fault_record(MODULE_TIM2, FAULT_TIMER_OVERFLOW); TIM_SetCounter(TIM2, 0); // 重置计数器 } last_cnt curr_cnt; } // 主循环中的定时任务处理 void main_loop(void) { while (1) { tim2_monitor(); // 执行定时器监护 if (tim2_task_flag) { // 处理TIM2定时任务如LED闪烁、数据采集 tim2_task_flag 0; } // 其他主任务... } }3. ADC 监护ADC 常见异常转换超时、数据越界、转换结果跳变过大、硬件校准失败需结合软件超时、数据滤波和合法性检查实现监护。关键监护策略转换超时检测为 ADC 转换设置软件超时若未在预期时间内完成则判定异常数据合法性检查对转换结果进行范围检查如电压应在 0~3.3V 之间过滤无效值数据稳定性检查使用滑动平均滤波若单次采样值与平均值偏差过大则判定异常自动恢复检测到异常后重新校准 ADC 并重启转换。ADC 监护代码示例以 ADC1 为例单次转换模式#include stm32f10x_adc.h #define ADC1_CONV_TIMEOUT_MS 5 // 转换超时时间 #define ADC1_VALID_MIN 0 // ADC有效值最小值 #define ADC1_VALID_MAX 4095 // ADC有效值最大值12位 #define ADC1_FILTER_WINDOW 5 // 滑动平均窗口大小 uint16_t adc1_filter_buf[ADC1_FILTER_WINDOW]; // 滤波缓冲区 uint8_t adc1_filter_idx 0; // 滤波缓冲区索引 uint16_t adc1_avg_val 0; // 平均值 // ADC1初始化单次转换通道0PA0 void ADC1_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; ADC_InitTypeDef ADC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADC时钟72/612MHz // PA0 模拟输入 GPIO_InitStruct.GPIO_Pin GPIO_Pin_0; GPIO_InitStruct.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, GPIO_InitStruct); ADC_InitStruct.ADC_Mode ADC_Mode_Independent; ADC_InitStruct.ADC_ScanConvMode DISABLE; // 单通道 ADC_InitStruct.ADC_ContinuousConvMode DISABLE; // 单次转换 ADC_InitStruct.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStruct.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStruct.ADC_NbrOfChannel 1; ADC_Init(ADC1, ADC_InitStruct); ADC_Cmd(ADC1, ENABLE); // 使能ADC1 ADC_ResetCalibration(ADC1); // 重置校准 while (ADC_GetResetCalibrationStatus(ADC1)); // 等待校准完成 ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); } // 带监护的ADC转换函数 uint16_t adc1_read(void) { uint32_t start_ms sys_tick_ms; uint16_t adc_val 0; // 启动转换 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 等待转换完成检测超时 while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) RESET) { if ((sys_tick_ms - start_ms) ADC1_CONV_TIMEOUT_MS) { fault_record(MODULE_ADC1, FAULT_ADC_CONV_TIMEOUT); // 恢复重新初始化ADC1 ADC_DeInit(ADC1); ADC1_Init(); return 0; } } adc_val ADC_GetConversionValue(ADC1); ADC_ClearFlag(ADC1, ADC_FLAG_EOC); // 数据合法性检查 if (adc_val ADC1_VALID_MIN || adc_val ADC1_VALID_MAX) { fault_record(MODULE_ADC1, FAULT_ADC_VALUE_INVALID); return adc1_avg_val; // 返回平均值容错 } // 滑动平均滤波 adc1_filter_buf[adc1_filter_idx] adc_val; if (adc1_filter_idx ADC1_FILTER_WINDOW) { adc1_filter_idx 0; } // 计算平均值 uint32_t sum 0; for (uint8_t i 0; i ADC1_FILTER_WINDOW; i) { sum adc1_filter_buf[i]; } adc1_avg_val sum / ADC1_FILTER_WINDOW; // 检测数据跳变可选如偏差超过20%则判定异常 if (abs(adc_val - adc1_avg_val) (adc1_avg_val * 0.2)) { fault_record(MODULE_ADC1, FAULT_ADC_VALUE_INVALID); return adc1_avg_val; } fault_clear(MODULE_ADC1, FAULT_ADC_CONV_TIMEOUT | FAULT_ADC_VALUE_INVALID); return adc1_avg_val; }四、高效监护优化原则轻量化检测监护逻辑尽量在中断或主循环中以 “短函数” 形式实现避免复杂计算分级处理轻微异常如单次 ADC 数据跳变仅记录不恢复严重异常如串口卡死才执行重新初始化批量检测将各模块的监护任务集中在主循环的 “监护阶段” 执行减少上下文切换硬件复用利用 MCU 的硬件特性如 UART 错误中断、ADC 校准实现被动检测减少软件轮询故障防抖对故障标志进行防抖处理如连续检测 3 次异常才判定为真故障避免误触发。五、总结MCU 裸奔程序中对串口、定时器和 ADC 的监护核心是 **“硬件中断检测 软件超时兜底 自动恢复 数据容错”**串口利用错误中断检测硬件异常软件超时防止发送卡死定时器通过时间戳检测定时任务超时检查计数器状态防止卡死ADC转换超时检测 数据范围 / 稳定性检查结合滤波实现容错。同时需通过临界区保护、轻量化逻辑和分级处理确保监护功能安全且高效不影响主程序的实时性和稳定性。