中断是MCU硬件特性,STM32由NVIC(嵌套向量中断控制器)管理硬件中断。以STM32F4为例,通过4位优先级分组配置中断的抢占优先级(数字越小优先级越高,决定中断嵌套)和子优先级(同抢占优先级时决定响应顺序)。每个中断对应一个中断服务例程(ISR),用于响应中断事件。

在启动freertos后,会自动对中断进行一些设置

image-20251013201811403

在CubeMX配置FreeRTOS的“config”参数时需关注以下两个中断相关参数

configLIBRARY_LOWEST_INTERRUPT_PRIORITY

表示系统中断的最低优先级数值。由于采用4位抢占优先级分组,该参数固定为 15(4位二进制最大值为15)

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY

表示FreeRTOS可管理的中断最高优先级,默认值为 5。其核心作用是:

  • 仅当中断优先级 ≥ 5 时,中断服务程序(ISR)中才能调用FreeRTOS的中断安全API(即带 FromISR后缀的函数,如 taskDISABLE_INTERRUPTS());
  • 该参数绝不能设为0,且高优先级(>5)的中断ISR中禁止调用任何FreeRTOS API(包括中断安全函数)。

这里具体还是看书吧

中断安全API

中断安全API是FreeRTOS专门为中断服务程序(ISR)设计的特殊函数(通常带FromISR后缀,如taskDISABLE_INTERRUPTS_FromISR()xQueueSendFromISR())。

普通API(如vTaskDelay()xQueueSend()):只能在任务上下文(即任务函数内部)调用。若在中断里用,会直接操作调度器状态、访问共享资源(如任务队列),导致调度器崩溃或数据错乱。

中断安全API:内部做了中断上下文同步(比如先关闭中断再操作、用原子指令),确保在中断里调用也不会破坏FreeRTOS的内核状态。例如:

  • taskDISABLE_INTERRUPTS_FromISR():安全关闭中断(避免嵌套关闭导致中断永远无法开启);
  • xQueueReceiveFromISR():安全从队列取数据(避免中断与任务争夺队列资源)。

FreeRTOS可屏蔽的中断

这里的“可屏蔽”不是指硬件上的NMI(不可屏蔽中断),而是FreeRTOS通过优先级管理,允许用户控制“哪些中断可以安全调用FreeRTOS API”

PendSV是“可悬起中断”:若PendSV已挂起,SysTick中断到来时会先处理SysTick,之后再处理PendSV——这不会影响任务切换结果,因为两者都是最低优先级,不会干扰高优先级任务的执行。顺序不影响调度的正确性

中断服务例程ISR

只要有ISR在运行,就无法进行任务调度

不管任务的优先级有多高,最低的中断例程也能抢占

如果一个 ISR 执行的时间比较长,任务函数无法及时执行,FreeRTOS 也无法进行任务调度,就会导致软件响应变迟钝。

在实际的软件设计中,一般要尽量简化 ISR 的功能,使其尽量少占用 CPU 的时间。一般的硬件中断都是处理一些数据的接收或发送工作,例如,采用中断方式进行 ADC 数据采集时,只需在 ADC 的中断里将数据读取到缓冲区,而对数据进行滤波、频谱计算等耗时间的工作,就转移到任务函数里处理。

中断频闭和临界代码段

中断屏蔽

taskDISABLE_INTERRUPTS()屏蔽 MCU 的部分中断(不是全部!比如优先级为 0 的高优先级中断可能无法被屏蔽,具体看硬件)。大于等于5

taskENABLE_INTERRUPTS()解除中断屏蔽

临界代码段(内置嵌套计数器,一个加加一个减减)

taskENTER_CRITICAL()进入临界段

taskEXIT_CRITICAL()退出临界段

ISR(中断服务函数)专用的临界段宏(因为普通临界段宏不能在中断里直接调用,会引发重入或逻辑冲突):

taskENTER_CRITICAL_FROM_ISR():中断版本的“进入临界段”,内部调用

taskEXIT_CRITICAL_FROM_ISR(x):中断版本的“退出临界段”

ISR临界段的核心目的:保护ISR内部的原子性,即要么全执行,要么不执行,不会出现中间状态被干扰

当代码在ISR的临界代码段内执行的时候。此时出现更高级的中断时,需要对比BASEPRI的值,也就是所能屏蔽的最屌中断

两种版本的API函数

一种在任务中使用,一种在ISR中使用,可单向混用

设计原则

根据参数 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的设置,MCU(微控制单元)优先级为 0 到 15 的中断,会被划分为 FreeRTOS 不可屏蔽中断可屏蔽中断两类。需依据中断的“重要性”与“功能”,为其分配合适的中断优先级,以明确该中断属于“FreeRTOS 不可屏蔽中断”或“可屏蔽中断”。

ISR 的代码应尽量简洁精炼,需把耗时较长的处理逻辑转移到“任务函数”中实现(避免 ISR 执行过久阻塞系统调度)

中断调用规则:

  • 若为可屏蔽中断的 ISR,仅能调用「中断级」的 FreeRTOS API 函数;绝对禁止调用「普通级」的 FreeRTOS API 函数。
  • 若为不可屏蔽中断的 ISR,禁止调用任何 FreeRTOS API 函数。

代码示例

在临界代码段或者taskdisable_interrupts里,不能调用vtaskdelay等触发任务调度的函数,否则会直接打开中断(反正严禁调用就行)