本文目标:掌握三种UART数据传输模式的原理、优缺点及应用场景
### 目录
- [@TOC(目录)](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [三种模式对比](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [轮询模式](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [原理](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [优缺点](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [应用场景](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [中断驱动模式](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [发送中断实现](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [接收中断实现](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [DMA传输模式](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [DMA配置](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [循环DMA(接收)](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [混合模式](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [RX中断 + TX DMA](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
- [性能对比实测](#目录 @TOC 三种模式对比 轮询模式 原理 优缺点 应用场景 中断驱动模式 发送中断实现 接收中断实现 DMA传输模式 DMA配置 循环DMA(接收) 混合模式 RX中断 + TX DMA 性能对比实测)
三种模式对比
| 特性 | 轮询模式 | 中断驱动 | DMA传输 |
|---|---|---|---|
| CPU占用 | 极高(阻塞等待) | 中等(中断上下文切换) | 极低(硬件自动) |
| 实时性 | 高(立即响应) | 中等(中断延迟) | 低(DMA延迟) |
| 吞吐量 | 低 | 中 | 高 |
| 实现复杂度 | 简单 | 中等 | 复杂 |
| 功耗 | 高 | 中 | 低 |
| 适用场景 | 简单调试、Bootloader | 通用应用 | 高速大数据量传输 |
轮询模式
原理
c
// 轮询发送
void uart_send_polling(uint8_t data) {
while (!(UART->LSR & LSR_THRE)); // 等待发送缓冲区空
UART->THR = data;
}
// 轮询接收
uint8_t uart_recv_polling(void) {
while (!(UART->LSR & LSR_DR)); // 等待数据就绪
return UART->RBR;
}
优缺点
优点:
- 实现简单,代码量少
- 无需配置中断
- 实时性好(立即检测到数据)
缺点:
- CPU 100%占用,无法处理其他任务
- 功耗高
- 不适合RTOS环境
应用场景
- Bootloader固件下载(简单可靠)
- 早期调试阶段
- 单线程简单应用
中断驱动模式
发送中断实现
c
#define TX_BUF_SIZE 256
static uint8_t tx_buffer[TX_BUF_SIZE];
static volatile uint16_t tx_head = 0, tx_tail = 0;
// 启动发送
void uart_send_start(const uint8_t *data, uint16_t len) {
for (uint16_t i = 0; i < len; i++) {
uint16_t next = (tx_head + 1) % TX_BUF_SIZE;
if (next == tx_tail) break; // 缓冲区满
tx_buffer[tx_head] = data[i];
tx_head = next;
}
UART->IER |= IER_THRE; // 使能发送中断
}
// 发送中断处理
void uart_tx_isr(void) {
if (tx_head != tx_tail) {
UART->THR = tx_buffer[tx_tail];
tx_tail = (tx_tail + 1) % TX_BUF_SIZE;
} else {
UART->IER &= ~IER_THRE; // 关闭发送中断
}
}
接收中断实现
c
#define RX_BUF_SIZE 256
static uint8_t rx_buffer[RX_BUF_SIZE];
static volatile uint16_t rx_head = 0, rx_tail = 0;
// 接收中断处理
void uart_rx_isr(void) {
while (UART->LSR & LSR_DR) {
uint8_t data = UART->RBR;
uint16_t next = (rx_head + 1) % RX_BUF_SIZE;
if (next != rx_tail) { // 缓冲区未满
rx_buffer[rx_head] = data;
rx_head = next;
} else {
// 溢出处理
}
}
}
// 读取数据
int uart_getchar(void) {
if (rx_head == rx_tail) return -1;
uint8_t c = rx_buffer[rx_tail];
rx_tail = (rx_tail + 1) % RX_BUF_SIZE;
return c;
}
DMA传输模式
DMA配置
c
// 配置TX DMA
void uart_tx_dma_init(void) {
// 配置DMA通道
DMA_CH->SAR = (uint32_t)tx_dma_buffer; // 源地址
DMA_CH->DAR = (uint32_t)&UART->THR; // 目标地址
DMA_CH->CTL = DMA_MEM_TO_PERIPH |
DMA_MINC_ENABLE | // 源地址递增
DMA_BYTE_SIZE;
// UART使能DMA
UART->DMACR |= UART_TXDMAE;
}
// 启动DMA发送
void uart_send_dma(const uint8_t *data, uint16_t len) {
memcpy(tx_dma_buffer, data, len);
DMA_CH->CNDTR = len; // 传输长度
DMA_CH->CCR |= DMA_EN; // 启动DMA
}
// DMA传输完成中断
void DMA_IRQHandler(void) {
if (DMA->ISR & DMA_TCIF) { // 传输完成
DMA->IFCR = DMA_CTCIF; // 清除标志
DMA_CH->CCR &= ~DMA_EN; // 停止DMA
// 通知应用层
tx_complete_callback();
}
}
循环DMA(接收)
c
#define RX_DMA_SIZE 1024
void uart_rx_dma_init(void) {
DMA_CH->SAR = (uint32_t)&UART->RBR;
DMA_CH->DAR = (uint32_t)rx_dma_buffer;
DMA_CH->CNDTR = RX_DMA_SIZE;
DMA_CH->CTL = DMA_PERIPH_TO_MEM |
DMA_MINC_ENABLE |
DMA_CIRCULAR_MODE; // 循环模式
DMA_CH->CCR |= DMA_EN;
UART->DMACR |= UART_RXDMAE;
}
// 读取已接收数据
uint16_t uart_rx_dma_read(uint8_t *buf, uint16_t len) {
uint16_t dma_pos = RX_DMA_SIZE - DMA_CH->CNDTR;
uint16_t available = (dma_pos - rx_tail + RX_DMA_SIZE) % RX_DMA_SIZE;
if (len > available) len = available;
for (uint16_t i = 0; i < len; i++) {
buf[i] = rx_dma_buffer[rx_tail];
rx_tail = (rx_tail + 1) % RX_DMA_SIZE;
}
return len;
}
混合模式
RX中断 + TX DMA
c
// 接收:中断驱动(低延迟)
// 发送:DMA(高效率)
适用场景:
- 接收数据量小,需要快速响应(命令/协议)
- 发送数据量大(日志、文件传输)
性能对比实测
测试条件:
- MCU: STM32F4, 168MHz
- 波特率: 921600 bps
- 数据: 连续发送1KB
| 模式 | CPU占用 | 传输时间 | 中断次数 |
|---|---|---|---|
| 轮询 | 100% | 11.1ms | 0 |
| 中断 | 15% | 11.2ms | ~1000 |
| DMA | 2% | 11.1ms | 1 |
延伸阅读:\[09-FIFO管理与流控]、\[13-多串口并发处理]
上一篇 :\[07-UART控制器寄存器详解]
下一篇:\[09-FIFO管理与流控]
✨ 感谢你的阅读 ✨
技术之路漫漫,分享是为了更好地交流。
如果本文的内容对你有启发,希望能得到你的支持:
👍 点赞 | ⭐ 收藏 | 👀 关注
如果你在调试过程中遇到了其他问题,
欢迎在 评论区 💬 留言,我们一起探讨。
关注我,一起交流底层开发的那些事儿!🚀