单片机基础核心知识点汇总(四十九)

目录

前言

[一、先理清 ARM Cortex-M 中断优先级基础](#一、先理清 ARM Cortex-M 中断优先级基础)

[1. 两个关键阈值(Cortex-M 端口)](#1. 两个关键阈值(Cortex-M 端口))

[2. BASEPRI 寄存器作用](#2. BASEPRI 寄存器作用)

[二、中断服务函数 ISR 的两条路线](#二、中断服务函数 ISR 的两条路线)

[1. 高优先级快中断(禁止调用 RTOS API)](#1. 高优先级快中断(禁止调用 RTOS API))

[2. 可交互中断(允许调用 xxxFromISR)](#2. 可交互中断(允许调用 xxxFromISR))

[三、延迟中断处理(DPC,Deferred Interrupt Processing)------ 工程最推荐方案](#三、延迟中断处理(DPC,Deferred Interrupt Processing)—— 工程最推荐方案)

[1. 核心思想](#1. 核心思想)

[2. 标准模板(信号量版本)](#2. 标准模板(信号量版本))

[四、中断中可用与禁用 API 清单](#四、中断中可用与禁用 API 清单)

五、中断嵌套规则

[六、临界区保护:taskENTER_CRITICAL 和 taskEXIT_CRITICAL](#六、临界区保护:taskENTER_CRITICAL 和 taskEXIT_CRITICAL)

七、中断栈配置(极易忽略,量产死机元凶)

八、高频量产坑点汇总

九、工程最佳实践总结

小结


前言

在嵌入式系统里,中断是硬件和内核交互的入口,按键、串口、传感器、DMA、定时器全部依赖中断。很多新手写 RTOS 项目时,裸机中断代码直接移植进来,出现莫名其妙的死机、任务卡死、数据丢包、临界区异常、低功耗唤醒失败。


根源在于:RTOS 环境下的中断不再是裸机里简单的 "来了就执行",中断和任务调度存在优先级博弈、资源共享规则、API 调用限制。


本篇围绕 FreeRTOS 中断整套体系,从中断优先级分组、BASEPRI 屏蔽、中断服务函数写法、中断里能用 / 不能用的 API、延迟中断处理、中断嵌套、临界区保护、量产踩坑点完整梳理,是稳定性项目必须吃透的内容。


一、先理清 ARM Cortex-M 中断优先级基础

Cortex-M 内核的中断优先级分为抢占优先级(Preempt Priority) 和子优先级(Sub Priority),由优先级分组决定。

重点:FreeRTOS 不关心子优先级,只认抢占优先级!子优先级只在同抢占优先级中断同时到来时决定先后,不能触发嵌套。

1. 两个关键阈值(Cortex-M 端口)

  1. configMAX_SYSCALL_INTERRUPT_PRIORITY 可以调用 FreeRTOS FromISR 系列 API 的中断最高抢占优先级。优先级数字越小,优先级越高。 高于这个阈值(数值更小)的中断,禁止调用任何 FreeRTOS API ,这类中断称为零延迟中断 / 内核外中断,不会被内核屏蔽,不参与调度。
  2. configKERNEL_INTERRUPT_PRIORITY SysTick、PendSV 这两个内核专用中断的优先级,一般设置为最低。

口诀:高优先级中断只管硬件快响应,不要发信号量、队列;低优先级中断才允许和 RTOS 内核交互。

举个常用配置示例:

复制代码
// 优先级分组4,4位抢占优先级,0位子优先级
#define configPRIO_BITS         __NVIC_PRIO_BITS
#define configKERNEL_INTERRUPT_PRIORITY         (15)
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    (5)

**含义:**抢占优先级 0~4:极高优先级中断,禁止调用 xxxFromISR;抢占优先级 5~15:可以安全调用中断版本 API。

2. BASEPRI 寄存器作用

FreeRTOS 关闭中断不是直接清全局中断掩码(PRIMASK),而是写 BASEPRI。 BASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY: 所有抢占优先级≥该值的中断被屏蔽;优先级更高的中断依旧可以正常进入,实现选择性关中断,这也是 RTOS 保证实时性的核心设计。

二、中断服务函数 ISR 的两条路线

1. 高优先级快中断(禁止调用 RTOS API)

**适用场景:**高频、严苛实时需求,比如高速编码器、PWM 故障保护、紧急停机。

特点:

  • 抢占优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY
  • ISR 代码必须极短,只做硬件寄存器清标志、简单 IO 翻转
  • 绝对不能调用 xSemaphoreGiveFromISR、xQueueSendFromISR 等 API
  • 不能触发任务切换,和 RTOS 内核完全隔离 缺点:无法通知任务,复杂业务逻辑不能放这里。

2. 可交互中断(允许调用 xxxFromISR)

**适用场景:**串口接收、按键触发、传感器数据就绪、DMA 传输完成。

特点:

  • 抢占优先级 ≤ configMAX_SYSCALL_INTERRUPT_PRIORITY
  • ISR 内只做最精简硬件操作,通过信号量 / 队列通知任务,把复杂逻辑丢到任务里执行(延迟中断处理)
  • API 必须带后缀 FromISR,普通 API(xSemaphoreGive)严禁在中断中调用
  • 携带参数 pxHigherPriorityTaskWoken,用来判断是否需要中断退出后触发任务切换

三、延迟中断处理(DPC,Deferred Interrupt Processing)------ 工程最推荐方案

1. 核心思想

中断服务函数只做三件小事:

  1. 清除中断标志位
  2. 拷贝必要的少量硬件数据到缓冲区
  3. 释放信号量 / 投递消息到队列,唤醒专门的处理任务 耗时解析、校验、协议解析、打印日志、数据存储全部放到任务中执行。

好处:

  • ISR 执行时间极短,降低中断阻塞、丢失其他中断的风险
  • 代码分层清晰,中断只管硬件通知,业务逻辑在任务,方便调试
  • 可以正常使用所有任务 API、延时、队列、事件组
  • 避免长中断占用 CPU,打乱调度、破坏 Tickless 低功耗

2. 标准模板(信号量版本)

复制代码
// 全局二值信号量
SemaphoreHandle_t xSensorSem = NULL;

// 中断服务函数
void EXTI0_IRQHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    {
        EXTI_ClearITPendingBit(EXTI_Line0);
        // 释放信号量,唤醒任务
        xSemaphoreGiveFromISR(xSensorSem, &xHigherPriorityTaskWoken);
        // 如果唤醒了更高优先级任务,退出中断时切换上下文
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

// 处理任务
void vSensorTask(void *pvParam)
{
    while(1)
    {
        xSemaphoreTake(xSensorSem, portMAX_DELAY);
        // 这里放耗时逻辑:读取数据、校验、滤波、上报
    }
}

portYIELD_FROM_ISR:中断上下文的任务切换,只能在 FromISR API 之后使用,不要随便调用。

四、中断中可用与禁用 API 清单

✅ 中断(xxxFromISR)允许调用:

  • xSemaphoreGiveFromISR /xSemaphoreTakeFromISR(二值、计数信号量)
  • xQueueSendFromISR / xQueueReceiveFromISR
  • xEventGroupSetBitsFromISR
  • vTaskNotifyGiveFromISR(任务通知,轻量化首选)

❌ 中断里面绝对禁止:

  • 不带 FromISR 后缀全部 API:xSemaphoreGive、xQueueSend、vTaskDelay
  • 动态内存分配:pvPortMalloc
  • vTaskSuspend、vTaskDelete
  • printf、串口阻塞发送(底层可能带锁、延时)
  • 任何会阻塞的函数

补充:任务通知(vTaskNotifyGiveFromISR)开销比信号量更小,不需要单独创建信号量,资源紧张项目优先选用。


五、中断嵌套规则

Cortex-M 本身支持中断嵌套:抢占优先级高的中断可以打断正在执行的低抢占优先级中断。 结合 FreeRTOS,嵌套约束:

  1. 高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的高优先级中断,可以随时嵌套打断低优先级中断,不受 BASEPRI 屏蔽
  2. 同抢占优先级,不会嵌套,按先后排队
  3. 内核关闭中断(BASEPRI 生效期间),只屏蔽≤阈值的中断,高优先级中断依旧可以进来
  4. 不要滥用嵌套:嵌套层级越深,栈溢出风险越高,调试难度指数上升

⚠️ 坑:很多人把所有中断优先级设成一样,结果并发中断丢事件、响应卡顿。


六、临界区保护:taskENTER_CRITICAL 和 taskEXIT_CRITICAL

临界区用来保护全局共享变量,防止任务和中断同时访问造成数据错乱。

复制代码
taskENTER_CRITICAL();
// 访问共享全局变量,简短操作
g_u32Count++;
taskEXIT_CRITICAL();
  • taskENTER_CRITICAL 底层写 BASEPRI,屏蔽可调用 RTOS API 的中断;高优先级硬中断依旧能进入
  • 临界区代码必须极短,禁止延时、打印、循环、调用任何阻塞 API
  • 如果是中断内部 的临界保护,要用 portSET_INTERRUPT_MASK_FROM_ISR() / portCLEAR_INTERRUPT_MASK_FROM_ISR(),不能用 taskENTER_CRITICAL

七、中断栈配置(极易忽略,量产死机元凶)

两个栈要区分:

  1. 主栈 MSP:中断服务函数默认使用 MSP 栈,在启动文件中配置 Stack_Size
  2. 任务栈 PSP:每个任务独立栈,任务运行时使用

重点:中断里面函数调用深度大、局部变量多,消耗的是 MSP!很多项目任务栈配很大,但 MSP 栈很小,中断一复杂直接栈溢出,随机 HardFault。

排查建议:

  • 串口、DMA、协议解析这类中断相关逻辑尽量丢到任务,减少 ISR 栈消耗
  • 调试时开启栈水位统计,监控 MSP 剩余空间

八、高频量产坑点汇总

  1. 裸机中断直接复制,ISR 里调用普通 xSemaphoreGive 直接触发异常、HardFault,必须替换成 FromISR 版本,带上 pxHigherPriorityTaskWoken。
  2. 优先级配置颠倒,数字大小理解错误 很多人误以为数值大优先级高,和 Cortex-M 规则相反,导致高实时中断被内核屏蔽。
  3. 中断里做大量耗时处理 ISR 长时间占用 CPU,其他中断被阻塞、丢数据,同时破坏 Tickless 休眠,功耗异常。
  4. pxHigherPriorityTaskWoken 传 NULL 高优先级任务唤醒后无法及时切换,调度延迟,时序异常。
  5. 临界区里面写延时、打印 临界区长时间关中断,系统 Tick 停止、调度卡死。
  6. 高优先级中断里面使用 FromISR API 高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断调用内核 API,直接崩溃。
  7. 多个中断同时操作同一个队列,缺少保护 队列本身 FromISR 接口是线程安全的,但如果中断 + 任务同时操作,遵循 API 规范即可;跨多个中断并发写入队列一般没问题,但要注意数据帧边界。
  8. 中断标志忘记清除、清除时机错误 中断反复进,系统卡死在 ISR 循环。
  9. MSP 栈空间不足,随机死机 现象:偶发 HardFault,复现概率低,抓栈很难定位。
  10. portYIELD_FROM_ISR 放错位置 必须在 FromISR 调用之后,中断退出前;不要放在 if 判断之外随意调用。

九、工程最佳实践总结

  1. 分层原则:ISR 只做硬件标记 + 通知,业务逻辑全部延迟到任务处理
  2. 优先级划分:故障保护、紧急信号放在高优先级(不碰 RTOS API);通信、传感器放在低优先级(允许 FromISR)
  3. 中断代码瘦身:禁止在 ISR 写循环、协议解析、日志输出
  4. 优先使用任务通知替代信号量,减少内核资源开销
  5. 合理设置 MSP 栈大小,定期监控栈水位
  6. 共享资源区分保护:任务之间用互斥量;中断与任务共享用临界区
  7. 低功耗项目注意:中断是唤醒源,所有唤醒中断优先级要合理配置,避免唤醒后调度异常
  8. 上线前长时间压力测试:高频触发中断,测试丢包、死机、时序异常

小结

FreeRTOS 中断管理的核心一句话:区分中断优先级等级,划分 "和内核交互" 与 "纯硬件快中断" 两类中断;中断只负责通知,业务交给任务。

中断是稳定性的重灾区,很多偶发死机、数据异常,根源都出自中断写法、优先级、栈配置这几块。吃透这部分,项目稳定性会上一个台阶。

相关推荐
国科安芯1 小时前
星上计算的第一道防线:低轨遥感卫星载荷处理链中的AS32S601型抗辐射MCU—— 面向高分辨率成像与在轨智能处理的场景化综述
大数据·网络·人工智能·单片机·算法·低轨卫星·抗辐射
新晨单片机设计1 小时前
S032A-基于STM32单片机智能加湿器【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus·智能加湿器
硅基造物主1 小时前
STM32 从 0 到 1 做智能家居(九):按键消抖与三模式状态机
stm32·单片机·嵌入式硬件·cubemx·智能家居
小飞侠123!2 小时前
Simplicity Studio v5 IDE添加SDK失败如何处理?
嵌入式硬件
霖霖7142 小时前
【笔记】直流减速电机(GA25-370)调速
笔记·单片机·mcu
国科安芯2 小时前
从点火到入轨的毫秒尺度:商业运载火箭飞行时序控制中的抗辐射MCU可靠性边界—— 面向短时高可靠任务的单粒子效应证据与架构分析
网络·人工智能·单片机·嵌入式硬件·架构·火箭·抗辐射
吠品2 小时前
78B 只激活 3.46B,Kolibri 给模型选型上了一课
人工智能·单片机·嵌入式硬件
恒锐丰科技林技术员2 小时前
大电流同步降压 DC‑DC 芯片 EG11732 解析
经验分享·嵌入式硬件·硬件工程
路上有只喵2 小时前
认识元器件 · 单片机(MCU/MPU/SOC) · 规格书解读1
单片机·嵌入式硬件