一直以来,对FreeRTOS的使用与教程看了好多个系列教程,操作了很多原始代码,都没有很好的理解与掌握。今天终于全面理解了这几个东西的作用与使用方法了,并将它们进行了极简单化的改造并跑了起来。
一、它们之间的关系:
在FreeRTOS中队列(Queue)、信号量(Semaphore)、任务(Task)是核心组件,但他们设计目标、功能、任务、使用场景截然不同,不能随意互换。在 FreeRTOS 中,队列(Queue)、信号量(Semaphore)和任务(Task)是核心组件,但它们的设计目标、功能和使用场景截然不同,不能随意相互替换。以下是具体分析:
- 1. 核心区别
- (1)任务(Task)
- • 本质:是操作系统调度的基本单位,是一段独立运行的代码(函数),拥有自己的栈空间和运行状态(就绪、运行、阻塞等)。
- • 作用:负责实现具体的业务逻辑(如数据处理、设备控制等),是系统功能的实际执行者。
- • 特点:由 FreeRTOS 调度器管理,可根据优先级抢占 CPU 资源;任务之间相对独立,通过内核对象(队列、信号量等)通信。
- (2)队列(Queue)
- • 本质:是一种数据缓冲区,用于在任务之间(或任务与中断之间)传递数据(如数值、结构体、指针等)。
- • 作用:实现任务间的数据交换,支持异步通信(发送方无需等待接收方立即处理)。
- • 特点:
- ◦ 采用 FIFO(先进先出)机制,也可配置为 LIFO(后进先出);
- ◦ 数据通过“拷贝”方式传递(避免指针引用的安全性问题);
- ◦ 可设置阻塞时间(发送/接收数据时,若队列满/空,任务可阻塞等待)。
- (3)信号量(Semaphore)
- • 本质:是一种同步/互斥机制,本质是一个“计数器”或“标志位”,不传递具体数据,仅用于传递“事件发生”的信号。
- • 作用:
- ◦ 同步:协调多个任务的执行顺序(如任务 A 完成后通知任务 B 开始);
- ◦ 互斥:保护共享资源(如同一时间只允许一个任务访问硬件设备);
- ◦ 计数:限制同时访问某资源的任务数量(如有限的缓冲区资源)。
- • 分类:
- ◦ 二值信号量(0 或 1,用于互斥或简单同步);
- ◦ 计数信号量(计数器,用于资源计数);
- ◦ 递归信号量(允许同一任务多次获取,避免死锁)。
二、在 FreeRTOS(以及大多数实时操作系统 RTOS)中,任务(Task)必须包含一个无限循环(while(1)或类似结构),否则任务会 立即执行完并退出,导致 任务被 FreeRTOS 自动删除,甚至可能引发 系统不稳定或崩溃。
以下是最简单的示例代码了:注:必须有 vTaskDelete(NULL);
#include <Arduino.h> // 必须!用于 Serial 和 setup()/loop()
#include <FreeRTOS.h> // 必须!用于 FreeRTOS 函数
#include <task.h> // 必须!用于任务相关定义
#include <stdio.h> // 可选!用于 printf(但 Arduino 的 Serial 更常用)
void setup() {
Serial.begin(115200);
xTaskCreate(
blink1, "Blink 1", 8192, NULL, 1, NULL);
xTaskCreate(
blink2, "Blink 2", 8192, NULL, 1, NULL);
}
void blink1(void *parameter) {
printf("this is task_1\n");
vTaskDelay(pdMS_TO_TICKS(1000)); // FreeRTOS 延迟 500ms
vTaskDelete(NULL);
}
void blink2(void *parameter) {
printf("this is task_2\n");
vTaskDelay(pdMS_TO_TICKS(5000)); // FreeRTOS 延迟 500ms
vTaskDelete(NULL);
}
void loop() {
}
三、FreeRTOS信号量(Semaphoretake) 与互斥
如果任务访问相同的资源,例如外部传感器,EEPROM,ADC,串行通信等,则它们可能会互相干扰。如果可能发生这种情况,那么必须将任务同步(在协调的意义上,而不是同时)
以下是最简单的形式的信号量互斥上锁,实现两个printf同时输出结果:意义是在保证blink1、blink2任务在输出printf(“this is task_1_%d\n”, i)、printf(“this is task_2_%d\n”, i)时,将处理器上锁实现互斥(其真正意义在于:现实当中读取传感器时,不受其它任务影响)
#include <Arduino.h> // 必须!用于 Serial 和 setup()/loop()
#include <FreeRTOS.h> // 必须!用于 FreeRTOS 函数
#include <freertos/task.h> // 必须!用于任务相关定义(如 xTaskCreate)
#include <freertos/semphr.h> // 必须!用于信号量(SemaphoreHandle_t, xSemaphoreCreateBinary)
SemaphoreHandle_t sem; // Create semaphore handle
void setup() {
Serial.begin(115200);
sem = xSemaphoreCreateBinary(); // Create binary semaphore
xSemaphoreGive(sem);
xTaskCreate(
blink1, "Blink 1", 2048, NULL, 1, NULL);
xTaskCreate(
blink2, "Blink 2", 2048, NULL, 1, NULL);
}
void blink1(void *parameter) {
while (1) {
for (int i = 0; i < 10; i++) {
xSemaphoreTake(sem, portMAX_DELAY);
printf("this is task_1_%d\n", i);
xSemaphoreGive(sem);
vTaskDelay(pdMS_TO_TICKS(1000)); // FreeRTOS 延迟 500ms
}
}
vTaskDelete(NULL);
}
void blink2(void *parameter) {
while (1) {
for (int i = 0; i < 10; i++) {
xSemaphoreTake(sem, portMAX_DELAY);
printf("this is task_2_%d\n", i);
xSemaphoreGive(sem);
vTaskDelay(pdMS_TO_TICKS(1000)); // FreeRTOS 延迟 500ms
}
}
vTaskDelete(NULL);
}
void loop() {
}