目录

概述

1 信号量概述

2 FreeRTOS信号量类型

2.1 二进制信号量(Binary Semaphore)

2.2 计数信号量(Counting Semaphore)

2.3 互斥信号量(Mutex)

2.4 递归互斥量(Recursive Mutex)

3 信号量API函数详解

3.1 创建信号量

3.2 获取/释放信号量

3.3 中断服务程序中的信号量操作

3.4 其他函数

4 使用示例

4.1 二进制信号量示例:任务同步

4.2 计数信号量示例:资源池管理

4.3 互斥量示例:保护共享资源

4.4 递归互斥量示例

4.5 ISR中使用信号量


概述

FreeRTOS中信号量是用于任务间同步和资源管理的重要机制。信号量分为二进制信号量、计数型信号量和互斥信号量(互斥锁)。下面将详细说明它们的使用方法。

1 信号量概述

信号量是FreeRTOS中用于任务间同步和互斥的重要机制,主要用于:

  1. 任务同步:通知某个事件发生

  2. 资源管理:控制对共享资源的访问

  3. 任务通信:在任务间传递状态信息

信号量选择原则

场景 推荐信号量类型
任务同步 二进制信号量
资源计数 计数信号量
保护共享资源 互斥量
任务可能多次获取同一锁 递归互斥量

2 FreeRTOS信号量类型

2.1 二进制信号量(Binary Semaphore)

  • 只有0和1两种状态

  • 常用于任务同步

2.2 计数信号量(Counting Semaphore)

  • 计数器值可以从0到最大值

  • 用于管理多个相同的资源

2.3 互斥信号量(Mutex)

  • 特殊的二进制信号量

  • 具有优先级继承机制,防止优先级反转

2.4 递归互斥量(Recursive Mutex)

  • 允许同一任务多次获取锁

  • 必须释放相同次数才能完全解锁

3 信号量API函数详解

3.1 创建信号量

/* 创建二进制信号量 */
SemaphoreHandle_t xSemaphoreCreateBinary(void);

/* 创建计数信号量 */
SemaphoreHandle_t xSemaphoreCreateCounting(
    UBaseType_t uxMaxCount,     /* 最大计数值 */
    UBaseType_t uxInitialCount   /* 初始计数值 */
);

/* 创建互斥量 */
SemaphoreHandle_t xSemaphoreCreateMutex(void);

/* 创建递归互斥量 */
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void);

3.2 获取/释放信号量

/* 获取信号量(阻塞) */
BaseType_t xSemaphoreTake(
    SemaphoreHandle_t xSemaphore,  /* 信号量句柄 */
    TickType_t xTicksToWait        /* 超时时间 */
);

/* 获取信号量(非阻塞) */
xSemaphoreTake(xSemaphore, 0);

/* 获取信号量(无限等待) */
xSemaphoreTake(xSemaphore, portMAX_DELAY);

/* 释放信号量 */
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);

/* 获取递归互斥量 */
BaseType_t xSemaphoreTakeRecursive(
    SemaphoreHandle_t xMutex,
    TickType_t xTicksToWait
);

/* 释放递归互斥量 */
BaseType_t xSemaphoreGiveRecursive(SemaphoreHandle_t xMutex);

3.3 中断服务程序中的信号量操作

/* 在ISR中释放信号量 */
BaseType_t xSemaphoreGiveFromISR(
    SemaphoreHandle_t xSemaphore,
    BaseType_t *pxHigherPriorityTaskWoken
);

/* 在ISR中获取信号量 */
BaseType_t xSemaphoreTakeFromISR(
    SemaphoreHandle_t xSemaphore,
    BaseType_t *pxHigherPriorityTaskWoken
);

3.4 其他函数

/* 删除信号量 */
void vSemaphoreDelete(SemaphoreHandle_t xSemaphore);

/* 获取信号量计数值 */
UBaseType_t uxSemaphoreGetCount(SemaphoreHandle_t xSemaphore);

4 使用示例

4.1 二进制信号量示例:任务同步

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/* 定义信号量句柄 */
SemaphoreHandle_t xBinarySemaphore;

