全部学习汇总: ​​https://github.com/GreyZhang/g_FreeRTOS​

之前用FreeRTOS的时候,感觉很方便的一点就是vTaskDelay()接口提供了一个非阻塞的延时。这样,就很容易把一些等待或者延时的时间解放出来去做一些更有价值的事情。当时我对这个接口的认识就是这个接口会触发一次任务调度,但是我并没有去做深入的分析甚至去看相应的接口说明。因为这样的观念是从ucos ii的时候就建立了的。不过,说真的,我对ucos的理解也并不深。

前一段时间,项目中使用了一个封闭的RTOS。为了能够在这样的环境中实现一个类似的接口实现分阻塞的调度,我直接利用触发任务调度的接口结合硬件定时器来做了一个时间偏差的判断。纵然精度可能并不是很好,但是表现上肯定是远远好过使用阻塞模式的延时了。今天简单看了一下FreeRTOS这方面功能的实现,其实本质上的方法一致。但是,FreeRTOS的实现自然是更加细腻一些。

1277_FreeRTOS中vTaskDelay的实现分析_嵌入式

以上代码就是FreeRTOS中vTaskDelay()接口的实现,我增加了一个中文的理解注释。不同于我之前自己“创造”的延时方法,FreeRTOS中的vTaskDelay()其实是分为了2种情况做延时的处理。2种情况上的差异很小,甚至说是1种,只是有时候特殊一些。

1277_FreeRTOS中vTaskDelay的实现分析_嵌入式_02

之前分析其他的代码的时候遇到过一个一组delayed task链表。上面是相关链表的定义信息,这个链表在tick handler以及任务的删除等接口中都是用到过的。之前一直不理解是什么概念,现在看来应该是被delay接口触发挂起的任务。而delay接口则可以指定其挂起的时间。

这样,vTaskDelay()接口实现的功能就很好总结了。首先判断延时是否是0,如果是0的话其实触发一次调度就可以了。这里能够看得出来,其实这个delay总会触发任务调度的,不管这个延时的时间是否存在。如果延时时间大于0个tick,那么先去挂起所有的任务,然后把当前的任务加入到delayed task链表。这里加入的时候带着一个延时时间,暂且不看这个接口实现也大概能够知道这个应该是用以处理任务排序用的那个计数器。之后,恢复所有挂起的任务。如果恢复的时候出现了任务调度,那么设置一个标志位后面不再触发任务调度。否则,触发一次任务调度。

这么看,其实我之前自己设计的延时接口也是可以凑合用用的。由于我之前用的是一个封闭的RTOS,并不能够直接修改任务链表,因此能够结合硬件定时器做一个判断之后使用调度请求灵活处理也可以将就。