在 STM32 开发中,串口(UART)通信主要有 轮询模式、 中断模式 和 DMA(直接存储器访问)模式 三种方式。其中 中断模式 和 DMA 模式 适用于高效、非阻塞的串口通信。
1. 中断模式(Interrupt Mode)
中断模式(UART Interrupt Mode) 依赖 UART 接收/发送完成 时触发 中断 来处理数据,适用于 低速串口通信或短数据包传输。
中断模式的工作原理
- 发送:调用
HAL_UART_Transmit_IT()
,数据传输完成时触发HAL_UART_TxCpltCallback()
回调函数。 - 接收:调用
HAL_UART_Receive_IT()
,数据接收完成时触发HAL_UART_RxCpltCallback()
回调函数。 - CPU 只在数据传输完成时才执行回调函数,减少 CPU 资源占用。
示例代码
① 开启 UART 中断接收
uint8_t rxData[10]; // 接收缓冲区
// 初始化 UART 接收中断(一次接收 1 字节)
HAL_UART_Receive_IT(&huart1, rxData, 1);
② 处理 UART 接收中断
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) // 判断是哪个串口
{
HAL_UART_Transmit_IT(&huart1, rxData, 1); // 回显接收的数据
HAL_UART_Receive_IT(&huart1, rxData, 1); // 继续接收
}
}
③ 处理 UART 发送中断
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
// 发送完成后可以执行其他操作
}
}
中断模式的优点
✅ 非阻塞:CPU 只在需要时处理数据,空闲时可以执行其他任务。
✅ 适用于短数据包通信(比如命令解析、按键输入等)。
✅ 比轮询模式更节省 CPU 资源。
中断模式的缺点
❌ 需要占用 CPU 处理中断,当数据流量较大时,中断频繁触发会影响系统性能。
❌ 不能高效处理大数据量传输,会影响 CPU 响应时间。
2. DMA 模式(Direct Memory Access Mode)
DMA(直接存储器访问)模式 让 UART 直接通过 DMA 控制器读写内存,无需 CPU 介入,适用于 大数据量、高速串口通信(如日志输出、数据采集等)。
DMA 模式的工作原理
- 发送数据:调用
HAL_UART_Transmit_DMA()
,DMA 直接从内存读取数据发送到 UART,不占用 CPU。 - 接收数据:调用
HAL_UART_Receive_DMA()
,DMA 直接将 UART 接收到的数据存入内存,完成后触发HAL_UART_RxCpltCallback()
回调。
示例代码
① 配置 UART 使用 DMA
uint8_t rxBuffer[100]; // DMA 接收缓冲区
// 开启 DMA 接收(一次性接收 100 字节数据)
HAL_UART_Receive_DMA(&huart1, rxBuffer, sizeof(rxBuffer));
② 处理 DMA 传输完成回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
// 数据接收完成,可以处理 rxBuffer 里的数据
HAL_UART_Transmit_DMA(&huart1, rxBuffer, sizeof(rxBuffer)); // 发送接收到的数据
}
}
DMA 模式的优点
✅ 完全非阻塞:DMA 负责数据搬运,CPU 只在数据完成时处理,不受干扰。
✅ 适用于大数据量、高速通信(如 GPS、WiFi、摄像头数据传输)。
✅ CPU 负载低,系统可以执行其他任务(如 RTOS 多任务)。
DMA 模式的缺点
❌ 需要额外配置 DMA 控制器,比中断模式复杂。
❌ 适合连续大数据传输,不适用于短数据命令交互(比如 AT
命令)。
❌ 可能需要管理环形缓冲区(Ring Buffer),避免数据丢失。
3. 中断模式 vs. DMA 模式对比
在 STM32 串口通信中,DMA 模式 和 中断模式 都依赖 中断机制,但它们的 中断触发方式、频率、CPU 负载 有显著区别。以下是两者的详细对比:
3.1. 中断模式的中断触发
触发条件:
- 发送完成中断(Tx Complete Interrupt):每次发送完 1 次完整的数据 后触发。
- 接收完成中断(Rx Complete Interrupt):每次接收到 指定数量的数据 后触发。
中断触发频率:
- 发送数据:每次调用
HAL_UART_Transmit_IT()
都会触发 1 次发送完成中断。 - 接收数据:每次调用
HAL_UART_Receive_IT()
都会触发 1 次接收完成中断。 - 如果接收数据是逐字节的,那么每收到 1 个字节 就会触发一次中断,导致中断频率高,影响 CPU 性能。
示例:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
HAL_UART_Transmit_IT(&huart1, rxData, 1); // 发送回显数据
HAL_UART_Receive_IT(&huart1, rxData, 1); // 继续接收
}
}
问题:如果接收的数据流量大,每个字节都触发一次
HAL_UART_RxCpltCallback()
,会导致 CPU 频繁处理中断,降低系统响应能力。
3.2. DMA 模式的中断触发
触发条件:
- 发送完成中断(Tx DMA Complete Interrupt):整个 DMA 传输 全部数据 结束后触发。
- 接收完成中断(Rx DMA Complete Interrupt):整个 DMA 缓存区接收满 或 指定的字节数到达 时触发。
中断触发频率:
- 由于 DMA 直接传输整个数据块,相比中断模式 减少了大量的中断触发。
- 例如,使用 DMA 方式接收 100 字节数据,仅在100 字节全部接收完成时触发一次中断。
- 相比中断模式,DMA 方式极大地降低了中断频率,提高了系统效率。
示例:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
// 一次性接收100字节数据
HAL_UART_Transmit_DMA(&huart1, rxBuffer, 100);
HAL_UART_Receive_DMA(&huart1, rxBuffer, 100); // 继续接收
}
}
优势:DMA 只在整个数据块传输完成时触发 1 次中断,而不是逐字节触发,提高了 CPU 的可用性。
3.3. 触发中断次数对比
方式 | 触发中断条件 | 触发次数(假设 100 字节) | 适用场景 |
---|---|---|---|
中断模式 | 每接收 1 个字节触发 | 100 次中断 | 低速数据、小数据包 |
DMA 模式 | 整个缓冲区满了 触发 | 1 次中断 | 高速数据、大数据流 |
3.4. 中断模式 vs. DMA 模式:中断影响
方式 | 中断触发频率 | CPU 负载 | 适用于 |
---|---|---|---|
中断模式 | 高(逐字节触发) | 高(CPU 处理开销大) | 短数据、低速通信(如 AT 指令) |
DMA 模式 | 低(整块数据传输完成后才触发) | 低(CPU 只需处理一次中断) | 高速数据、大数据量(如 GPS、日志记录) |
3.5. 总结
✅ 如果数据量小(例如 AT 指令交互),使用 中断模式,因为它简单易用。
✅ 如果数据量大(如 WiFi 模块、传感器数据采集),必须用 DMA 模式,减少 CPU 负载,提高效率。
✅ DMA 模式大幅减少了中断次数,适用于 高速数据传输,尤其是 RTOS 或多任务系统。
如果你的项目涉及 高频率串口通信,比如传感器数据流、日志记录等,DMA 绝对是最优选择! 🚀
4. 什么时候用哪种模式?
✅ 如果数据量较小(命令解析、调试信息)→ 选用中断模式。
✅ 如果数据量较大(日志存储、传感器数据)→ 选用 DMA 模式。
✅ 如果数据量很小,但 CPU 负载高 → 也可以考虑 DMA。
例如:
- 调试信息(printf 串口输出):中断模式
- GPS 数据流:DMA 模式
- 按键输入解析:中断模式
- WiFi 模块(AT 指令):中断模式(少量指令),DMA(大量数据)
5. 总结
- 中断模式(Interrupt Mode) 适用于 短数据包、低速通信,如 按键输入、AT 指令解析。
- DMA 模式(Direct Memory Access Mode) 适用于 大数据流、高速通信,如 GPS 传输、日志存储。
- DMA 优先级高于中断,在高负载系统中推荐使用 DMA,避免 CPU 过载。
如果你的 STM32 需要处理大数据的串口通信,建议 使用 DMA 模式,否则中断模式即可满足需求! 🚀