STM32 进阶封神之路(三十八) FreeRTOS 从零到一完全吃透|裸机对比、内核本质、任务创建与调度(超详细图文版)

0 阅读7分钟

STM32 进阶封神之路(三十八)

FreeRTOS 从零到一完全吃透|裸机对比、内核本质、任务创建与调度(超详细图文版)

前言

在嵌入式系统开发从 “裸机” 走向 “多任务” 的过程中,FreeRTOS 占据着不可替代的地位。它轻量、开源、稳定、覆盖芯片平台极广,是每一位嵌入式开发者必须掌握的实时操作系统。

本篇将从零开始,完整、细致、深入地讲解 FreeRTOS 核心基础内容。从最经典的裸机前后台架构讲起,逐步深入 RTOS 概念、可剥夺内核、任务状态、任务创建、调度机制、延时函数本质区别。全文逻辑清晰、语言通俗、内容系统,帮你真正理解 FreeRTOS 是什么、为什么要用、如何正确使用。

无论你是刚刚接触 RTOS 的单片机开发者,还是即将面对面试、笔试的嵌入式岗位求职者,这一篇都能帮你彻底打通 FreeRTOS 基础关卡。


一、什么是嵌入式系统?裸机与操作系统的本质区别

在正式进入 FreeRTOS 之前,我们必须先理清一个最核心、最基础的问题:裸机系统是什么?RTOS 又是什么?

1.1 裸机系统(前后台系统)

绝大多数开发者学习单片机的起点,都是裸机程序。

裸机系统也被称为前后台系统

  • 后台:main 函数中的 while (1) 死循环,依次轮询执行各个模块逻辑。
  • 前台:中断服务函数,处理异步紧急事件,如串口接收、外部中断、定时器触发等。

典型裸机结构如下:

c

运行

while(1)
{
    LED_Process();
    Key_Process();
    UART_Process();
    LCD_Process();
}

裸机系统结构简单、易于理解,但它存在无法回避的致命缺陷

  • 实时性极差高优先级事件必须等待当前函数执行完毕才能响应。
  • 程序结构混乱功能越多,while (1) 越长,耦合严重、难以维护。
  • 无法抢占一旦某个模块出现长时间延时或阻塞,整个系统都会卡住。
  • CPU 利用率极低大量时间浪费在空循环、软件延时中。

这就是为什么稍微复杂的项目、工业级项目,都必须使用 RTOS 实时操作系统。

1.2 什么是 RTOS(Real Time Operating System)

RTOS 即实时操作系统

它最核心的特点是:能够在规定的时间内响应外部事件,保证高优先级任务优先执行。

常见的 RTOS:

  • FreeRTOS(开源免费、最主流)
  • UCOS II / UCOS III
  • RT-Thread
  • RTX

FreeRTOS 凭借开源、轻量、生态完善、芯片厂商原生支持,成为学习与工业产品的首选方案。


二、操作系统分类:分时、实时、半实时

2.1 分时操作系统

代表:Linux、Windows

  • 按时间片轮流执行任务
  • 不区分任务优先级
  • 不保证实时响应

2.2 硬实时操作系统

代表:UCOS

  • 永远运行优先级最高的任务
  • 高优先级任务可以抢占低优先级
  • 不允许相同优先级存在

2.3 半实时操作系统

代表:FreeRTOS

  • 支持优先级抢占
  • 允许相同优先级任务
  • 相同优先级任务按时间片轮流调度

FreeRTOS 属于可剥夺型实时内核,这是它实时性强、效率高的根本原因。


三、可剥夺内核 vs 不可剥夺内核(面试必考)

这是 FreeRTOS 最核心的原理,必须彻底理解。

3.1 不可剥夺内核(合作式)

  • 任务必须主动放弃 CPU 才能切换
  • 中断可以唤醒高优先级任务,但不能直接抢占
  • 实时性差,不适合工业控制

3.2 可剥夺内核(抢占式)—— FreeRTOS 使用

规则只有一句话:CPU 永远运行当前就绪队列中优先级最高的任务!

运行流程:

  1. 低优先级任务正在运行
  2. 高优先级任务变为就绪态
  3. 立即抢占 CPU,低优先级任务暂停
  4. 高优先级任务执行完毕
  5. 低优先级任务恢复运行

这就是 FreeRTOS 能够保证强实时性的核心机制。


四、FreeRTOS 基础术语(必须背会)

4.1 任务(Task)

  • 一个独立的无限循环函数
  • 拥有独立栈空间
  • 可独立被调度、切换

4.2 任务调度器(Scheduler)

内核的核心,负责决定当前哪个任务可以运行。

4.3 优先级(Priority)

数字越大,优先级越高。优先级范围:0 ~ configMAX_PRIORITIES-1

4.4 任务堆栈(Stack)

