学习RTOS(8)任务延时列表

在本章之前, 为了实现任务的阻塞延时,在任务控制块中内置了一个延时变量xTicksToDelay。每当任务需要延时的时候,就初始化 xTicksToDelay 需要延时的时间, 然后将任务挂起,这里的挂起只是将任务在优先级位图表 uxTopReadyPriority 中对应的位清零,并不会将任务从就绪列表中删除。 当每次时基中断( SysTick 中断) 来临时, 就扫描就绪列表中的每个任务的 xTicksToDelay, 如果 xTicksToDelay 大于 0 则递减一次,然后判断xTicksToDelay 是否为 0,如果为 0 则表示延时时间到,将该任务就绪( 即将任务在优先级位图表 uxTopReadyPriority 中对应的位置位) ,然后进行任务切换。 这种延时的缺点是,在每个时基中断中需要对所有任务都扫描一遍,费时,优点是容易理解。

任务延时列表的工作原理

在 FreeRTOS 有两个任务延时列表,当任务需要延时的时候,则先将任务挂起,即先将任务从就绪列表删除,然后插入到任务延时列表,同时更新下一个任务的解锁时刻变量:xNextTaskUnblockTime 的值
xNextTaskUnblockTime 的值等于系统时基计数器的值 xTickCount 加上任务需要延时的值 xTicksToDelay。 当系统时基计数器 xTickCount 的值与 xNextTaskUnblockTime 相等时,就表示有任务延时到期了,需要将该任务就绪。 与 RT-Thread 和 μC/OS 在解锁延时任务时要扫描定时器列表这种时间不确定性的方法相比, FreeRTOS 这个 xNextTaskUnblockTime全局变量设计的非常巧妙。
任务延时列表表维护着一条双向链表,每个节点代表了正在延时的任务,节点按照延时时间大小做升序排列。 当每次时基中断( SysTick 中断) 来临时, 就拿系统时基计数器的值 xTickCount 与下一个任务的解锁时刻变量 xNextTaskUnblockTime 的值相比较, 如果相等, 则表示有任务延时到期, 需要将该任务就绪, 否则只是单纯地更新系统时基计数器xTickCount 的值, 然后进行任务切换。

任务延时列表初始化在这里插入图片描述

代码清单 11-1(1)(2): FreeRTOS 定义了两个任务延时列表,当系统时基计数器xTickCount 没有溢出时,用一条列表,当 xTickCount 溢出后, 用另外一条列表。
代码清单 11-1(3): 任务延时列表指针, 指向 xTickCount 没有溢出时使用的那条列表。
代码清单 11-1(7): 任务延时列表指针, 指向 xTickCount 溢出时使用的那条列表。

任务延时列表初始化

任务延时列表属于任务列表的一种,在 prvInitialiseTaskLists()函数中初始化。
在这里插入图片描述

xNextTaskUnblockTime 是一个在 task.c 中定义的静态变量,用于表示下一个任务的解锁时刻。 xNextTaskUnblockTime 的值等于系统时基计数器的值 xTickCount 加上任务需要延时值 xTicksToDelay。当系统时基计数器 xTickCount 的值与 xNextTaskUnblockTime 相等时,就表示有任务延时到期了,需要将该任务就绪。
xNextTaskUnblockTime 在 vTaskStartScheduler()函数中初始化为 portMAX_DELAY( portMAX_DELAY 是一个 portmacro.h 中定义的宏,默认为 0xffffffffUL)。
在这里插入图片描述

修改 vTaskDelay()函数
在这里插入图片描述

代码清单 11-4(1): 从本章开始,添加了任务的延时列表,延时的时候不用再依赖任务 TCB 中内置的延时变量 xTicksToDelay。
代码清单 11-4(2): 将任务插入到延时列表。 函数 prvAddCurrentTaskToDelayedList()在 task.c 中定义,具体实现见代码清单 11-5。

prvAddCurrentTaskToDelayedList()函数
在这里插入图片描述

