FreeROTS基础学习(一)

整理了作为小白的我学FreeRTOS的笔记,希望对一些也在学习FreeRTOS的同学有所帮助。

目录

一、基础概念

1. 什么是操作系统(Operating System, OS)?

2. 操作系统有哪些?

3. 什么是FreeROTS?

4. 裸机开发与FreeROTS开发的区别:

二、FreeRTOS 的核心组成

1. 任务管理(Task Management)

2 .任务状态与生命周期(Task Status)

3.任务调度与调度器机制

4. 系统滴答

5. 上下文切换(Context Switch)

6 .空闲任务(Idle Task )与钩子函数(Hook)


一、基础概念

  • 1. 什么是操作系统(Operating System, OS)?

因为FreeRTOS是一个操作系统,所以这里先讲一下操作系统的概念;

操作系统是一种系统软件,它负责管理计算机的硬件资源,并为应用程序提供运行环境和服务。

它就像是硬件与应用程序之间的桥梁,帮助应用程序有序地使用 CPU、内存、输入输出设备等硬件资源。

当多个程序同时请求同一个资源(比如 CPU 或打印机)时,操作系统会像一个“领导”一样,通过调度算法和内存管理策略,决定哪个程序先使用资源,哪个程序要等待,从而保障系统的稳定性与效率。

  • 2. 操作系统有哪些?

操作系统按照用途分主要有两大类——通用操作系统和实时操作系统;

(1)通用操作系统(General-Purpose OS)

通用操作系统是指面向大众用户或通用计算平台设计的操作系统,主要关注多功能、用户交互体验、任务并发处理、资源管理效率。它们运行在电脑、手机、服务器等设备上,具备图形界面、文件系统、网络功能、驱动支持等复杂服务,为各种应用程序提供统一平台。主流的通用操作系统其实我们每天都会接触到,例如有我们电脑上按照的Windows、Linux、Android,以及苹果手机的IOS系统等;

(2)实时操作系统(RTOS, Real-Time OS)

实时操作系统是一种专为嵌入式设备、工业控制等应用场景设计的轻量操作系统,它强调任务响应时间的可预测性和及时性。“实时”不一定意味着“快”,而是指对时间的控制非常严格,任务必须按预定时间点完成,否则就可能导致系统失效。RTOS系统有我们今天要学的FreeRTOS,还有国产开源的RT-Thread,除这两个外,其实还有其他的RTOS系统,由于目前我还没接触到,所以这里就不班门弄斧了。

(3)以下是通用操作系统和实时操作系统的主要区别:

对比角度

通用操作系统(GPOS)

实时操作系统(RTOS)

核心目标

强调功能丰富和用户体验

强调任务按时完成,响应及时

响应速度

响应时间不确定,可能延迟

响应时间可预测、低延迟

调度机制

按公平或效率调度,不保证准时执行

按优先级或实时需求调度,可抢占调度

资源占用

功能多,资源占用大

精简设计,资源占用小

适用场景

手机、电脑、服务器等

工业控制、机器人、汽车等对时效敏感场景

  • 3. 什么是FreeROTS?

好,上文已经提到了RTOS的概念,那接下来正式开始我们要学习的内容重要基础概念——FreeRTOS是什么?

 FreeRTOS英文全称是Free Real-Time Operating System,它是一个轻量级、开源的实时操作系统,常用于嵌入式系统,它提供了任务调度、多任务并行、任务间通讯、资源管理等功能,适用于复杂的嵌入式应用场景。 

在执行程序时,如果你使用 FreeRTOS ,它会通过调度器管理这些任务的运行时间,自动切换任务(例如 A 任务等 I/O 的时候,切换执行 B 任务),并且提供了通信与同步机制(信号量、队列等),所以FreeRTOS 可以让你写的 MCU 程序变得有组织、能多任务并发、响应及时。

  • 4. 裸机开发与FreeROTS开发的区别:

裸机开发是指不依赖操作系统,直接在硬件上编写和运行代码的编程方式,一切任务执行顺序、时机、优先级 —— 都是靠你手写代码来控制的。你写什么就执行什么,你写在哪儿它就在哪儿执行,想延时就用 delay() 函数,但一延时就整个程序停在那里。

下面,通过以下2个示例来说明裸机编程和FreeRTOS编程的区别:

1. 裸机编程示例(阻塞式执行)

#include <stdio.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

void app_main() {
    while (1) {
        ESP_LOGI("TASK", "任务A:读取温湿度传感器");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 任务A执行1秒

        ESP_LOGI("TASK", "任务B:发送数据到串口");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 任务B执行1秒
    }
}
//在这个代码中,任务 A 执行完再到任务 B,中途所有人都必须等当前任务完成,无法并发,延迟会影响系统响应;

