FreeRTOS: 中断服务例程 Interrupt Service Routine, ISR
中断服务例程(Interrupt Service Routine, ISR)是嵌入式系统中非常重要的概念,它用于处理硬件或软件触发的中断事件。当一个中断发生时,CPU 会暂停当前执行的任务,转而执行相应的 ISR 来响应这个中断,处理完成后返回原来的任务继续执行。以下是关于 ISR 的详细介绍:
什么是 ISR?
ISR 是一段专门编写的小型程序代码,用来处理特定类型的中断请求。每当有中断信号到来时,操作系统会根据预先设定好的中断向量表找到对应的 ISR 并执行它。ISR 必须快速完成其工作,以确保其他更高优先级的中断能够及时得到响应。
ISR 的特点
- 高优先级:ISR 比普通任务具有更高的优先级,因为它打断了正常程序流。
- 非抢占性:在一个 ISR 执行期间,不会被另一个 ISR 或者普通任务所抢占,除非新来的中断源设置了更高的优先级。
- 简短高效:ISR 应尽可能快地完成,因为长时间运行的 ISR 可能会影响系统的实时性能和响应速度。
- 不能阻塞:ISR 内部不允许调用任何可能导致阻塞的操作(如
vTaskDelay()
),因为这会导致整个系统陷入死锁状态。
中断处理流程
- 中断产生:某个外部设备(如按键、定时器等)或者内部条件触发了中断。
- 保存上下文:CPU 自动保存当前正在执行的任务的上下文信息(寄存器状态等),以便稍后恢复。
- 跳转到 ISR:根据中断向量表中的地址,CPU 跳转到相应的 ISR 开始执行。
- 执行 ISR:ISR 进行必要的操作,例如读取传感器数据、更新计数器、设置标志位等。
- 清除中断标志:确保中断源被正确处理并且不再重复触发。
- 恢复上下文:ISR 完成后,CPU 恢复之前保存的任务上下文,并继续执行被打断的任务。
在 FreeRTOS 中使用 ISR
在 FreeRTOS 环境下,为了保证中断处理的安全性和效率,有一些特殊的 API 和最佳实践需要注意:
- 从 ISR 中发送消息给队列:可以使用
xQueueSendFromISR()
函数将数据发送到队列,但要注意避免阻塞。 - 从中断上下文唤醒任务:可以通过
xSemaphoreGiveFromISR()
或xTaskResumeFromISR()
唤醒等待的任务,同样要避免阻塞。 - 检查是否需要上下文切换:某些 ISR 函数(如上述两个)有一个参数指向一个布尔变量,如果该变量被设为
pdTRUE
,则表明有更高优先级的任务被唤醒,可能需要进行上下文切换。这时应该调用portYIELD_FROM_ISR()
来实现这一点。