在 STM32 串口通信开发中,不定长数据接收是高频需求。传统方案(定时器计时、IDLE 中断)存在占用资源多、超时配置不灵活等问题。本文基于 ST 官方 LAT1315 应用笔记,详解 “串口 DMA + 接收超时中断(RTO)” 的实现方法,该方案无需额外定时器、超时时间可灵活配置,适用于 STM32 全系列支持 RTO 特性的芯片。
1. 核心原理:RTO 接收超时中断的工作逻辑
1.1 技术核心
接收超时中断(Receiver Timeout, RTO)是部分 STM32 UART/USART 外设的硬件特性,通过配置超时时间,当串口超过设定时间未接收新数据时,自动触发中断,判定为一帧数据接收完成。
1.2 关键机制
- 配置入口:通过 USART_RTOR 寄存器的
RTOEN位使能功能,RTO位域配置超时时间(单位:单个数据位的传输时间,即波特率倒数); - 计时起始点:随停止位配置不同变化
- 停止位为 00/11:从停止位末尾开始计时;
- 停止位为 10:从第二个停止位末尾开始计时;
- 停止位为 01:从停止位起始开始计时;
- 中断触发:计时超过
RTO设定值,且使能RTOIE位时,触发错误中断,通过回调函数处理数据。
1.3 适用前提
- 芯片与外设支持:需确认目标 STM32 芯片及所用 UART/USART 是否支持 RTO 特性(参考对应芯片参考手册);
- 软件依赖:STM32Cube HAL 库已提供 RTO 相关 API,直接调用即可,无需底层寄存器操作。
2. 实操步骤:从配置到代码实现(以 STM32U575 为例)
以 STM32U575ZIT6 为目标芯片,实现 115200 波特率下的不定长数据接收,步骤分 “STM32CubeMX 配置” 和 “代码编写” 两部分。
2.1 STM32CubeMX 配置
(1)基础参数配置
- 系统时钟:配置为 160MHz;
- UART 配置:USART1,异步模式(Asynchronous),引脚 PA9(TX)、PA10(RX);
- 串口参数:波特率 115200 bits/s,数据位 8bit,校验位 None,停止位 1bit;
- 中断使能:启用 USART1 全局中断,配置 NVIC 优先级。
(2)DMA 配置
- DMA 通道:USART1_RX 关联 GPDMA1 Channel 0;
- 传输参数:方向 “Peripheral To Memory”,源地址增量禁用,目的地址增量启用,数据宽度均为 Byte;
- 模式配置:正常模式(Circular Mode 禁用),优先级 Low,禁用触发与数据处理功能。
2.2 代码编写与核心配置
(1)宏定义与全局变量
#define MAX_UART_RCV_LEN 10 // 最大接收数据长度
uint8_t Uart_RcvBuf[MAX_UART_RCV_LEN]; // 接收缓冲区
uint16_t Uart_RcvLen; // 实际接收数据长度
(2)初始化配置(main 函数 USER CODE BEGIN 2 段)
// 1. 配置RTO超时时间:10ms(计算逻辑:波特率/100 = 115200/100 = 1152)
HAL_UART_ReceiverTimeout_Config(&huart1, huart1.Init.BaudRate / 100);
// 2. 使能接收超时功能
HAL_UART_EnableReceiverTimeout(&huart1);
// 3. 启动DMA接收(循环接收,缓冲区满则覆盖)
HAL_UART_Receive_DMA(&huart1, Uart_RcvBuf, MAX_UART_RCV_LEN);
(3)中断回调函数处理
RTO 中断触发后,会进入
HAL_UART_ErrorCallback回调函数,需在此解析错误类型并处理数据:void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
if (huart == &huart1) { // 确认是USART1触发中断
// 检查是否为DMA模式且触发RTO错误
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR) &&
(huart->ErrorCode & HAL_UART_ERROR_RTO) == HAL_UART_ERROR_RTO) {
// 计算实际接收长度:最大长度 - DMA未传输字节数
uint16_t nb_remaining_rx_data = (uint16_t)__HAL_DMA_GET_COUNTER(huart->hdmarx);
Uart_RcvLen = MAX_UART_RCV_LEN - nb_remaining_rx_data;
// 此处添加数据处理逻辑(如解析数据、发送响应等)
// 示例:打印接收数据(需自行实现串口打印功能)
printf("接收数据长度:%d,数据内容:", Uart_RcvLen);
for (uint16_t i = 0; i < Uart_RcvLen; i++) {
printf("%02X ", Uart_RcvBuf[i]);
}
printf("rn");
// 清除错误标志,重启DMA接收
__HAL_UART_CLEAR_ERRORCODE(huart);
HAL_UART_Receive_DMA(&huart1, Uart_RcvBuf, MAX_UART_RCV_LEN);
}
}
}
3. 核心优势:与传统方案的对比
4. 注意事项与避坑指南
- 特性兼容性:务必先查阅芯片参考手册,确认所用 UART/USART 是否支持 RTO(如 STM32U5、STM32H7 系列大部分支持,部分低端系列可能不支持);
- 超时时间计算:
HAL_UART_ReceiverTimeout_Config的第二个参数单位为 “数据位传输时间”,需根据波特率换算(如 115200 波特率下,10ms 对应 115200/100=1152); - DMA 计数器使用:
__HAL_DMA_GET_COUNTER用于获取 DMA 未传输的字节数,需注意数据类型转换(避免溢出); - 错误标志清除:处理完 RTO 中断后,需调用
__HAL_UART_CLEAR_ERRORCODE清除错误标志,否则无法重启 DMA 接收; - 缓冲区大小:
MAX_UART_RCV_LEN需根据实际最大接收数据长度配置,避免缓冲区溢出。
阅读全文
4187