FreeRTOS--任务通知方式

一.任务通知(Task Notifications)介绍

        FreeRTOS 每个已经创建的任务都有一个任务控制块( task control block),任务控制块就是一个结构体变量, 用于记录任务的相关信息。 结构体变量中有一个 32 位的变量成员 ulNotifiedValue 是专门用于任务通知的。通过任务通知方式可以实现计数信号量二值信号量事件标志组消息邮箱(消息邮箱就是消息队列长度为 1 的情况)。

        任务通知方式实现的计数信号量, 二值信号量,事件标志组和消息邮箱是通过修改变量ulNotifiedValue 实现的:

 设置接收任务控制块中的变量 ulNotifiedValue 可以实现消息邮箱。

 如果接收任务控制块中的变量 ulNotifiedValue 还没有被其接收到, 也可以用新数据覆盖原有数据, 这就是覆盖方式的消息邮箱。

 设置接收任务控制块中的变量 ulNotifiedValue 的 bit0-bit31 数值可以实现事件标志组。

 设置接收任务控制块中的变量 ulNotifiedValue 数值进行加一或者减一操作可以实现计数信号量和二值信号量。

二、通知任务计数信号量

1.任务计数信号量概念及其作用

        FreeRTOS 计数信号量的另一种实现方式--基于任务通知( Task Notifications)的计数信号量,这里我们将这种方式实现的计数信号量称之为任务计数信号量。 任务计数信号量效率更高,需要的 RAM 空间更小。实际项目中,如果使用计数信号量和任务计数信号量都能实现相应功能,强烈建议使用任务计数信号量

2.任务计数信号量 API 函数

1)函数 xTaskNotifyGive 用于任务中释放信号量( 含任务二值信号量, 任务计数信号量)

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify ); /* 任务句柄 */ 

返回 :pdPASS 

注意:此函数用于任务代码中调用,不可在中断服务程序中调用!!!

 2)函数 vTaskNotifyGiveFromISR用于中断中释放信号量(含任务二值信号量, 任务计数信号量)

void vTaskNotifyGiveFromISR(

            TaskHandle_t xTaskToNotify, /* 任务句柄 */

            BaseType_t *pxHigherPriorityTaskWoken ); /* 高优先级任务是否被唤醒的状态保存 */

 3)函数 ulTaskNotifyTake 从调用任务的任务控制块中检索通知值,并可选地清除该值

uint32_t ulTaskNotifyTake(

        BaseType_t xClearCountOnExit, /* 选择是否清零用于任务通知的 ulNotifiedValue */

        TickType_t xTicksToWait );          /* 等待信号量可用的最大等待时间 */

参数:

xClearCountOnExit  如果收到 RTOS 任务通知且 xClearCountOnExit 设置为 pdFALSE,则 RTOS 任务的通知值 在 ulTaskNotifyTake() 退出之前递减。 这 等同于 通过成功调用 xSemaphoreTake() 而递减计数信号量的值。

如果收到 RTOS 任务通知且 xClearCountOnExit 设置为 pdTRUE,则 RTOS 任务的通知值 在 ulTaskNotifyTake() 退出之前重设为 0。 这 等同于在成功调用 xSemaphoreTake() 后 将二进制信号量的值保留为 0 (或为空,或为“不可用” )。

xTicksToWait  在阻塞状态下等待接收通知的最长时间, 如果通知在 ulTaskNotifyTake() 被调用时 尚未挂起。

处于阻塞状态的 RTOS 任务不会消耗 任何 CPU 时间。

时间以 RTOS tick 周期为单位。 宏 pdMS_TO_TICKS() 可以 将以毫秒为单位的时间 转换为以 tick 为单位的时间。

 返回:被递减或清除之前的任务通知值的值

三、通知任务二值信号量