/* 任务1:等待事件 */
void vTask1(void *pvParameters)
{
    for(;;)
    {
        /* 等待信号量 */
        if(xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE)
        {
            /* 收到信号量,执行相应操作 */
            printf("Task1: Event received!\n");
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}

/* 任务2:触发事件 */
void vTask2(void *pvParameters)
{
    for(;;)
    {
        /* 每隔1秒触发一次事件 */
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        
        /* 释放信号量 */
        xSemaphoreGive(xBinarySemaphore);
        printf("Task2: Event triggered!\n");
    }
}

/* 主函数 */
int main(void)
{
    /* 创建二进制信号量,初始值为0 */
    xBinarySemaphore = xSemaphoreCreateBinary();
    
    if(xBinarySemaphore != NULL)
    {
        /* 创建任务 */
        xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
        xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
        
        /* 启动调度器 */
        vTaskStartScheduler();
    }
    
    /* 如果调度器启动失败,会执行到这里 */
    for(;;);
}

4.2 计数信号量示例:资源池管理

/* 模拟有3个可用资源 */
#define MAX_RESOURCES 3

SemaphoreHandle_t xCountingSemaphore;

/* 资源使用者任务 */
void vResourceUserTask(void *pvParameters)
{
    char *pcTaskName = (char *)pvParameters;
    
    for(;;)
    {
        /* 请求资源 */
        printf("%s: Requesting resource...\n", pcTaskName);
        
        if(xSemaphoreTake(xCountingSemaphore, portMAX_DELAY) == pdTRUE)
        {
            /* 获取到资源,使用一段时间 */
            printf("%s: Got resource, using...\n", pcTaskName);
            vTaskDelay(500 / portTICK_PERIOD_MS);
            
            /* 释放资源 */
            xSemaphoreGive(xCountingSemaphore);
            printf("%s: Released resource\n", pcTaskName);
        }
        
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

int main(void)
{
    /* 创建计数信号量,初始有3个资源可用 */
    xCountingSemaphore = xSemaphoreCreateCounting(MAX_RESOURCES, MAX_RESOURCES);
    
    if(xCountingSemaphore != NULL)
    {
        /* 创建多个资源使用者任务 */
        xTaskCreate(vResourceUserTask, "User1", configMINIMAL_STACK_SIZE, 
                   "User1", 1, NULL);
        xTaskCreate(vResourceUserTask, "User2", configMINIMAL_STACK_SIZE, 
                   "User2", 1, NULL);
        xTaskCreate(vResourceUserTask, "User3", configMINIMAL_STACK_SIZE, 
                   "User3", 1, NULL);
        xTaskCreate(vResourceUserTask, "User4", configMINIMAL_STACK_SIZE, 
                   "User4", 1, NULL);
        
        vTaskStartScheduler();
    }
    
    for(;;);
}

4.3 互斥量示例:保护共享资源

#include <stdio.h>

/* 共享资源 */
int iSharedVariable = 0;
SemaphoreHandle_t xMutex;

/* 任务:访问共享资源 */
void vAccessSharedResource(void *pvParameters)
{
    char *pcTaskName = (char *)pvParameters;
    int iLocalCopy;
    
    for(;;)
    {
        /* 获取互斥锁 */
        if(xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE)
        {
            /* 临界区开始 */
            iLocalCopy = iSharedVariable;
            printf("%s: Read value = %d\n", pcTaskName, iLocalCopy);
            
            vTaskDelay(50 / portTICK_PERIOD_MS); /* 模拟处理时间 */
            
            iLocalCopy++;
            iSharedVariable = iLocalCopy;
            printf("%s: Updated value = %d\n", pcTaskName, iSharedVariable);
            /* 临界区结束 */
            
            /* 释放互斥锁 */
            xSemaphoreGive(xMutex);
        }
        
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}

int main(void)
{
    /* 创建互斥量 */
    xMutex = xSemaphoreCreateMutex();
    
    if(xMutex != NULL)
    {
        /* 创建两个任务同时访问共享资源 */
        xTaskCreate(vAccessSharedResource, "TaskA", configMINIMAL_STACK_SIZE, 
                   "TaskA", 2, NULL);
        xTaskCreate(vAccessSharedResource, "TaskB", configMINIMAL_STACK_SIZE, 
                   "TaskB", 1, NULL);
        
        vTaskStartScheduler();
    }
    
    for(;;);
}

4.4 递归互斥量示例

SemaphoreHandle_t xRecursiveMutex;

void vRecursiveFunction(int depth)
{
    char buffer[50];
    
    /* 获取递归锁 */
    if(xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY) == pdTRUE)
    {
        sprintf(buffer, "Depth %d: Got lock", depth);
        printf("%s\n", buffer);
        
        if(depth < 3)
        {
            /* 递归调用 */
            vRecursiveFunction(depth + 1);
        }
        
        /* 释放递归锁 */
        xSemaphoreGiveRecursive(xRecursiveMutex);
        sprintf(buffer, "Depth %d: Released lock", depth);
        printf("%s\n", buffer);
    }
}

void vRecursiveTask(void *pvParameters)
{
    for(;;)
    {
        vRecursiveFunction(1);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

int main(void)
{
    xRecursiveMutex = xSemaphoreCreateRecursiveMutex();
    
    if(xRecursiveMutex != NULL)
    {
        xTaskCreate(vRecursiveTask, "RecTask", configMINIMAL_STACK_SIZE, 
                   NULL, 1, NULL);
        vTaskStartScheduler();
    }
    
    for(;;);
}

4.5 ISR中使用信号量

/* 定义信号量句柄 */
SemaphoreHandle_t xSemaphoreFromISR;

/* 中断服务程序 */
void vExampleInterruptHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    /* 在ISR中释放信号量 */
    xSemaphoreGiveFromISR(xSemaphoreFromISR, &xHigherPriorityTaskWoken);
    
    /* 如果需要任务切换 */
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

/* 任务:处理中断事件 */
void vISRHandlerTask(void *pvParameters)
{
    for(;;)
    {
        /* 等待来自ISR的信号量 */
        if(xSemaphoreTake(xSemaphoreFromISR, portMAX_DELAY) == pdTRUE)
        {
            /* 处理中断事件 */
            printf("ISR event handled in task\n");
        }
    }
}

int main(void)
{
    /* 创建二进制信号量 */
    xSemaphoreFromISR = xSemaphoreCreateBinary();
    
    if(xSemaphoreFromISR != NULL)
    {
        /* 配置中断 */
        // configure_interrupt();
        
        /* 创建处理任务 */
        xTaskCreate(vISRHandlerTask, "ISRHandler", configMINIMAL_STACK_SIZE, 
                   NULL, 3, NULL);
        
        vTaskStartScheduler();
    }
    
    for(;;);
}

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