FreeRTOS 信号量使用教程
FreeRTOS 中的信号量是一种同步机制,用于在任务之间共享资源或控制对共享资源的访问。信号量可以用来防止多个任务同时访问共享资源,从而避免竞态条件和数据损坏。
在 FreeRTOS 中,信号量可以是二进制的(只能取 0 或 1)或计数器的(可以取多个值)。信号量的类型由开发者根据应用程序的需求来选择。本文将详细介绍如何在 FreeRTOS 中定义、创建和使用信号量。
1. 定义信号量句柄
首先,我们需要定义一个信号量句柄,以便在后续的操作中引用互斥量:
static xSemaphoreHandle semaphHandle = NULL;
2. 解决 xSemaphoreHandle 找不到定义的问题
如果在代码中发现 xSemaphoreHandle
报红 X,提示未定义,需要包含 FreeRTOS 提供的头文件:
#include "semphr.h"
这样就可以消除错误,继续编写代码。
3. 创建二值信号量
接下来,创建一个二值信号量:
void createBinarySemaph(void)
{
if (semaphHandle == NULL)
{
vSemaphoreCreateBinary(semaphHandle);
}
}
4. 创建释放信号量的线程
定义一个任务,用于释放信号量:
5. 创建接收信号量的线程
定义另一个任务,用于接收信号量:
6. 验证信号量超时
上述步骤 4 和 5 的线程设计中,在任务中接收信号量时,理论上应能获取到一次信号量,然后两次没有获取到信号量,将代码烧写到设备后验证预期:
7. 使用中断服务程序 (ISR) 版本的信号量函数
在中断服务程序中,同样可以使用信号量,但需要使用带有 FromISR
后缀的函数:
xSemaphoreGiveFromISR(semaphHandle, &pxHigherPriorityTaskWoken);
xSemaphoreTakeFromISR(semaphHandle, &pxHigherPriorityTaskWoken);
其中第二个参数是表明接收线程是否需要优先执行(线程优先级反转)
注意
如果在二值信号量正在处理中,又有中断触发信号量,则可能会丢失信号量,因为二值信号量只能表示“空”或“非空”的状态。
可以通过代码模拟这种情况看看是否回丢失信号量:
接收信号量的线程实现跟步骤 5 保持一致,烧写后验证如下:
为了解决这个问题,可以使用计数信号量。
使用计数信号量
8. 创建计数信号量
void createCountingSemaph(void)
{
if (semaphHandle == NULL)
{
semaphHandle = xSemaphoreCreateCounting(10, 0);
}
}
9. 创建释放计数信号量的线程
每隔11S连续释放6个计数信号量
10. 创建接收计数信号量的线程
每0.8S获取一次
11. 编译和验证
编译代码、烧写程序,验证所有信号量是否都能成功获取和处理。若编译出错,请检查 FreeRTOSConfig.h
中是否启用了 configUSE_COUNTING_SEMAPHORES
宏:
#define configUSE_COUNTING_SEMAPHORES 1
12. 结果验证
烧写完成后,程序运行起来可以看到连续的信号量被成功获取,表明计数信号量能正确处理多次中断触发的情况。
通过本教程,您应已掌握如何在 FreeRTOS 中定义、创建和使用二值信号量和计数信号量。两者的主要区别在于创建方式不同,而获取和释放的用法完全一致。根据实际需求选择合适的信号量类型,可以有效管理资源竞争,确保系统的稳定性和实时性。
对应的 demo 源码, 请点击 RtosExPro at freertos_sync_semaphore
也可扫码关注博主同名公众号"不解之榬",回复 “freeRTOS” 获取
写在最后:
不可以在线程中创建二值信号量,会导致前后不一
希望这篇教程能对您的开发工作有所帮助。如果有任何疑问或需要进一步的说明,欢迎在评论区留言。祝您的 FreeRTOS 项目开发顺利,运行稳定!