1、二值信号量的概念及其作用

        多次调用函数 xTaskNotifyGive ()难免会出现计数值大于 1 的情况,用作任务二值信号量时,我们可以将所有大于 1 的计数理解为一种情况,即二值信号量管理的资源可用。因此, 不管当前的计数是多少,大于 0 的计数在通过函数 ulTaskNotifyTake()获取二值信号量的时候统一清零,这样就实现了二值信号量的功能。实际项目中,如果使用二值信号量和任务二值信号量都能实现相应功能,强烈建议使用任务二值信号量

2.任务二值信号量 API 函数

        函数以及用法与任务计数信号量基本相同。

四、任务事件标志组

1、任务事件标志组的概念及其作用

        任务事件标志组与事件标志组要实现的功能是一样的, 不同的是调用的函数和支持的事件标志个数, 任务事件标志组支持 32 个事件标志设置, 事件标志组,每创建一个支持 24 个事件标志设置。实际项目中,如果使用事件标志组和任务事件标志组都能实现相应功能,强烈建议使用任务事件标志组

2、任务事件标志组 API 函数

1)函数 xTaskNotify
BaseType_t xTaskNotify( 
            TaskHandle_t xTaskToNotify, /* 任务句柄 */
            uint32_t ulValue,           /* 更新任务控制块中的变量 ulNotifiedValue */
             eNotifyAction eAction );   /* 任务通知模式设置 */

参数:

xTaskToNotify  正在通知的 RTOS 任务的句柄。 
ulValue  用于更新目标任务的通知值。 请参阅下面 eAction 参数的说明。
eAction  一种枚举类型,可以采用 下表中记录的值之一来执行相关操作。
eAction 设置已执行的操作
eNoAction目标任务接收事件,但其 通知值未更新。 在这种情况下,不使用 ulValue。

eSetBits目标任务的通知值 使用 ulValue 按位或运算。 例如, 如果 ulValue 设置为 0x01,则将在 目标任务的通知值中设置位 0。 同样,如果 ulValue 为 0x04,则将在 目标任务的通知值中设置位 2。 通过这种方式,RTOS 任务通知机制 可以用作 事件组的轻量级替代方案。

eIncrement目标任务的通知值 自增 1,使得调用 xTaskNotify() 相当于调用 xTaskNotifyGive()。 在这种情况下,不使用 ulValue。
eSetValueWithOverwrite目标任务的通知值 无条件设置为 ulValue。 因此, RTOS 任务通知机制可用作 xQueueOverwrite() 的轻量级替代方案。
eSetValueWithoutOrwrite如果目标任务没有 挂起的通知,则其通知值 将设置为 ulValue。

如果目标任务已经有 挂起的通知,则不会更新其通知值, 因为这样做会覆盖 之前使用的值。 在这种情况下, 调用 xTaskNotify() 失败,返回 pdFALSE。

因此,RTOS 任务通知机制可 在长度为 1 的队列上用作 xQueueSend() 在长度为 的轻量级替代方案。

返回:

        除了 eAction 被设置为 eSetValueWithoutOverwrite 且目标任务的通知值 因目标任务已有挂起的通知而无法更新之外, 在所有情况下均返回 pdPASS

        函数 xTaskNotify 通过设置任务控制块中的变量 ulNotifiedValue 可以在任务代码中实现任务事件标志组,任务计数信号量, 任务消息邮箱和任务二值信号量四种方式的消息通知。

2)函数 xTaskNotifyFromISR   
BaseType_t xTaskNotifyFromISR( 
TaskHandle_t xTaskToNotify,              /* 任务句柄 */
uint32_t ulValue,                        /* 更新任务控制块中的变量 ulNotifiedValue */
eNotifyAction eAction,                   /* 任务通知模式设置 */
BaseType_t *pxHigherPriorityTaskWoken ); /* 高优先级任务是否被唤醒的状态保存 */

        函数 xTaskNotifyFromISR 通过设置任务控制块中的变量 ulNotifiedValue 可以在中断服务程序中实现任务事件标志组,任务计数信号量, 任务消息邮箱和任务二值信号量四种方式的消息通知。

