FreeRTOS 笔记_任务计数信号量
基于任务通知(Task Notifications) 的计数信号量是FreeRTOS 计数信号量的另一种实现方式,这种方式实现的计数信号量称之为任务计数信号量。任务计数信号量效率更高, 需要的 RAM 空间更小。
1 任务通知介绍
FreeRTOS 每个已经创建的任务都有一个任务控制块(task control block),任务控制块就是一个结构体变量,用于记录任务的相关信息。
结构体变量中有一个 32 位的变量成员 ulNotifiedValue 是专门用于任务通知的。
通过任务通知方式可以实现计数信号量,二值信号量,事件标志组和消息邮箱(消息邮箱就是消息队列长度为 1 的情况)。使用方法与事件标志组和信号量基本相同,只是换了不同的函数来实现。任务通知方式实现的计数信号量,二值信号量,事件标志组和消息邮箱是通过修改变量ulNotifiedValue 实现的:
◆ 设置接收任务控制块中的变量 ulNotifiedValue 可以实现消息邮箱。
◆ 如果接收任务控制块中的变量 ulNotifiedValue 还没有被其接收到,也可以用新数据覆盖原有数据 ,这就是覆盖方式的消息邮箱。
◆ 设置接收任务控制块中的变量 ulNotifiedValue 的 bit0-bit31 数值可以实现事件标志组。
◆ 设置接收任务控制块中的变量 ulNotifiedValue 数值进行加一或者减一操作可以实现计数信号量和二值信号量。
2 任务计数信号量
计数信号量就是对一个变量进行计数,变量的范围是 从 0 到用户创建计数信号量时所设置的大小。当计数变量大于 0 的时候计数信号量管理的资源才可以使用, 计数变量的具体数值就是可用的资源大小。
任务计数信号量与计数信号量要实现的功能是一样的,不同的是调用的函数和使用的计数变量:
◆ 任务计数信号量的计数变量是通过任务控制块中的一个 32 位变量 ulNotifiedValue 实现计数。计数信号量创建后会有自己的计数变量。
◆ 任务计数信号量是通过函数 ulTaskNotifyTake()替代函数 xSemaphoreTake()实现资源获取,即对计数信号量数值进行减一操作。
◆ 任务计数信号量是通过函数 xTaskNotifyGive() 和 vTaskNotifyGiveFromISR()替代函数 xSemaphoreGive() 和 xSemaphoreGiveFromISR()实现资源释放,即对计数信号量的数值进 行加一操作。
3 任务计数信号量 API 函数
◆ xTaskNotifyGive
◆ vTaskNotifyGiveFromISR
◆ ulTaskNotifyTake
函数 xTaskNotifyGive 用于释放信号量(含任务二值信号量,任务计数信号量)。
◆ 第 1 个参数是任务句柄。
◆ 返回值,仅有一个返回值 pdPASS。
使用这个函数要注意以下问题:
1. 任务信号量的初始计数值是 0。任务信号量不像前面章节讲解的信号量,无需单独创建即可使用。
2. 默认配置此函数可以使用的的宏定义已经在 FreeRTOS.h 文件中使能:
#define configUSE_TASK_NOTIFICATIONS 1
当然,如果用户不需要使用任务通知功能相关的函数,可以在 FreeRTOSConfig.h 文件中配置此宏定义为 0 来禁止,这样创建的每个任务可以节省 8 个字节的需求。
3. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是 vTaskNotifyGiveFromISR。
函数 vTaskNotifyGiveFromISR 用于释放信号量(含任务二值信号量,任务计数信号量)。
◆ 第 1 个参数是任务句柄。
◆ 第2 个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是 pdTRUE, 说明有高优先级任务要执行,否则没有
举例:
函数 xTaskNotifyGive 用于释放信号量(含任务二值信号量,任务计数信号量)。
◆ 第 1 个参数配置为 pdFALSE 表示函数返回前用于任务信号量的内部变量 ulNotifiedValue数值减一,这种方式用于任务计数信号量。
参数配置为 pdTRUE 表示函数返回前用于任务信号量的内部变量 ulNotifiedValue数值被清零,这种方式用于任务二值信号量。
◆ 第 2 个参数是没有任务信号量可用时,等待信号量可用的最大等待时间,单位系统时钟节拍。
举例: