【串口技术系列文档 08】中断驱动vs轮询vs DMA

本文目标:掌握三种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管理与流控]


✨ 感谢你的阅读 ✨

技术之路漫漫,分享是为了更好地交流。

如果本文的内容对你有启发,希望能得到你的支持:

👍 点赞 | ⭐ 收藏 | 👀 关注

如果你在调试过程中遇到了其他问题,

欢迎在 评论区 💬 留言,我们一起探讨。

关注我,一起交流底层开发的那些事儿!🚀


相关推荐
尼喃1 小时前
OVP芯片完整方案:前级瞬态钳位、持续过压隔离与后端保护
嵌入式硬件
不会代码的小猴1 小时前
认识HAL库
单片机·嵌入式硬件
莫小墨1 小时前
数字地、模拟地、功率地
嵌入式硬件
Zw-awa1 小时前
把 AO 接回来:黑线和白底之间到底差了多少
stm32
BSD_HY1 小时前
薄膜开关矩阵按键的GPIO扩展芯片选型与中断响应延迟
单片机·线性代数·矩阵
xunyan62342 小时前
51 单片机LED闪烁(SDCC + Notepad++ + STC-ISP/普中ISP)
单片机·notepad++·接口隔离原则
桀人2 小时前
USART帧格式
网络·stm32·单片机·嵌入式硬件
qq_448011162 小时前
如何烧录TAU804的固件
单片机·嵌入式硬件
深圳老胡2 小时前
STM32F4 OTA 升级双 App 方案设计与实现
笔记·stm32·单片机·代码规范