FreeRTOS 二值信号量


FreeRTOS 二值信号量

一、二值信号量的基本概念

信号量是实现任务间同步和通信的一种机制,可以类比于裸机编程中的标志位。信号量分为多种类型,包括二值信号量、计数信号量、互斥信号量和递归互斥信号量。其中,二值信号量是最简单的一种,其取值只有0和1两种状态。当信号量为0时,表示没有资源可用,所有试图获取它的任务都将处于阻塞状态;当信号量为1时,表示有资源可用,任务可以成功获取信号量并继续执行。
二值信号量可以看作是一个深度为1的队列,这个队列要么为空(信号量为0),要么为满(信号量为1)。任务在获取信号量时,如果队列为空,则任务进入阻塞状态;如果队列为满,则任务成功获取信号量并继续执行。在释放信号量时,任务将信号量放回队列,使得队列从满变为空,从而唤醒等待在该信号量上的其他任务。

二、二值信号量的运作机制

在FreeRTOS中,二值信号量的运作机制主要涉及到信号的创建、获取和释放三个过程。
创建二值信号量:使用xSemaphoreCreateBinary()函数创建一个二值信号量。该函数返回一个信号量句柄,用于后续的信号量操作。如果创建成功,信号量的初始值通常为0(表示没有资源可用)。
获取二值信号量:使用xSemaphoreTake()函数获取二值信号量。如果信号量为1(表示有资源可用),则任务成功获取信号量并继续执行;如果信号量为0(表示没有资源可用),则任务进入阻塞状态,等待直到信号量变为1。
释放二值信号量:使用xSemaphoreGive()函数释放二值信号量。释放信号量后,如果有任务在等待该信号量,则唤醒该任务并使其进入就绪状态。
此外,在中断服务程序中释放二值信号量时,应使用xSemaphoreGiveFromISR()函数。该函数允许在中断上下文中释放信号量,并处理可能的任务优先级翻转问题。

三、二值信号量的常用API函数

FreeRTOS提供了丰富的API函数来操作二值信号量,以下是一些常用的API函数及其功能:
xSemaphoreCreateBinary():创建一个二值信号量并返回其句柄。
xSemaphoreTake():尝试获取二值信号量。如果信号量为0,则任务进入阻塞状态;如果信号量为1,则任务成功获取信号量。
xSemaphoreGive():释放二值信号量。如果有任务在等待该信号量,则唤醒该任务。
xSemaphoreGiveFromISR():在中断服务程序中释放二值信号量。该函数处理可能的任务优先级翻转问题。
vSemaphoreDelete():删除一个二值信号量。该函数释放信号量所占用的资源。

四、二值信号量实例

在这个例子中,我们创建了两个优先级相同的任务,这两个任务同时访问一个串口资源。为了避免竞争条件,我们使用二进制信号量进行同步。

#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
#include "stdio.h"
SemaphoreHandle_t xSem;
void Task1Function(void *param) {
    while (1) {
        if (xSemaphoreTake(xSem, portMAX_DELAY) == pdTRUE) {
            printf("Task1\r\n");
            xSemaphoreGive(xSem);
            vTaskDelay(1);
        } else {
            printf("Task1 xSemaphoreTake is err\r\n");
        }
    }
}
void Task2Function(void *param) {
    while (1) {
        if (xSemaphoreTake(xSem, portMAX_DELAY) == pdTRUE) {
            printf("Task2\r\n");
            xSemaphoreGive(xSem);
            vTaskDelay(1);
        } else {
            printf("Task2 xSemaphoreTake is err\r\n");
        }
    }
}
int main(void) {
    xSem = xSemaphoreCreateBinary();
    xSemaphoreGive(xSem); // 初始状态设为资源可用
    
    xTaskCreate(Task1Function, "Task1", 100, NULL, 1, NULL);
    xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
    
    vTaskStartScheduler();
    
    while (1) {} // 通常不会执行到这里
    return 0;
}

在这个例子中,xSemaphoreCreateBinary()用于创建一个二进制信号量,xSemaphoreTake()用于获取信号量,xSemaphoreGive()用于释放信号量。通过信号量的同步,Task1和Task2可以交替访问串口资源,避免竞争条件。

五、二值信号量的实际应用场景

二值信号量在嵌入式系统开发中有着广泛的应用场景,以下是一些典型的例子:
任务同步:在多个任务之间实现同步操作。例如,一个任务负责数据采集,另一个任务负责数据处理。当数据采集任务完成数据采集后,通过释放二值信号量通知数据处理任务开始处理数据。
中断与任务同步:在中断服务程序与任务之间实现同步操作。例如,在串口接收中断中,当接收到数据时,通过释放二值信号量通知任务来处理接收到的数据。这样可以避免任务在轮询等待数据时浪费CPU资源。
互斥访问:虽然二值信号量主要用于同步操作,但在某些情况下也可以用于实现简单的互斥访问。然而,需要注意的是,二值信号量没有优先级继承机制,因此在处理优先级反转问题时需要谨慎使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盼海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值