下冰雹 · 2020年09月19日

FreeRTOS系列第9篇---FreeRTOS任务概述

1. 任务和协程(Co-routines)

应用程序可以使用任务也可以使用协程,或者两者混合使用,但是任务和协程使用不同的API函数,因此在任务和协程之间不能使用同一个队列或信号量传递数据。

通常情况下,协程仅用在资源非常少的微处理器中,特别是RAM非常稀缺的情况下。目前协程很少被使用到,因此对于协程FreeRTOS作者既没有把它删除也没有进一步开发。

所以本系列文章以后不会对协程过多描述,包括其API函数。

1.1任务的特性

简而言之:使用RTOS的实时应用程序可认为是一系列独立任务的集合。每个任务在自己的环境中运行,不依赖于系统中的其它任务或者RTOS调度器。在任何时刻,只有一个任务得到运行,RTOS调度器决定运行哪个任务。调度器会不断的启动、停止每一个任务,宏观看上去就像整个应用程序都在执行。作为任务,不需要对调度器的活动有所了解,在任务切入切出时保存上下文环境(寄存器值、堆栈内容)是调度器主要的职责。为了实现这点,每个任务都需要有自己的堆栈。当任务切出时,它的执行环境会被保存在该任务的堆栈中,这样当再次运行时,就能从堆栈中正确的恢复上次的运行环境。

1.2任务概要
  • 简单
  • 没有使用限制
  • 支持完全抢占
  • 支持优先级
  • 每个任务都有自己的堆栈,消耗RAM较多
  • 如果使用抢占,必须小心的考虑可重入问题
2. 任务状态

一个任务可为下面中的一个:

1、运行:如果一个任务正在执行,那么说这个任务处于运行状态。此时它占用处理器。
2、就绪:就绪的任务已经具备执行的能力(不同于阻塞和挂起),但是因为有一个同优先级或者更高优先级的任务处于运行状态而还没有真正执行。
3、阻塞:如果任务当前正在等待某个时序或外部中断,我们就说这个任务处于阻塞状态。比如一个任务调用vTaskDelay()后会阻塞到延时周期到为止。任务也可能阻塞在队列或信号量事件上。进入阻塞状态的任务通常有一个“超时”周期,当事件超时后解除阻塞。
4、挂起:处于挂起状态的任务同样对调度器无效。仅当明确的分别调用vTaskSuspend() 和xTaskResume() API函数后,任务才会进入或退出挂起状态。不可以指定超时周期事件(不可以通过设定超时事件而退出挂起状态)
12121.png

3.任务优先级

每个任务都要被指定一个优先级,从0~configMAX_PRIORITIES,configMAX_PRIORITIES定义在FreeRTOSConfig.h中。

如果某架构硬件支持CLZ(或类似)指令(计算前导零的数目,Cortex-M3是支持该指令的,从ARMv6T2才支持这个指令),并且打算在移植层使用这个特性来优化任务调度机制,需要有一些步骤,首先将FreeRTOSConfig.h中configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1,并且最大优先级数目configMAX_PRIORITIES不能大于32。除此之外,configMAX_PRIORITIES可以设置为任意值,但是考虑到configMAX_PRIORITIES设置越大,RAM消耗也越大,一般设置为满足使用的最小值。

低优先级数值代表低优先级。空闲任务(idle task)的优先级为0(tskIDLE_PRIORITY)。

FreeRTOS调度器确保处于最高优先级的就绪或运行态任务获取处理器,换句话说,处于运行状态的任务,只有其中的最高优先级任务才会运行。

任何数量的任务可以共享同一个优先级。如果宏configUSE_TIME_SLICING未定义或着宏configUSE_TIME_SLICING定义为1,处于就绪态的多个相同优先级任务将会以时间片切换的方式共享处理器。

4.实现一个任务

一个任务具有以下结构:

void vATaskFunction( void *pvParameters )
{
    for( ;; )
    {
        /*-- 应用程序代码放在这里. --*/
    }
 
    /* 任务不可以从这个函数返回或退出。在较新的FreeRTOS移植包中,如果
    试图从一个任务中返回,将会调用configASSERT()(如果定义的话)。
    如果一个任务确实要退出函数,那么这个任务应调用vTaskDelete(NULL)
    函数,以便处理一些清理工作。*/
    vTaskDelete( NULL );
}

任务函数返回为void,参数只有一个void类型指针。所有的任务函数都应该是这样。void类型指针可以向任务传递任意类型信息。

任务函数决不应该返回,因此通常任务函数都是一个死循环。

任务由xTaskCreate()函数创建,由vTaskDelete()函数删除。

5.空闲任务和空闲任务钩子(idle task和Idle Task hook)
5.1空闲任务

空闲任务是启动RTOS调度器时由内核自动创建的任务,这样可以确保至少有一个任务在运行。空闲任务具有最低任务优先级,这样如果有其它更高优先级的任务进入就绪态就可以立刻让出CPU。

删除任务后,空闲任务用来释放RTOS分配给被删除任务的内存。因此,在应用中使用vTaskDelete()函数后确保空闲任务能获得处理器时间就很重要了。除此之外,空闲任务没有其它有效功能,所以可以被合理的剥夺处理器时间,并且它的优先级也是最低的。

应用程序任务共享空闲任务优先级(tskIDLE_PRIORITY)也是可能的。这种情况如何配置可以参考configIDLE_SHOULE_YIELD配置参数类获取更多信息。

5.2空闲任务钩子

空闲任务钩子是一个函数,每一个空闲任务周期被调用一次。如果你想将任务程序功能运行在空闲优先级上,可以有两种选择:

在一个空闲任务钩子中实现这个功能:因为FreeRTOS必须至少有一个任务处于就绪或运行状态,因此钩子函数不可以调用可能引起空闲任务阻塞的API函数(比如vTaskDelay()或者带有超时事件的队列或信号量函数)。
创建一个具有空闲优先级的任务去实现这个功能:这是个更灵活的解决方案,但是会带来更多RAM开销。

  创建一个空闲钩子步骤如下:

在FreeRTOSConfig.h头文件中设置configUSE_IDLE_HOOK为1;
定义一个函数,名字和参数原型如下所示:

  • void vApplicationIdleHook( void );

    • 通常,使用这个空闲钩子函数设置CPU进入低功耗模式。

#### 相关阅读
FreeRTOS系列第8篇---FreeRTOS内存管理
FreeRTOS系列第7篇---Cortex-M内核使用FreeRTOS特别注意事项

作者:朱工
首发博客:https://blog.csdn.net/zhzht19861011/article/details/50312443
关注FreeRTOS从基础到高级专栏,即时收取FreeRTOS系列文章。
推荐阅读
关注数
3260
内容数
54
介绍FreeRTOS的基本功能,移植与使用。主要介绍FreeRTOS的裁剪、任务、内存管理、队列、信号量、任务通知等基本组成,看完可以会用FreeRTOS,高级篇会深入介绍FreeRTOS的实现细节、方法、技巧。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息