FreeRTOS的任务(Task)与信号量(Semphaoretake)互斥

一直以来,对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,串行通信等,则它们可能会互相干扰。如果可能发生这种情况,那么必须将任务同步(在协调的意义上,而不是同时)

#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() {
}