代码清单 11-5(1): 获取系统时基计数器 xTickCount 的值, xTickCount 是一个在 task.c中定义的全局变量,用于记录 SysTick 的中断次数。
代码清单 11-5(2): 调用函数 uxListRemove()将任务从就绪列表移除, uxListRemove()会返回当前链表下节点的个数,如果为 0,则表示当前链表下没有任务就绪,则调用函数portRESET_READY_PRIORITY()将任务在优先级位图表 uxTopReadyPriority 中对应的位清除。 因为 FreeRTOS 支持同一个优先级下可以有多个任务,所以在清除优先级位图表uxTopReadyPriority 中对应的位时要判断下该优先级下的就绪列表是否还有其它的任务。 目前为止, 我们还没有支持同一个优先级下有多个任务的功能。
代码清单 11-5(3): 计算任务延时到期时,系统时基计数器 xTickCount 的值是多少。
代码清单 11-5(4): 将任务延时到期的值设置为节点的排序值。 将任务插入到延时列表时就是根据这个值来做升序排列的, 最先延时到期的任务排在最前面。
代码清单 11-5(5): xTimeToWake 溢出, 将任务插入到溢出任务延时列表。溢出?什么意思? xTimeToWake 等于系统时基计数器 xTickCount 的值加上任务需要延时的时间xTicksToWait。举例: 如果当前 xTickCount 的值等于 0xfffffffdUL, xTicksToWait 等于0x03,那么 xTimeToWake = 0xfffffffdUL + 0x03 = 1,显然得出的值比任务需要延时的时间0x03 还小,这肯定不正常,说明溢出了,这个时候需要将任务插入到溢出任务延时列表。
代码清单 11-5(6): xTimeToWake 没有溢出, 则将任务插入到正常任务延时列表。
代码清单 11-5(7): 更新下一个任务解锁时刻变量 xNextTaskUnblockTime 的值。 这一步很重要, 在 TaskIncrementTick()函数中,我们只需要让系统时基计数器 xTickCount 与xNextTaskUnblockTime 的值先比较就知道延时最快结束的任务是否到期。

xTaskIncrementTick()函数
在这里插入图片描述
在这里插入图片描述

代码清单 11-6(1): 更新系统时基计数器 xTickCount 的值。
代码清单 11-6(2) : 如果系统时基计数器 xTickCount 溢出,则切换延时列表。taskSWITCH_DELAYED_LISTS()函数在 task.c 中定义,具体实现见代码清单 11-7。
在这里插入图片描述

代 码 清 单 11-7(1) : 切 换 延 时 列 表 , 实 际 就 是 更 换 pxDelayedTaskList 和pxOverflowDelayedTaskList 这两个指针的指向。
代码清单 11-7(2): 复位 xNextTaskUnblockTime 的值。 prvResetNextTaskUnblockTime()函数在 task.c 中定义,在这里插入图片描述

代码清单 11-6(3) :有任务延时到期,则进入下面的 for 循环,一一将这些延时到期的任务从延时列表移除。
代码清单 11-6(4) :延时列表为空,则将 xNextTaskUnblockTime 设置为最大值, 然后跳出 for 循环。
代码清单 11-6(5) :延时列表不为空,则需要将延时列表里面延时到期的任务删除,并将它们添加到就绪列表。
代码清单 11-6(6) :取出延时列表第一个节点的排序辅助值。
代码清单 11-6(7) : 直到将延时列表中所有延时到期的任务移除才跳出 for 循环。延时列表中有可能存在多个延时相等的任务。
代码清单 11-6(8) : 将任务从延时列表移除,消除等待状态。
代码清单 11-6(9) : 将解除等待的任务添加到就绪列表。
代码清单 11-6(10) :执行一次任务切换。

在没有添加任务延时列表之前,与任务相关的列表只有一个,就是就绪列表,无论任务在延时还是就绪都只能通过扫描就绪列表来找到任务的 TCB,从而实现系统调度。 额外添加了延时列表,当任务要延时的时候,将任务从就绪列表移除,然后添加到延时列表,同时将任务在优先级位图表 uxTopReadyPriority 中对应的位清除。在清除任务在优先级位图表 uxTopReadyPriority 中对应的位的时候, 与上一章不同的是需要判断就绪列表 pxReadyTasksLists[]在当前优先级下对应的链表的节点是否为 0,只有当该链表下没有任务时才真正地将任务在优先级位图表 uxTopReadyPriority 中对应的位清零。
在这里插入图片描述

实验效果,间隔20ms取反一次
在这里插入图片描述

问题:在全速运行的时候,我该如何知道我的任务栈用了多少空间,还剩多少资源。

Hankin
2020.08.22

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值