嵌入式开发中,中断服务函数中该怎么设计

在嵌入式开发里,中断服务函数(ISR)的设计要遵循特定原则,以此保证系统的稳定性、可靠性以及实时性。下面为你介绍中断服务函数设计的核心要点:

1. 遵循短小精悍的原则

中断服务函数要尽可能简短,迅速完成关键操作后就退出。要是有复杂的处理任务,建议采用 "后半部分处理" 的模式,也就是在中断中只做标记或者设置标志位,具体的处理工作交给主循环或者任务去完成。

2. 禁止中断嵌套需谨慎

  • 完全屏蔽中断:可以通过__disable_irq()(以 ARM Cortex-M 为例)这类函数来屏蔽所有中断,但使用时必须谨慎,要确保屏蔽时间尽可能短。
  • 设置中断优先级:借助 NVIC(同样以 ARM Cortex-M 为例)来设置中断优先级,防止高优先级中断打断当前中断服务函数的执行。

3. 对共享资源进行保护

中断服务函数和主程序可能会共享变量或者硬件资源,此时需要采用原子操作或者互斥机制来进行保护。

c

运行

// 示例:使用原子操作保护共享变量
volatile uint32_t shared_counter;

void IRQ_Handler(void) {
    __disable_irq();    // 禁止中断
    shared_counter++;   // 操作共享变量
    __enable_irq();     // 使能中断
}

4. 不使用阻塞操作

在中断服务函数中,不要使用像延时(delay_ms())、等待信号量或者访问可能阻塞的外设(例如 UART 接收)这类操作。

5. 栈空间要充足

要保证中断服务函数有独立且足够的栈空间,防止出现栈溢出的情况。部分架构(如 ARM Cortex-M)会使用独立的 MSP 栈,这就需要合理配置其大小。

6. 寄存器的保存与恢复

在一些架构中,需要手动保存和恢复被中断服务函数使用的寄存器,不过大多数编译器或者 RTOS 会自动完成这项工作。

7. 外设的清理与使能

在中断服务函数结束之前,要清除中断标志位或者重新使能外设,防止出现中断风暴。

c

运行

void EXTI_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        // 处理中断
        // ...
        
        EXTI_ClearITPendingBit(EXTI_Line0);  // 清除中断标志
    }
}

8. 与 RTOS 的集成

如果使用了 RTOS,要通过特定的 API(如 FreeRTOS 的xTaskNotifyFromISR())来安全地唤醒任务,避免直接调用任务函数。

9. 进行严格测试

  • 压力测试:要验证在高频中断情况下系统的稳定性。
  • 边界条件测试:测试共享资源竞争、中断嵌套等边界情况。
  • 覆盖率测试:确保中断服务函数的每一条执行路径都经过了测试。

10. 避免使用的操作

  • 不要调用 malloc/free 等动态内存分配函数。
  • 禁止使用浮点数运算(除非硬件和编译器提供了支持)。
  • 避免进行复杂的计算或者调用非关键函数。

总结

设计中断服务函数的核心思路是 "快进快出",尽量减少中断处理的时间,把主要工作交给主循环或者任务去完成。同时,要特别注意共享资源的保护以及与系统其他部分的协作。

更多内容全在下方专栏

全网最受欢迎的嵌入式笔试专栏

笔试专栏包含全部最新的笔试必考考点,非常适合在找工作面经薄弱的同学

3000+订阅还会涨价,提前订阅提前享受,持续更新中。

专栏链接:https://www.nowcoder.com/creation/manager/columnDetail/mPZ4kk

#嵌入式笔面经分享#
全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务