1. 中断机制深度解析:从轮询到DMA的演进之路
在嵌入式系统开发中,I/O操作的处理方式直接影响着系统性能和资源利用率。记得我第一次调试温湿度传感器时,用while循环死等数据准备好的场景——CPU占用率直接飙到100%,风扇狂转的噪音至今难忘。后来改用中断机制,CPU负载瞬间降到5%以下,这种效率提升的震撼感,让我彻底理解了不同I/O处理方式的本质差异。
1.1 轮询方式的困境与适用场景
轮询(Polling)就像不断刷新快递物流页面,其核心特点是CPU持续主动询问外设状态。从代码实现来看,通常表现为一个while循环不断检查设备状态寄存器:
c复制while(!(USART1->SR & USART_SR_RXNE)) {
// 空循环消耗CPU周期
}
uint8_t data = USART1->DR;
这种方式的优势在于实现简单,不需要额外硬件支持,在以下场景仍然适用:
- 实时性要求不高的教学演示项目
- 单任务系统中处理响应速度极快的设备(如GPIO按键检测)
- 早期微控制器资源极度受限的环境
但它的致命缺陷在于CPU利用率低下。我曾用STM32F103以10ms间隔轮询超声波模块,实测即使没有测量任务,CPU占用率也高达30%。这意味着系统无法有效处理多任务,且功耗难以优化。
1.2 中断机制的工作原理
中断(Interrupt)机制如同快递到货电话通知,其核心组件包括:
- 中断源:GPIO、定时器、通信接口等能触发中断的外设
- 中断控制器:NVIC(Nested Vectored Interrupt Controller)等管理中断优先级和屏蔽
- 向量表:存储各中断服务程序(ISR)入口地址的内存区域
以按键中断为例的典型配置流程:
c复制// 1. 配置GPIO为输入模式
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 2. 设置中断触发边沿
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
// 3. 配置NVIC优先级
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_Init(&NVIC_InitStructure);
当中断发生时,CPU会自动完成以下动作:
- 保存当前程序计数器(PC)和状态寄存器
- 跳转到对应ISR执行
- 执行完毕后恢复现场继续原任务
关键细节:在STM32中,EXTI0_IRQHandler这类函数名是编译器通过向量表关联的,名称必须与启动文件完全一致,否则会导致中断无法响应。
1.3 DMA的飞跃性突破
DMA(Direct Memory Access)如同专业的物流团队,其核心优势体现在:
- 总线仲裁:通过AHB总线矩阵协调CPU与DMA控制器的内存访问
- **传
