2025最新超详细FreeRTOS入门教程:第十三章 FreeRTOS临界区与原子操作

2025最新超详细FreeRTOS入门教程:第十三章 FreeRTOS临界区与原子操作

摘要

在多任务系统中,多个任务可能会同时访问同一资源(如全局变量、外设寄存器、缓冲区)。如果没有采取保护措施,可能会发生:

  • 数据竞争(Race Condition)
  • 任务/中断交叉修改数据
  • 死锁

临界区(Critical Section) 和 原子操作(Atomic Operation) 是解决上述问题的基础机制。

在 FreeRTOS 中,它们提供了一种轻量级的数据保护方式,与互斥量、信号量相比,开销更低,效率更高。

文章目录


一、什么是临界区?

临界区指一段需要 独占访问共享资源 的代码。在多任务系统中,为了保证这段代码不被打断,必须采取措施:

  • 禁止任务切换(避免其他任务抢占 CPU)
  • 禁止中断访问(避免 ISR 修改共享数据)

访问共享变量 访问共享变量 访问共享变量 任务A 临界区 任务B 中断 冲突: 数据错乱


二、FreeRTOS 提供的临界区机制

1. 任务级临界区

c 复制代码
taskENTER_CRITICAL();
    // 临界区代码
taskEXIT_CRITICAL();

特点:

  • 禁止 中断和任务切换
  • 不可嵌套使用(多次调用会造成问题)

2. 支持嵌套的临界区

c 复制代码
UBaseType_t uxSavedStatus = taskENTER_CRITICAL_FROM_ISR();
// 临界区代码
taskEXIT_CRITICAL_FROM_ISR(uxSavedStatus);

特点:

  • 可在 ISR 中使用
  • 可多次嵌套,退出时恢复原状态

3. 调度器挂起/恢复

c 复制代码
vTaskSuspendAll();
// 临界区代码(调度器暂停)
xTaskResumeAll();

特点:

  • 只禁止任务切换
  • 中断仍然可用
  • 比 taskENTER_CRITICAL 粒度更细

三、原子操作

某些变量(如 8 位或 16 位寄存器)在大多数 MCU 上是原子访问的,但 32 位变量在 8/16 位 MCU 上不是原子操作。

FreeRTOS 提供了原子操作宏:

c 复制代码
#define taskENTER_CRITICAL()    portENTER_CRITICAL()
#define taskEXIT_CRITICAL()     portEXIT_CRITICAL()

此外,用户也可以使用 C11 原子库 或 CMSIS 提供的 __LDREX / __STREX 指令。


四、临界区 vs 互斥量

特性 临界区 互斥量
粒度 CPU 级别(禁止中断/调度) 任务级别(优先级继承)
开销 极低 较高
可嵌套 支持(带 FROM_ISR 版本) 不支持
使用场景 简单数据保护 共享外设、复杂资源

五、使用示例

示例1:任务中保护共享变量

c 复制代码
volatile int sharedCounter = 0;

void vTaskIncrement(void *pvParameters)
{
    for(;;)
    {
        taskENTER_CRITICAL();
        sharedCounter++;
        taskEXIT_CRITICAL();
        vTaskDelay(100);
    }
}

示例2:中断与任务共享数据

c 复制代码
volatile uint32_t ulISRValue = 0;

void vTaskHandler(void *pvParameters)
{
    for(;;)
    {
        taskENTER_CRITICAL();
        printf("共享值=%lu\n", ulISRValue);
        taskEXIT_CRITICAL();
        vTaskDelay(500);
    }
}

void TIM2_IRQHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken;
    uint32_t oldStatus;

    oldStatus = taskENTER_CRITICAL_FROM_ISR();
    ulISRValue++;
    taskEXIT_CRITICAL_FROM_ISR(oldStatus);

    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

六、临界区的工作机制

taskENTER_CRITICAL 阻止ISR和任务切换 taskEXIT_CRITICAL 正常调度 临界区 禁止中断 临界区结束


七、调试与优化

  1. 避免长时间占用临界区
    • 临界区代码必须简短
    • 否则会影响系统实时性
  2. 使用嵌套版本
    • 推荐使用 taskENTER_CRITICAL_FROM_ISR
    • 确保中断退出时状态恢复正确
  3. 避免死锁
    • 不要在临界区中使用阻塞 API(如 xQueueReceive())

八、常见问题与解决方法

问题 原因 解决方法
系统响应变慢 临界区占用过长 缩短临界区代码
死锁 临界区中调用阻塞 API 避免阻塞调用
中断丢失 过度使用临界区 优化设计,缩短屏蔽时间

九、经验总结

📌 开发建议

  1. 临界区适合保护简单的共享数据(如变量 ++)
  2. 对于复杂外设访问,用 互斥量 更合适
  3. 临界区必须尽可能短,避免影响实时性
  4. ISR 中推荐使用 taskENTER_CRITICAL_FROM_ISR

十、总结

通过本章学习,你已经掌握:

  • FreeRTOS 临界区的基本概念
  • taskENTER_CRITICAL 与 vTaskSuspendAll 的区别
  • 临界区与互斥量的对比
  • 如何在 ISR 中正确保护共享数据

临界区与原子操作是 FreeRTOS 最底层的数据保护机制,理解它们才能设计出高效、稳定的系统。


🔗 FreeRTOS专栏 👉 下一章:2025最新超详细FreeRTOS入门教程:第十四章 FreeRTOS空闲任务与钩子函数 ------我们将学习 FreeRTOS 的 Idle 任务、空闲任务钩子、Tick Hook、Malloc Failed Hook。


相关推荐
microrain2 小时前
读数是 1008,用电量是 8:SagooIoT 计算服务的增量口径与七种计算策略
物联网·golang·计算服务·sagooiot
wuyk5552 小时前
嵌入式驱动开发:量产级工程化实战(第9篇)——低功耗下的通信可靠性
c语言·驱动开发·stm32·单片机·嵌入式硬件
创界工坊工作室3 小时前
24-基于单片机的仓鼠养殖环境监控系统设计
stm32·单片机·嵌入式硬件·proteus
碧海银沙音频科技研究院3 小时前
基于炬芯ATS录音卡BLE控制协议
人工智能·嵌入式硬件·算法·语音识别
星恒讯工业路由器4 小时前
从5G-A到6G:工业通信网络的技术演进与产业落地
网络·物联网·5g·智能路由器·工业路由器·工业物联网·5g-a
comyccccc4 小时前
PCB走线设计秘籍:从载流到3D预览全解析学习笔记
单片机·嵌入式硬件
俊基科技4 小时前
A-59 工业级 AI 语音处理模组:100 dB 消回音 + 神经网络降噪的工程实践
嵌入式硬件·神经网络·硬件开发·语音模块·回音消除·拾音降噪
endeavor124 小时前
can总线(五)
c语言·stm32·单片机·can
威嵌神州5 小时前
10.1 寸集成加密专网加固平板|外场加密通信硬件基线选型评估
人工智能·嵌入式硬件·平板
深圳市尚想信息技术有限公司5 小时前
TM52F1376海速芯HITENX Flash-8位MCU单片机,多通道ADC + 段码显示一体化主控芯片
单片机·嵌入式硬件·mcu·flask·芯片·控制器