3)函数 xTaskNotifyWait

        函数 xTaskNotifyWait 可以在任务代码中实现任务事件标志组,任务计数信号量, 任务消息邮箱和任务二值信号量四种方式的消息获取。

BaseType_t xTaskNotifyWait(
/* 设置函数执行前清零任务控制块中变量 ulNotifiedValue 那些位 */
uint32_t ulBitsToClearOnEntry,
/*设置函数退出前清零任务控制块中变量 ulNotifiedValue 那些位 */
uint32_t ulBitsToClearOnExit,
/* 保存任务控制块中的变量 ulNotifiedValue 到指针变量 pulNotifiedValue 所指向的存储单元 */
uint32_t *pulNotificationValue,
/* 等待消息通知的最大等待时间 */
TickType_t xTicksToWait );

参数:

ulBitsToClearOnEntry  在 xTaskNotifyWait() 函数入口ulBitsToClearOnEntry 中设置的任何位都将在调用 RTOS 任务通知值中 被清除(在任务等待新通知之前), 前提是在调用 xTaskNotifyWait() 时通知尚未 挂起。

例如,如果 ulBitsToClearOnEntry 为 0x01, 则任务通知值的位 0 将在函数入口 被清除。

将 ulBitsToClearOnEntry 设置为 0xffffffff (ULONG_MAX) 将 清除任务通知值中的所有位,有效 将值清除为 0。

ulBitsToClearOnExit  在 xTaskNotifyWait() 函数退出之前, ulBitsToClearOnExit 中设置的任何位都将在调用 RTOS 任务通知值中 被清除,前提是接收到通知。

在 RTOS 任务通知值保存到 *pulNotificationValue 中 之后清除位 (请参阅下面的 pulNotificationValue 的说明)。

例如,如果 ulBitsToClearOnExit 为 0x03,则位 0 和 位 1 将在函数退出之前 清除。

将 ulBitsToClearOnExit 设置为 0xffffffff (ULONG_MAX) 将 清除任务通知值中的所有位,有效 将值清除为 0。

pulNotificationValue  用于传出 RTOS 任务的通知值。 在由于 ulBitsToClearOnExit 的设置清除任何位之前,复制到 *pulNotificationValue 的值是 RTOS 任务的 通知值 。

如果不需要通知值,则设置 pulNotificationValue 为 NULL。

xTicksToWait  在阻塞状态下等待接收通知的最长时间, 前提是在调用 xTaskNotifyWait() 时通知尚未 挂起。

处于阻塞状态的 RTOS 任务不会消耗 任何 CPU 时间。

时间以 RTOS tick 周期为单位。 宏 pdMS_TO_TICKS() 可以 将以毫秒为单位的时间 转换为以 tick 为单位的时间。

返回:

在调用 xTaskNotifyWait() 时,如果收到通知, 或通知已经挂起,则返回 pdTRUE。

如果调用 xTaskNotifyWait() 在收到通知之前超时, 则返回 pdFALSE。

 五、任务消息邮箱

1、任务消息邮箱的概念及其作用

        我们将消息队列( 消息队列长度固定为 1) 称之为任务消息邮箱。 这种方式实现的消息队列效率更高,需要的 RAM 空间更小。任务消息邮箱是通过任务控制块中的一个 32 位变量 ulNotifiedValue 对数据进行存取;实际项目中,如果使用任务消息邮箱和消息队列都能实现相应功能,强烈建议使用任务消息邮箱

2、任务消息邮箱使用的API与上面相同,参数设置用法不同

1)覆盖方式 xTaskNotify 第三个参数使用 eSetValueWithOverwrite 

2)非覆盖方式 xTaskNotify 第三个参数使用 eSetValueWithoutOverwrite 

六、测试例程

https://gitee.com/hutaooooooo/git_keil/tree/master/freetos_xTaskNotifyCreate

  • 51
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值