2. FreeRTOS 示例(多任务并发):

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

void task_A(void *pvParameters) {
    while (1) {
        printf("任务A:读取温湿度传感器\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1秒,不会阻塞其他任务
    }
}

void task_B(void *pvParameters) {
    while (1) {
        printf("任务B:发送数据到串口\n");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void app_main() {
    xTaskCreate(task_A, "Task A", 2048, NULL, 1, NULL);
    xTaskCreate(task_B, "Task B", 2048, NULL, 1, NULL);
}
//两个任务交替运行,看起来是“同时”执行,实际上是由 FreeRTOS 调度器轮流让任务占用 CPU,响应更快,也更高效;

想象一下这是一个接力赛:

在裸机编程中,只有一个人能拿接力棒跑,必须等他(Task A)跑完并休息够了,接力棒才能交给下一个人(Task B)。其他人全程干等着,不管有没有更重要的事情要做。

而在FreeRTOS中,有一个“智能裁判”负责控制每个人轮流接棒,每个选手(Task)只能跑一小段时间(比如10毫秒),然后裁判就把接力棒换给下一个人。这样每个任务看似是在同时进行,但实际上只有一个人在跑步,但因为切换得很快,我们几乎察觉不到交接。

所以说,FreeRTOS 提供了一种“伪并发”机制,让多个任务井然有序地共享 CPU,提高系统响应速度,避免一个任务卡住拖慢整体。

  • 5.FreeRTOS特点

上文对比了裸机开发和FreeRTOS的区别,相信你对它已经有大概的了解了,这里,再详细讲一下FreeRTOS的特点;

(1)轻量级,资源占用小

FreeRTOS 的内核代码非常小(通常 10~20KB 左右)。非常适合资源有限的嵌入式系统,比如 STM32、ESP32、ARM Cortex-M 系列等。

(2)实时性强

FreeRTOS支持抢占式调度,能及时响应高优先级任务。当有紧急任务时,低优先级任务会被立刻“打断”,系统能保证关键任务及时完成;

(3)多任务管理

可以同时管理多个任务(Task),每个任务像一个独立的小程序,开发更容易维护。

(4) 优先级调度

你可以设置任务的优先级,调度器根据优先级选择哪个任务先运行。高优先级任务随时都可以抢占低优先级任务。

(5) 任务间通信机制丰富

支持:队列(Queue)、信号量(Semaphore)、消息通知、事件组(Event Group)等。任务之间协作和共享数据更安全、更可靠。

(6) 可移植性强

FreeRTOS 是高度可移植的,能跑在上百种芯片和架构上(ARM、RISC-V、ESP32 等)。

以上这些特点,使得FreeRTOS成为当下最受欢迎的RTOS,毕竟——打个不恰当的比方,它就像是一个拿着很低月薪但是还要替老板统筹规划、让整个公司运作得井然有序的员工,哪个老板能拒绝呢?(开个玩笑)

二、FreeRTOS 的核心组成

  • 1. 任务管理(Task Management)

任务(Task)是 FreeRTOS 中的最小执行单位,类似于“线程”。每个任务都是我们写的一个函数,FreeRTOS 会负责调度它们运行。

FreeRTOS并不是真正的让多任务同时运行,而是是通过“时间片轮转 + 优先级”快速切换任务,只是看起来像同时运行。

在ESP32中,我们使用 xTaskCreate() 函数来创建任务:

xTaskCreate(TaskFunction,    // 参数1:任务函数;
            "Task1",         // 参数2:任务函数的别名;
            1024,            // 参数3:任务函数运行时的栈大小(注意不是字节)
            NULL,            // 参数4:传给任务函数的参数;
            1,               // 参数5:任务函数的优先级,最高优先级是 (configMAX_PRIORITIES - 1);
            NULL);           // 参数6:任务句柄;
  • 2 .任务状态与生命周期(Task Status)

FreeRTOS 中的任务在运行过程中不是一直处于“运行”状态,而是会根据资源占用情况、时间、事件等在多个状态之间切换。一共有 5 种主要状态:

(1)Created(已创建)

通过 xTaskCreate() 创建后,任务最开始是处于created的状态,如果调度器尚未启动(vTaskStartScheduler()),任务不会立即运行,一旦调度器启动,任务状态转为 Ready;

(2)Ready(就绪)

表示任务已准备好运行,只等着调度器分配 CPU,有多个任务处于就绪态时,调度器会选取最高优先级的任务运行;

(3)Running(运行)

表示任务当前正在使用 CPU,FreeRTOS 是抢占式内核,高优先级任务可以随时打断低优先级任务,同优先级任务之间采用“时间片轮转”机制;

(4)Blocked(阻塞)

如果任务当前正在等待延时或外部事件,则该任务视为处于阻塞状态。就像是任务主动要“休息一段时间”了:比如当我们调用了:

  • vTaskDelay()(延时一段时间);

  • xQueueReceive()(等待队列数据);

  • xSemaphoreTake()(等待信号量);

被阻塞的任务不参与调度器的调度,释放 CPU 给其它任务,阻塞时间结束(如延时完毕,或数据到达)后任务转为 Ready;

(5)Suspended(挂起)

表示任务被“冻结”了,不会运行也不会被调度,需要我们手动调用:

vTaskSuspend(TaskHandle_t handle); // 挂起

vTaskResume(TaskHandle_t handle); // 恢复,调用后才可以进入就绪状态;

挂起态不依赖时间,也不会自动恢复,适合你需要手动控制某任务是否激活的场景(如节电模式)。

  • 3.任务调度与调度器机制

调度器(Scheduler)决定了某个特定时刻执行哪个任务,并在任务之间切换。

(1)FreeRTOS默认使用固定优先级的抢占式调度策略,即高优先级任务一旦就绪,会立即打断低优先级任务,获取CPU。这样使得实时性更强,更适用于对时间敏感的场景;

(2)对于同优先级的任务,采用时间片轮转调度(Round Robin Scheduling),它是指当多个任务优先级相同时,FreeRTOS 会让每个任务轮流运行一小段时间(称为一个“时间片”),从而实现“公平调度”。时间片的长度由系统“滴答定时器”控制,默认情况下,每到一个系统滴答(一般为1ms或10ms),调度器就会判断是否要切换任务,如果当前的任务执行时间到了,那就切换到下一个同优先级的任务;

FreeRTOS 调度器的决策顺序:

①优先级不同:等级越高的就绪任务,调度器越优先选它执行。

比如有优先级 3 和优先级 1 的任务都就绪,调度器一定选优先级 3 的任务;

②优先级相同:时间片轮转调度”让它们轮流执行。每个任务获得一个固定的“时间片”(一个或多个 tick),用完就轮到下一个同等优先级的任务;

③任务状态变化触发调度器重新决策:以下情况会触发重新决策:

  • 系统 Tick 中断:每次 Tick 到,判断是否需要切换任务;

  • 任务调用 vTaskDelay()、taskYIELD():当前任务主动让出 CPU;

  • 有任务被唤醒(如中断唤醒、信号量释放):调度器会立即检查是否有更高优先级的任务要抢占;

  • 调用 xTaskCreate() 创建了新任务:调度器会立刻评估新任务是否抢占:

关于调度器的启动与关闭:启动调度器的函数是:vTaskStartScheduler();一旦启动,FreeRTOS 就开始自动管理任务运行;FreeRTOS 通常不支持手动关闭调度器(除非特殊配置)

  • 4. 系统滴答

(1)Tick(滴答)是FreeRTOS中一个定时节拍,由硬件定时器周期性触发。Tick 通常以固定的时间间隔发生,例如 1ms、10ms 等,这个时间间隔叫做 Tick Rate,用 configTICK_RATE_HZ 来配置。

假设我们创建了一个任务:vTaskDelay(100);

如果 configTICK_RATE_HZ = 1000,则表示 1ms 一次 Tick,100*1ms=100ms,所以这个任务就会被阻塞 100ms,也就是 等 100 个 Tick。

(2)Tick 的来源(硬件定时器):

①在 ARM Cortex-M 等芯片中,Tick 通常由 SysTick 定时器产生;

②在 ESP32 中,Tick 通常由系统定时器或 Timer Group 产生中断。

(3)每一次“滴答"发生时,FreeRTOS的调度器就有机会检查是否有任务状态发生变化,比如:

  • 有任务延时结束,转为就绪状态;

  • 时间片轮转到下一个任务;

  • 执行调度(上下文切换);

  • 5. 上下文切换(Context Switch)

(1)上下文切换是指操作系统暂停当前正在运行的任务,把CPU交给另外一个任务运行的过程。在这个过程中,FreeRTOS会做2件事:

① 保存当前任务的上下文(寄存器、堆栈等),以便以后能恢复继续执行;

② 恢复新任务的上下文,让它从上次暂停的地方继续运行;

(2)上下文包含什么?

  • ① CPU 寄存器:比如 PC(程序计数器)、SP(堆栈指针)、R0~R15 等;

  • ② 堆栈指针:当前任务的局部变量、返回地址等保存在任务栈中;

  • ③ PSW(程序状态字):用于标记任务当前的运行状态、优先级等;

FreeRTOS 使用每个任务的“任务栈”来保存这些上下文。

(3) 何时发生上下文切换?

①新任务唤醒且优先级更高时:比如中断唤醒了高优先级任务,当前任务会被打断切换;

②任务主动让出 CPU:比如调用 taskYIELD();

③当前任务进入阻塞/延时:比如调用 vTaskDelay() 后不再就绪,切换至其他就绪任务;

④Tick 中断触发,时间片到:同优先级任务使用完时间片后,轮换执行;

(4)上下文切换的性能开销大吗?

每次切换都需要保存/恢复上下文,存在时间开销(几十us到几百us,取决于架构);如果频繁切换会带来“任务切换负担”,影响实时性和效率,所以 FreeRTOS 推荐尽量不要让任务频繁主动让出 CPU(例如空转 taskYIELD())。

  • 6 .空闲任务(Idle Task )与钩子函数(Hook)

(1)在FreeRTOS中,空闲任务是系统自动创建的一个特殊任务,用来确保始终存在一个能够运行的任务;

空闲任务优先级最低(默认为0),当没有其他就绪任务可以运行时,FreeRTOS 调度器就会调度空闲任务来运行;

空闲任务是启动调度器时由系统生成的,不需要你手动创建。它相当于“最后一个候补选手”,当其他任务都在休息或被阻塞时,它就上来占用 CPU,保证系统处于活动状态。

空闲任务可用于资源回收,你删除任务时,它负责清理被删除任务分配的堆栈资源;

空闲任务还可用来定义钩子函数,可以设置空闲任务钩子(vApplicationIdleHook())做低功耗处理或后台任务;

(2)空闲任务钩子函数(Idle Hook) 是什么?

首先,钩子函数(Hook Function)是指你提前定义好的一段函数代码,系统在某个特定时刻自动“调用”你这段代码;钩子函数是回调机制的一种,你不需要手动调用它,系统在某个“时间点”或“事件点”会自动调用,你只要“挂钩”上去(hook),它就会在合适时机被调用。

那空闲任务钩子函数指的是挂在空闲任务里的钩子函数。你可以选择写一段函数,FreeRTOS 会在空闲任务每次运行时自动调用你写的那段函数。

如果把Idle Task 比作一个“保安值班”,没活干时他在岗待命。那 Idle Hook 就像你在保安上岗时给他附带的“备忘清单”——“你要是闲着,就扫扫地、打个日志、测个温湿度什么的。”

(笔记整理中......)

### FreeRTOS 简介与学习资源 FreeRTOS款开源免费的实时操作系统,遵循 GPLv2+ 的许可协议[^1]。用户可以免费获取其源代码,并在未修改内核源码的情况下将产品闭源。如果对 FreeRTOS 内核进行了修改,则需要将修改部分开源并反馈给社区。 #### FreeRTOS 学习资料 关于 FreeRTOS学习资料,可以通过以下途径获取: - **官方文档**:FreeRTOS 官方网站提供了详尽的文档和示例代码,适合初学者入门。 - **教程推荐**:引用中的教程内容详细介绍了 FreeRTOS基础知识以及任务间通信机制(如队列的使用)[^2][^3]。 - **GitHub 仓库**:通过 GitHub 搜索 FreeRTOS,可以找到许多由开发者维护的项目和教程,例如 Despacito0o/FreeRTOS[^3]。 #### FreeRTOS 下载方法 FreeRTOS 的下载可以通过以下方式实现: - **官方网站**:访问 [FreeRTOS 官方网站](https://www.freertos.org/) 并下载最新版本的源代码。 - **GitHub 仓库**:FreeRTOS 的源代码托管在 [GitHub](https://github.com/FreeRTOS) 上,用户可以根据需求选择合适的分支进行克隆或下载。 #### FreeRTOS 使用方法 FreeRTOS 的使用通常包括以下几个方面: 1. **环境搭建**:根据目标硬件平台(如 STM32),利用开发工具(如 STM32CubeMX)生成基础工程。 2. **任务管理**:创建、启动和管理任务是 FreeRTOS 的核心功能之。例如,通过 `xTaskCreate` 函数创建任务[^2]。 ```c void vTaskCode(void *pvParameters) { for (;;) { // 任务逻辑 } } xTaskCreate(vTaskCode, "TaskName", configSTACK_DEPTH, NULL, tskIDLE_PRIORITY, NULL); ``` 3. **任务间通信**:FreeRTOS 提供了多种通信机制,其中队列是最常用的种。例如,创建个队列并发送数据。 ```c QueueHandle_t xQueue = xQueueCreate(10, sizeof(uint32_t)); xQueueSend(xQueue, (void *)&data, portMAX_DELAY); ``` #### 注意事项 - 如果使用 CMSIS-RTOS 封装的 API,需注意其与原生 FreeRTOS API 的区别[^2]。 - 在实际应用中,建议结合硬件平台的特性优化 FreeRTOS 的配置参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值