FreeRTOS信号量使用详解
FreeRTOS中信号量是用于任务间同步和资源管理的重要机制。信号量分为二进制信号量、计数型信号量和互斥信号量(互斥锁)。下面将详细说明它们的使用方法。
·
目录
概述
FreeRTOS中信号量是用于任务间同步和资源管理的重要机制。信号量分为二进制信号量、计数型信号量和互斥信号量(互斥锁)。下面将详细说明它们的使用方法。
1 信号量概述
信号量是FreeRTOS中用于任务间同步和互斥的重要机制,主要用于:
任务同步:通知某个事件发生
资源管理:控制对共享资源的访问
任务通信:在任务间传递状态信息
信号量选择原则
| 场景 | 推荐信号量类型 |
|---|---|
| 任务同步 | 二进制信号量 |
| 资源计数 | 计数信号量 |
| 保护共享资源 | 互斥量 |
| 任务可能多次获取同一锁 | 递归互斥量 |
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(;;);
}
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐



所有评论(0)