用于保存任务运行现场(寄存器值)。创建任务时指定大小,单位:字(32 位 / 4 字节)

4.5 共享资源

可被多个任务同时访问的资源,如串口、Flash、IIC、SPI、全局变量。

4.6 临界区

执行过程中不希望被打断的代码段,如时序操作、打印、数据赋值。


五、FreeRTOS 任务的四种状态(核心)

任何一个任务,在任意时刻一定处于以下四种状态之一:

1. 就绪态(Ready)

  • 任务已创建
  • 等待被调度运行

2. 运行态(Running)

  • 正在占用 CPU
  • 单核 CPU 同一时间只能有一个任务运行

3. 阻塞态(Blocked)

  • 任务在等待延时、信号量、队列、事件等
  • 主动让出 CPU

4. 挂起态(Suspended)

  • 任务被 “冻结”
  • 不参与调度
  • 只能通过 vTaskResume () 唤醒

状态转换重点:

  • 调用延时 → 进入阻塞态
  • 被更高优先级抢占 → 回到就绪态
  • 调用 vTaskSuspend → 进入挂起态
  • 恢复执行 → 回到就绪态

六、FreeRTOS 任务创建完整步骤(超详细)

任务是 FreeRTOS 最基本的调度单元,我们从最底层完整讲解创建流程。

6.1 包含头文件

c

运行

#include "FreeRTOS.h"
#include "task.h"

6.2 定义任务句柄

相当于任务的 “唯一标识符”。

c

运行

TaskHandle_t xHandle_LED1 = NULL;

6.3 编写任务函数(无限循环)

任务函数规则:

  • 不能 return
  • 必须包含让出 CPU 的操作(vTaskDelay 或阻塞)

c

运行

void vTaskLED1Code( void * pvParameters )
{
    for( ;; )
    {
        LED1_Toggle();
        vTaskDelay(1000);
    }
}

6.4 使用 xTaskCreate 创建任务

c

运行

xTaskCreate(
    vTaskLED1Code,      // 任务函数
    "vTaskLED1Code",    // 任务名称(调试用)
    512,                // 堆栈大小(单位:字)
    NULL,               // 入口参数
    1,                  // 任务优先级
    &xHandle_LED1       // 任务句柄
);

6.5 启动调度器

c

运行

vTaskStartScheduler();

该函数永不返回!启动后,整个系统完全由 FreeRTOS 接管。


七、vTaskDelay 与裸机 delay_ms 的本质区别(面试必问)

这是初学者最容易踩坑、面试最高频的问题。

7.1 裸机延时 delay_ms

c

运行

void delay_ms(uint32_t ms)
{
    for(i=0;i<ms*7200;i++);
}

特点:

  • 死循环空转
  • 不释放 CPU
  • 高优先级任务使用 → 系统卡死
  • 低优先级任务完全无法运行

7.2 FreeRTOS 延时 vTaskDelay

c

运行

vTaskDelay(1000);

特点:

  • 任务进入阻塞态
  • 主动释放 CPU
  • 调度器切换到其他任务
  • 系统整体运行不受影响

一句话总结:delay_ms = 霸占 CPU****vTaskDelay = 交出 CPU


八、任务堆栈大小如何确定?

创建任务时,堆栈大小单位是 字(4 字节)

通用判断规则:

  • 简单任务:128~256
  • 涉及 LCD、printf、浮点运算:512+
  • 协议栈、网络任务:1024+

建议:

  • 初期适当开大
  • 利用调试工具查看剩余堆栈
  • 最终缩到合适大小,节约内存

九、高优先级任务如何抢占低优先级?(实验现象)

实验示例:

  • LED1 任务:优先级 1,vTaskDelay (1000)
  • LED2 任务:优先级 2,vTaskDelay (500)

实验结果:

  • LED2 优先运行
  • LED2 可以随时打断 LED1
  • 高优先级任务完全掌控系统执行权

如果高优先级任务使用裸机 delay_ms:

  • LED2 独占 CPU
  • LED1 完全无法运行
  • 系统失去响应

这就是可剥夺内核最直观、最真实的表现。


十、本篇博客总结

本篇我们完整、系统地学习了以下内容:

  • 裸机系统与 RTOS 的本质区别
  • 实时操作系统与可剥夺内核
  • FreeRTOS 基础专业术语
  • 任务的四种状态及转换
  • 任务创建完整流程
  • vTaskDelay 与裸机延时的本质区别
  • 任务堆栈设置规则
  • 优先级抢占机制与实验现象

下一篇博客,我们将继续深入:临界区保护、任务挂起 / 恢复、堆栈溢出钩子、空闲任务、调度器底层运行原理。

对于嵌入式学习者而言,本篇是 FreeRTOS 最核心、最基础、面试最高频的内容,建议收藏反复理解。