嵌入式面试八股文之FreeRTOS

1.1 任务 Task

1
2
xTaskCreate(task_func, "task", 4096, NULL, 5, &handle);
任务函数 名字 任务名 栈大小 传参 优先级 任务句柄

动态创建(xTaskCreate):从堆分配TCB和栈,简答灵活。

静态创建(xTaskCreateStaytic):用预分配的数组-不依赖堆、确定性好。资源受限的安全关键场景用静态创建。

1.1.1优先级

在FreeRTOS中,数字越大优先级越高。

1.1.2怎么设置优先级?

1、实时性要求高的任务优先级高

2、耗时但不紧急的任务优先级低

3、高优先级任务不能长时间占用CPU

1.2 队列 Queue

队列是FreeRTO任务间传递数据的安全通道:

发送方put数据->队列缓冲->接收方get数据。

支持阻塞等待(满时等空位/空时等数据)。

1.2.1场景:

  • UART接收任务把数据发送给协议解析任务
  • 传感器任务把采集结果发送给显示任务
  • 中断把事件发送给事件处理任务

1.2.2队列和共享全局变量:

队列更适合任务间传递数据:

1、数据边界清晰

2、可以阻塞等待

3、减少共享变量竞争

4、容易维护

5、自带同步

全局变量:适合简单状态,但是需要考虑同步

1.3 互斥量 Mutex

互斥锁保护共享资源一次只被一个任务访问。互斥锁有优先级继承(防止优先级反转)、持有者概念(只有获取者能释放)。保护共享资源用互斥锁。

1.4 二值信号量

二值信号量只有0和1两个状态-Give设为1(有事件)、Take设为0(处理事件)。典型用途:中断Give->任务Take(中断通知任务)。简单高效,最常用的同步机制。

信号量常用于任务间同步或资源计数。

1.5 计数信号量

计数信号量计数值可以大于1。Give加1、Take减1(为0则阻塞)。

用于:

1、管理多个资源(例如3个UART通道)

2、事件计数(不丢失多次Give)

信号量同于任务间同步或资源计数。

1.6 任务通知 Task Notification

任务通知时FreeRTOS最轻量的同步机制—每个任务内置一个32位通知值和一个通知状态(不需要额外创建内核对象 )。比信号量/队列都快45%(无需创建对象、无需动态内存)。限制:只能点对点通知(不能一对多),

1.7 看门狗

看门狗是一个硬件定时器,作用是检测程序卡死/跑飞,自动复位系统:

工作原理:任务必须定期“喂狗”(重置计数器),如果超时没喂,说明程序出问题 -> 看门狗复位芯片。

独立看门狗 IWDG:

  • 独立时钟源(LSI),主时钟挂了也能复位
  • 只能防程序跑飞/卡死

窗口看门狗 WWDG:

  • 喂狗必须在时间窗口内(太快太慢都复位)
  • 能检测程序“跑得太快”(时序异常)

1.7.1 FreeRTOS中的应用

用空闲任务钩子(Idle Hook)+ 计数方式实现任务级监控:

  1. 每个被监控任务运行时设置一个“活着”标志
  2. 空闲任务检查所有标志,全部正常才喂狗
  3. 清零标志,等待下一轮

好处:任何一个任务卡死,空闲任务检测到标志不全 -> 不喂狗 -> 系统复位。

1.7.2 注意

1、喂狗周期要合理:太短容易误复位,太长失去保护意义
2、不要在中断里随意喂狗(会掩盖任务卡死)
3、调试器断点会暂停喂狗,可配置调试时暂停看门狗

1.8 临界区 Critical Section

临界区是一段不允许被打断的代码,用于保护极短的共享资源访问:

1
2
3
taskENTER_CRITICAL();   // 进入临界区(关闭中断/调到最高优先级)
// 访问共享资源,必须极短
taskEXIT_CRITICAL(); // 退出临界区

1.8.1 实现方式

FreeRTOS根据配置不同,进入临界区可能:

  • 关中断(禁用可屏蔽中断)
  • 或屏蔽到 configMAX_SYSCALL_INTERRUPT_PRIORITY 以下的中断

1.8.2 使用原则

1、时间要极短(微秒级):关中断期间无法响应中断,影响实时性
2、临界区内不能调用可能阻塞的API(如 xQueueSend 带阻塞时间)
3、支持嵌套:进出次数配对即可

1.8.3 中断中的临界区

1
2
3
UBaseType_t saved = taskENTER_CRITICAL_FROM_ISR();
// 访问共享资源
taskEXIT_CRITICAL_FROM_ISR(saved);

1.8.4 临界区 vs 互斥量 vs 挂起调度器

机制 适用场景 是否关中断 开销
临界区 任务与中断共享数据(短) 是 小
互斥量 Mutex 任务之间共享资源(可长) 否,有优先级继承 中
挂起调度器 vTaskSuspendAll 任务之间,不想关中断 否 小

选择建议:

  • 和中断共享数据 -> 临界区
  • 任务间共享长资源 -> 互斥量
  • 任务间共享但不想关中断 -> 挂起调度器