RT-Thread 中断与轮询模式驱动笔记
RT-Thread 中断与轮询模式驱动笔记一、两种驱动模式对比特性轮询模式 (Polling)中断模式 (Interrupt)CPU 占用高等待时忙等低等待时挂起线程实时性低需不断查询高事件触发吞吐量低CPU 被占用高可并行处理代码复杂度简单较复杂适用场景高速大数据、低优先级任务低速小数据、实时性要求高二、轮询模式工作流程线程开始发送 ↓ 查询 TXE 标志位 ↓ TXE1? ──否──┐ ↓是 │ 写入 DR 寄存器 │ ↓ │ 还有数据──是──┘ ↓否 发送完成代码示例/* 轮询模式发送 - main.c 中 E22x 驱动类似这种方式 */voiduart_poll_send(uint8_t*data,uint16_tsize){while(size--){/* 等待发送数据寄存器为空 */while(USART_FLAG_RESETusart_flag_get(USART0,USART_FLAG_TBE));/* 写入数据 */usart_data_transmit(USART0,*data);}}优缺点优点代码简单易于理解无中断上下文切换开销数据发送顺序严格保证缺点CPU 一直忙等无法做其他事吞吐量受限于 CPU 速度实时性差三、中断模式工作流程线程写入 FIFO → FIFO 满──是──→ 挂起线程 ↓否 继续写入 ISR: 数据发完了──是──→ FIFO 空──是──→ 唤醒线程 ↓否 ↓否 继续发送 从 FIFO 取数据发送代码示例/* 中断模式 - 线程侧代码 */rt_err_tuart_intr_send(structrt_serial_device*serial,constuint8_t*buf,rt_size_tsize){/* 写入发送 FIFO */for(i0;isize;i){if(fifo_is_full(serial-tx_fifo)){/* FIFO 满挂起线程等待 */rt_completion_wait(serial-tx_comp,RT_WAITING_FOREVER);}fifo_push(serial-tx_fifo,buf[i]);}/* 开启发送中断 */usart_interrupt_enable(serial-uart_device,USART_INT_TBE);returnRT_EOK;}/* 中断服务程序 */voidusart0_irq_handler(void){if(usart_flag_get(USART0,USART_FLAG_TBE)){if(!fifo_is_empty(serial-tx_fifo)){/* FIFO 有数据继续发送 */usart_data_transmit(USART0,fifo_pop(serial-tx_fifo));}else{/* FIFO 空关闭中断并唤醒线程 */usart_interrupt_disable(USART0,USART_INT_TBE);rt_completion_done(serial-tx_comp);}}}优缺点优点CPU 利用率高发送时可做其他事实时性好事件触发适合低速外设缺点代码复杂每次中断有上下文切换开销高速大数据时效率反而下降四、性能分析中断模式吞吐量计算前提条件传输速率10 Mbps单次传输32 Byte中断上下文切换4us进入 退出传输 32 Byte 需要时间 32 Byte × 10 bit/Byte ÷ 10 Mbps 32 us 中断开销 32 × 4us 128 us 总时间 32 us 128 us 160 us 有效吞吐率 32 / 160 20%理论值 实际情况 - 发送时间32us - 中断开销约 8us优化后 - 效率 32/(328) 80%优化策略1. 增加单次传输长度/* 不推荐单次发送 1 Byte */uart_send_byte(data);// 中断开销占比大/* 推荐单次发送 256 Byte */uart_send_buffer(buf,256);// 中断开销平摊2. 轮询 中断混合模式/* 大数据用轮询小数据用中断 */if(sizeTHRESHOLD_256B){uart_poll_send(buf,size);// 轮询模式}else{uart_intr_send(buf,size);// 中断模式}3. DMA 中断/* DMA 传输完成后再触发中断 */dma_transfer(start_addr,size);dma_interrupt_enable(DMA_INT_TC);// 仅传输完成中断五、工程中的应用E22 无线模块驱动 (中断模式)/* ebyte_core.c - 工程中的无线模块驱动 */voidE22x_TaskForIRQ(void){/* 中断回调处理 */if(irq_flag.tx_complete){rt_completion_done(e22_tx_comp);// 唤醒发送线程}if(irq_flag.rx_complete){rt_mq_send(e22_rx_mq,rx_buf,rx_len);// 发送到消息队列}}CAN 总线 (中断模式)/* drv_can.c - 工程中的 CAN 驱动 */staticrt_err_tcan_send(structcan_device*can,structcan_msg*msg){/* 邮箱空闲则写入否则等待中断唤醒 */if(can-tx_fifo_full){rt_sem_take(can-tx_sem,RT_WAITING_FOREVER);}can_write_mailbox(msg);can_interrupt_enable(CAN_INT_TME);// 发送邮箱空中断returnRT_EOK;}六、如何选择场景推荐模式理由高速 SPI Flash 读写轮询数据量大中断开销占比高UART 调试输出轮询简单可靠速率要求不高CAN 总线通信中断实时性要求高数据量小无线模块通信中断事件驱动等待时间长ADC 采样DMA 中断定时采样数据量大按键检测中断事件稀疏实时性要求高七、注意事项中断上下文限制/* 错误在中断中使用 IPC 等待 */voidirq_handler(void){rt_sem_take(sem,RT_WAITING_FOREVER);// 会死锁}/* 正确在中断中使用 IPC 发送 */voidirq_handler(void){rt_sem_release(sem);// 唤醒其他线程rt_mq_send(mq,data,len);// 发送消息}临界区保护/* 中断和线程共享的数据需要保护 */rt_base_tlevelrt_hw_interrupt_disable();// 关中断shared_counter;rt_hw_interrupt_enable(level);// 开中断中断优先级配置/* 确保 RT-Thread 系统中断优先级最高 *//* GD32 配置示例 */NVIC_PriorityGroupConfig(NVIC_PRIGROUP_PRE2_SUB2);NVIC_SetPriority(SysTick_IRQn,0);// 系统滴答最高优先级八、关键 API 总结函数作用上下文rt_hw_interrupt_disable()关中断线程/中断rt_hw_interrupt_enable()开中断线程/中断rt_interrupt_enter()进入中断标志中断rt_interrupt_leave()退出中断标志中断rt_completion_wait()等待完成线程rt_completion_done()完成通知中断/线程rt_sem_take/release()信号量操作线程/中断最后更新2026-03-29