Skip to content

FreeRTOS 的信号量

关于信号量的使用

  • 二值信号量: 二值信号量是一种最简单的信号量,它只有两个状态,即已上锁和未上锁。
  • 互斥信号量: 互斥信号量是一种高级信号量,它可以实现多个任务对同一资源的互斥访问。
  • 递归信号量: 递归信号量是一种高级信号量,它可以实现多个任务对同一资源的递归访问。
  • 计数信号量: 计数信号量是一种高级信号量,它可以实现多个任务对同一资源的并发访问。
  • 事件标志组: 事件标志组是一种高级信号量,它可以实现多个任务对同一事件的并发访问。
  • 队列: 队列是一种高级信号量,它可以实现多个任务对同一资源的并发访问。

1. 二值信号量的使用

  • 二值信号量的使用方法如下:
  1. 创建信号量:
  2. 获取信号量:
  3. 释放信号量:
  4. 删除信号量:
  • 举例代码:
c
#include "FreeRTOS.h"
#include "semphr.h"

SemaphoreHandle_t xSemaphore;

void vTask1(void *pvParameters)
{
    while (1)
    {
        // 获取信号量
        if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE)
        {
            // 信号量获取成功,执行任务
            // ...
            // 释放信号量
            xSemaphoreGive(xSemaphore);
        }
        else
        {
            // 信号量获取失败,执行其他任务
            // ...
        }
    }
}

void vTask2(void *pvParameters)
{
    while (1)
    {
        // 获取信号量
        if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE)
        {
            // 信号量获取成功,执行任务
            // ...
            // 释放信号量
            xSemaphoreGive(xSemaphore);
        }
        else
        {
            // 信号量获取失败,执行其他任务
            // ...
        }
    }
}

int main(void)
{
    // 创建二值信号量
    xSemaphore = xSemaphoreCreateBinary();

    // 创建任务1
    xTaskCreate(vTask1, "Task1", 256, NULL, 1, NULL);

    // 创建任务2
    xTaskCreate(vTask2, "Task2", 256, NULL, 2, NULL);

    // 启动任务调度器
    vTaskStartScheduler();

    return 0;
}

- 典型应用:
有两个任务需要同步时,可以使用二值信号量来实现。是一个任务完成后,释放信号量,另一个任务获取信号量,继续执行。比如在串口通讯中,我们经常需要在发送完串口数据后,等待接收对方传过来的数据.但是数据的接收可以使用非阻塞的回调函数来实现,这就造成一个问题,当发送完数据后,数据的接收是在另一个线程里接收的,当前的发送数据的线程怎么知道数据接收完成呢?这就需要使用二值信号量来实现同步。
- 创建二值信号量:
```c
SemaphoreHandle_t xSemaphore;
xSemaphore = xSemaphoreCreateBinary();
  • 获取信号量:
c
if(xSemaphoreTake(xSettingSemaphore, (TickType_t)1000) == pdTRUE){
    // 信号量获取成功
}
else
{
    // 信号量获取失败,或是超时
}
  • 在接收线程中,如果收到数据,就会释放信号量:
c
xSemaphoreGive(xSettingSemaphore);

这样就实现的了两个任务之间的同步。