资讯动态

【电路笔记 STM32】Cortex-M7 UART 中断模式(串口接收中断+串口空闲中断)

发布时间:2026/10/13 6:59:49 来源:尧图企业网站定制
文章目录轮询模式 (Polling)中断模式 (Interrupt)CUBEMX 优先级配置中断实现数据包的接收串口接收中断串口空闲中断核心思路代码实现HAL库定义全局变量串口初始化使能RXNE IDLE中断中断服务函数主循环处理CG轮询模式 (Polling)轮询模式最大的优点是实现极其简单、执行路径完全可控不需要配置 NVIC、中断优先级和 ISR调试时单步跟踪也直观适合在串口功能验证或简单裸机场景下快速跑通。但它的缺点也很明显HAL_UART_Receive()在超时时间内会阻塞主循环导致 CPU 无法及时处理其他任务实时性差且 CPU 占用高波特率越高或数据越密集越容易因为主循环被卡住而漏收数据甚至触发 ORE 溢出错误。因此它只适合低波特率、单任务或对实时性要求不高的场景正式工程里如果后续还要跑多任务或处理高频通信建议尽早切换其他模式。/* main.c */#includemain.h#includeusart.h/* USER CODE BEGIN PV */volatileuint8_tusart3_rx_buffer[USART3_RX_BUFFER_SIZE];volatileuint16_tusart3_rx_count0;volatileuint8_tusart3_rx_flag0;/* USER CODE END PV */intmain(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 */HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART3_UART_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 *//* ---- 轮询接收 USART3 数据 ---- */uint8_trx_byte0;HAL_StatusTypeDef statusHAL_UART_Receive(huart3,rx_byte,1,100);if(statusHAL_OK){/* 收到一个字节 */if(rx_byte\r||rx_byte\n){/* 一帧结束 */usart3_rx_flag1;}else{if(usart3_rx_countUSART3_RX_BUFFER_SIZE){usart3_rx_buffer[usart3_rx_count]rx_byte;}}}/* HAL_TIMEOUT 表示没有新数据继续循环即可 *//* ---- 处理一帧数据 ---- */if(usart3_rx_flag){usart3_rx_flag0;/* 这里解析 usart3_rx_buffer长度是 usart3_rx_count *//* 例如回显、协议解析等 */usart3_rx_count0;/* 清空计数 */}/* 其他任务放在这里 *//* USER CODE END 3 */}}HAL_UART_Receive的超时时间这里用100毫秒可以根据波特率调整。波特率越高、数据越密集超时可以设短一点减少主循环阻塞。中断模式 (Interrupt)STM32 的中断优先级由内核里的NVIC管理本质是把每个中断的优先级拆成两部分抢占优先级和子优先级。抢占优先级数值越小优先级越高决定能不能打断正在执行的中断。抢占优先级高的中断可以抢占抢占优先级低的中断形成中断嵌套。子优先级也叫响应优先级数值越小越优先。但它只在抢占优先级相同时起作用用来决定多个中断同时挂起时谁先执行抢占优先级相同时子优先级高的中断不能打断正在执行的同抢占优先级中断。如果抢占优先级和子优先级都相同则按硬件固定的IRQ 编号决定编号小的优先响应。中断嵌套CPU 正在执行一个低抢占优先级的中断服务函数时来了一个抢占优先级更高的中断CPU 暂停当前中断先去执行高优先级中断执行完再回来继续原来的中断。在 STM32 里嵌套只和 抢占优先级 有关和 子优先级 无关。STM32 使用优先级寄存器的高 4 位来配置优先级这 4 位可以按 5 种分组方式划分分组抢占优先级位数子优先级位数Group 004Group 113Group 222Group 331Group 440CUBEMX 优先级配置HAL 库中配置流程通常是HAL_NVIC_SetPriority(USART3_IRQn,1,0);HAL_NVIC_EnableIRQ(USART3_IRQn);“4 bits for pre-emption priotiry”:即 4 bits 全部用于抢占优先级相当于 Group 4 / 无子优先级划分。实际工程中比较推荐的做法是分组只设置一次不要中途修改抢占优先级留给真正紧急的中断比如保护、高速控制、紧急故障通信类中断如 USART、SPI、I2C 一般放在中低优先级SysTick 通常放在较低优先级避免它频繁打断业务中断。[STM32 HAL库][中断]中断优先级最佳教程没有之一~中断实现数据包的接收串口接收中断串口空闲中断核心思路RXNE中断每收到1个字节触发将数据存入缓冲区并计数IDLE中断总线空闲超过1个字符时间后触发标志一帧数据接收完毕当前纯中断方案适合波特率 ≤ 115200、帧长较短的场景调试简单、逻辑清晰。CPU占用较高每字节都进中断921600bps下约每11μs一次中断不适合持续大数据流粘帧风险如果两帧数据间隔小于1个字符时间IDLE无法区分会粘成一帧代码实现HAL库CubeMX 配置NVIC 配置使能 USARTx 全局中断抢占优先级建议设高如1避免被其他中断阻塞导致ORE错误定义全局变量/* 接收缓冲区与状态变量 */#defineUSART3_RX_BUFFER_SIZE512volatileuint8_tusart3_rx_buffer[USART3_RX_BUFFER_SIZE];// 接收缓冲区volatileuint16_tusart3_rx_count0;// 当前已接收字节数volatileuint8_tusart3_rx_flag0;// 一帧接收完成标志串口初始化使能RXNE IDLE中断在生成的MX_USART3_UART_Init()函数的/* USER CODE BEGIN USART3_Init 2 */区域中添加/* USER CODE BEGIN USART3_Init 2 */// 使能串口3的接收中断RXNE__HAL_UART_ENABLE_IT(huart3,UART_IT_RXNE);// 使能串口3的空闲中断IDLE__HAL_UART_ENABLE_IT(huart3,UART_IT_IDLE);/* USER CODE END USART3_Init 2 */整体代码如下void MX_USART3_UART_Init(void){/*USERCODE BEGIN USART3_Init0*/ /*USERCODE END USART3_Init0*/ /*USERCODE BEGIN USART3_Init1*/ /*USERCODE END USART3_Init1*/ huart3.InstanceUSART3;huart3.Init.BaudRate9600;huart3.Init.WordLengthUART_WORDLENGTH_8B;huart3.Init.StopBitsUART_STOPBITS_1;huart3.Init.ParityUART_PARITY_NONE;huart3.Init.ModeUART_MODE_TX_RX;huart3.Init.HwFlowCtlUART_HWCONTROL_NONE;huart3.Init.OverSamplingUART_OVERSAMPLING_16;huart3.Init.OneBitSamplingUART_ONE_BIT_SAMPLE_DISABLE;huart3.Init.ClockPrescalerUART_PRESCALER_DIV1;huart3.AdvancedInit.AdvFeatureInitUART_ADVFEATURE_NO_INIT;if(HAL_UART_Init(huart3)!HAL_OK){Error_Handler();}if(HAL_UARTEx_SetTxFifoThreshold(huart3, UART_TXFIFO_THRESHOLD_1_8)!HAL_OK){Error_Handler();}if(HAL_UARTEx_SetRxFifoThreshold(huart3, UART_RXFIFO_THRESHOLD_1_8)!HAL_OK){Error_Handler();}if(HAL_UARTEx_DisableFifoMode(huart3)!HAL_OK){Error_Handler();}/*USERCODE BEGIN USART3_Init2*/ // 使能串口3的接收中断RXNE __HAL_UART_ENABLE_IT(huart3, UART_IT_RXNE);// 使能串口3的空闲中断IDLE __HAL_UART_ENABLE_IT(huart3, UART_IT_IDLE);/*USERCODE END USART3_Init2*/}项目当前状态建议FIFO 模式已禁用DisableFifoMode开启可用HAL_UARTEx_EnableFifoMode并设置合适的 FIFO 阈值如 8/16可显著减少中断次数(8 个字节才触发一次中断)波特率9600ORE 处理已在 ISR 中添加ORE是Overrun Error溢出错误必须保留否则连续接收时一旦溢出会导致中断卡死中断服务函数找到USART3_IRQHandler修改为voidUSART3_IRQHandler(void){uint8_tres;/* 接收中断RXNE */if(__HAL_UART_GET_FLAG(huart3,UART_FLAG_RXNE)!RESET){// 读取数据寄存器读RDR会自动清除RXNE标志res(uint8_t)(huart3.Instance-RDR0xFF);if(usart3_rx_countUSART3_RX_BUFFER_SIZE){usart3_rx_buffer[usart3_rx_count]res;}else{// 缓冲区溢出保护重置计数防止数组越界usart3_rx_count0;}}/* 空闲中断IDLE */if(__HAL_UART_GET_FLAG(huart3,UART_FLAG_IDLE)!RESET){// 清除IDLE标志H7系列推荐写法__HAL_UART_CLEAR_IDLEFLAG(huart3);// 一帧数据接收完成if(usart3_rx_count0){usart3_rx_flag1;// 通知主循环处理}}/* 错误处理防止ORE导致卡死 */if(__HAL_UART_GET_FLAG(huart3,UART_FLAG_ORE)!RESET){__HAL_UART_CLEAR_FLAG(huart3,UART_FLAG_ORE);}}注意H7系列清除IDLE标志推荐使用__HAL_UART_CLEAR_IDLEFLAG()它内部已正确处理SR/DR读取序列。在 STM32F1/F4 这类老系列里USART 没有 ICR 寄存器IDLE 标志的清除方式是硬件规定的软件序列老版本F1/F4中常用USART1-SR; USART1-DR;。主循环处理/* main.c 的 while(1) 中 */while(1){if(usart3_rx_flag1){usart3_rx_flag0;// 清除标志/* 此处处理接收到的数据 * 有效数据范围usart3_rx_buffer[0] ~ usart3_rx_buffer[usart3_rx_count - 1] * 数据长度usart3_rx_count */// 示例将接收到的数据原样回发用于调试验证HAL_UART_Transmit(huart3,(uint8_t*)usart3_rx_buffer,usart3_rx_count,1000);// 重置计数器准备接收下一帧usart3_rx_count0;}// 其他任务...}CGSTM32入门——串口接收中断串口空闲中断实现数据包的接收编程【电路笔记 STM32】stm32f103 实现HAL_UART_Transmit_DMA 普通模式/连续模式的 UART DMA 收发串口中断里如果只自己读 RDRUART 的接收数据寄存器却没有处理 ORE overrun 错误上一个字节还没被软件读走新的字节又来了也没有在清除 ORE 后再读一次 RDR就可能丢字节或读到错误字节。开 RTS/CTS 需要硬件支持MCU 和上位机都要接 RTS/CTS 引脚并且 CubeMX 里 USART3 的硬件流控要配置成RTS/CTS。如果只有 TX/RX/GND 三根线就没法用硬件流控只能靠协议层控制发送节奏。RTSRequest To Send请求发送。CTSClear To Send允许发送。如果上位机是连续流帧间几乎没有空闲IDLE 可能不会及时触发甚至可能把多帧拼成一帧这时要么在上层按帧头/长度拆帧要么考虑开启 RTS/CTS。硬件 IDLE 空闲中断时长不可配置固定约为 1 个字符时间

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