阿拉尔市网站建设_网站建设公司_改版升级_seo优化
2026/1/18 21:28:17 网站建设 项目流程

消息量

信号量本质上是一个特殊的队列,但是它内部是一个计数装置,通过计数来表明程序的状态,可以理解成一个状态机,

信号量是FreeRTOS中用于"计数"和"同步"的工具,主要解决:1个资源多个任务抢的问题,和1个事件多个任务等的问题。

信号量的使用主要分为创建,读取,释放三个步骤,此外还有一个删除操作

创建信号量

使用信号量之前,要先创建,得到一个句柄;使用信号量时,要使用句柄来表明使用哪个信号量。 对于二进制信号量、计数型信号量,它们的创建函数不一样:

具体的信号量还分为二进制信号量,和计数信号量

他两个大致的区别就是,二进制初始数据只能是1,技术型可以自己设定

此外还有动态和静态之分,动态和静态的区别前面已经说过

这个里就直接搬运韦老师的代码了

/* 创建一个二进制信号量,返回它的句柄。 * 此函数内部会分配信号量结构体 * 返回值: 返回句柄,非NULL表示成功 */ SemaphoreHandle_t xSemaphoreCreateBinary( void ); /* 创建一个二进制信号量,返回它的句柄。 * 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针 * 返回值: 返回句柄,非NULL表示成功 */ SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer ); 创建计数型信号量的函数原型如下: /* 创建一个计数型信号量,返回它的句柄。 * 此函数内部会分配信号量结构体 * uxMaxCount: 最大计数值 * uxInitialCount: 初始计数值 * 返回值: 返回句柄,非NULL表示成功 */ SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount); /* 创建一个计数型信号量,返回它的句柄。 * 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针 * uxMaxCount: 最大计数值 * uxInitialCount: 初始计数值 * pxSemaphoreBuffer: StaticSemaphore_t结构体指针 * 返回值: 返回句柄,非NULL表示成功 */ SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer );

然后是读取函数,这个函数有任务中和中断中两种

在任务中使用在ISR中使用
givexSemaphoreGivexSemaphoreGiveFromISR

xSemaphoreGive的函数原型如下:

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

xSemaphoreGive函数的参数与返回值列表如下:

参数说明
xSemaphore信号量句柄,释放哪个信号量
返回值pdTRUE表示成功, 如果二进制信号量的计数值已经是1,再次调用此函数则返回失败; 如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败

pxHigherPriorityTaskWoken的函数原型如下:

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );

xSemaphoreGiveFromISR函数的参数与返回值列表如下:

参数说明
xSemaphore信号量句柄,释放哪个信号量
pxHigherPriorityTaskWoken如果释放信号量导致更高优先级的任务变为了就绪态, 则*pxHigherPriorityTaskWoken = pdTRUE
返回值pdTRUE表示成功, 如果二进制信号量的计数值已经是1,再次调用此函数则返回失败; 如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败

然后是释放

xSemaphoreTake的函数原型如下:

BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );

xSemaphoreTake函数的参数与返回值列表如下:

参数说明
xSemaphore信号量句柄,获取哪个信号量
xTicksToWait如果无法马上获得信号量,阻塞一会: 0:不阻塞,马上返回 portMAX_DELAY: 一直阻塞直到成功 其他值: 阻塞的Tick个数,可以使用*pdMS_TO_TICKS()*来指定阻塞时间为若干ms
返回值pdTRUE表示成功

xSemaphoreTakeFromISR的函数原型如下:

BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );

xSemaphoreTakeFromISR函数的参数与返回值列表如下:

参数说明
xSemaphore信号量句柄,获取哪个信号量
pxHigherPriorityTaskWoken如果获取信号量导致更高优先级的任务变为了就绪态, 则*pxHigherPriorityTaskWoken = pdTRUE
返回值pdTRUE表示成功

最后是删除操作

对于动态创建的信号量,不再需要它们时,可以删除它们以回收内存。

vSemaphoreDelete可以用来删除二进制信号量、计数型信号量,函数原型如下:

/* * xSemaphore: 信号量句柄,你要删除哪个信号量 */ void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

然后我来给大家将几点注意事项

1.如果你的代码不是事先用CUBEMX生成好的信号量,那么你就需要引用

#include "semphr.h"

头文件

2.一定有释放要不然又溢出风险,这种一般是不会编译报错的,但是运行不出来结果

然后我们在使用信号量可能会出现优先级反转的问题,简单来说,就是低优先级的任务运行比高优先级的任务高,这个原因就是因为,信号量的权限一直在低优先级手里,也就是低优先级没有释放信号量造成的,

大概如图所示

要想完美解决这个问题就要使用到互斥量

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询