【FreeRTOS学习】第12章 任务管理

1. 任务的基本概念

FreeRTOS的任务可认为是一系列独立任务的集合。每个任务在自己独立的环境中运行。
在这里插入图片描述
在任何时刻,只有一个任务能得到运行,由FreeRTOS调度器决定运行哪个任务。调度器会在合适的时候的启动、停止一个任务,宏观看上去所有的任务都在同时在执行。这其实就是任务的切换。
任务切入/切出时保存上下文环境
每个FreeRTOS任务都需要有自己的栈空间
FreeRTOS中的任务是抢占式调度机制,也支持时间片轮转调度方式
任务通常会运行在一个死循环中,也不会退出,如果一个任务不再需要,可以调用FreeRTOS中的任务删除API函数接口显式地将其删除。

2. 任务调度器的基本概念

FreeRTOS中提供的任务调度器是基于优先级的全抢占式调度:在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的。

当有比当前任务优先级更高的任务就绪时,当前任务将立刻被切出,高优先级任务抢占处理器运行。

FreeRTOS内核中也允许创建相同优先级的任务。相同优先级的任务采用时间片轮转方式进行调度。时间片轮转调度仅在当前系统中无更高优先级就绪任务存在的情况下才有效。

任务调度的原则是一旦任务状态发生了改变,并且当前运行的任务优先级小于优先级队列组中任务最高优先级时,立刻进行任务切换

3. 任务状态

就绪(Ready):该任务在就绪列表中,就绪的任务已经具备执行的能力,只等待调度器进行调度,新创建的任务会初始化为就绪态。

运行(Running):该状态表明任务正在执行,此时它占用处理器,FreeRTOS调度器选择运行的永远是处于最高优先级的就绪态任务,当任务被运行的一刻,它的任务状态就变成了运行态。

阻塞(Blocked):如果任务当前正在等待某个时序或外部中断,我们就说这个任务处于阻塞状态,该任务不在就绪列表中。包含任务被延时、任务正在等待信号量、读写队列或者等待读写事件等。

挂起(Suspended):处于挂起态的任务对调度器而言是不可见的,让一个任务进入挂起状态的唯一办法就是调用 vTaskSuspend()函数;而 把 一 个 挂 起 状态 的 任 务 恢复的 唯 一 途 径 就 是 调 用 vTaskResume() 或vTaskResumeFromISR()函数。

3.1 任务状态的迁移

在这里插入图片描述

4. 相关函数

4.1 vTaskSuspend()

挂起指定任务。被挂起的任务绝不会得到CPU的使用权,不管该任务具有什么优先级。
参数:任务句柄。

4.2. vTaskResume()

任务恢复就是让挂起的任务重新进入就绪状态,恢复的任务会保留挂起前的状态信息,在恢复的时候根据挂起时的状态继续运行。

4.3 xTaskResumeFromISR()

xTaskResumeFromISR()专门用在中断服务程序中恢复一个任务。

无论通过调用一次或多次 vTaskSuspend()函数而被挂起的任务,也只需调用一次恢复任务函数就可以恢复。
如果被恢复任务在所有就绪态任务中处于最高优先级的,那么系统将进行任务上下文的切换。

4.4 vTaskSuspendAll()

挂起所有任务就是挂起任务调度器。调度器被挂起后则不能进行上下文切换。

通过uxSchedulerSuspended变量记录挂起多少次。

在调度器挂起期间,被中断恢复的任务,将被挂载到xPendingReadyList待处理就绪列表中。

4.5 xTaskResumeAll()

那么调用对应的xTaskResumeAll()会将变量uxSchedulerSuspended减一。
将任何准备好的任务从待处理就绪列表,移动到相应的就绪列表中。
重置下一个任务的解除阻塞时间。
更新时基确保滴答定时器的计数不会滑动。
调用了多少次的vTaskSuspendAll()就要调用多少次xTaskResumeAll()进行恢复

4.6 vTaskDelete()

vTaskDelete()用于删除一个任务。当一个任务删除另外一个任务时,形参为要删除任务创建时返回的任务句柄,如果是删除自身, 则形参为 NULL。

如果此时删除的任务是任务自身的话,那么删除任务函数不能在任务本身内完成删除操作,因为需要上下文切换到另一个任务。所以需要将任务放在回收列表中(xTasksWaitingTermination),空闲任务会检查结束列表并在空闲任务prvIdleTask()中释放删除任务的控制块和已删除任务的堆栈内存。

删除任务时,只会自动释放内核本身分配给任务的内存。应用程序(而不是内核)分配给任务的内存或任何其他资源必须是删除任务时由应用程序显式释放。

5. 相对延时与绝对延时

5.1 vTaskDelay()

vTaskDelay()是阻塞延时,调用该函数后,任务将进入阻塞状态,进入阻塞态的任务将让出 CPU资源。

vTaskDelay()在我们任务中用得非常之多,每个任务都必须是死循环,并且是必须要有阻塞的情况,否则低优先级的任务就无法被运行了。

vTaskDelay()延时是相对性的延时,它指定的延时时间是从调用 vTaskDelay()结束后开始计算的,经过指定的时间后延时结束。
在这里插入图片描述

5.2 vTaskDelayUntil()

这个绝对延时vTaskDelayUntil()函数常用于较精确的周期运行任务

任务从上一次运行开始到下一次运行开始的时间间隔是绝对的

void vTaskA( void * pvParameters )  
 {   
    /* 用于保存上次时间。调用后系统自动更新 */  
   static portTickType PreviousWakeTime;  
   /* 设置延时时间,将时间转为节拍数 */  
   const portTickType TimeIncrement = pdMS_TO_TICKS(1000);    
   /* 获取当前系统时间 */  
   PreviousWakeTime = xTaskGetTickCount();   
   while(1)    
   {           
      /* 调用绝对延时函数,任务时间间隔为1000个tick */        
      vTaskDelayUntil( &PreviousWakeTime,TimeIncrement );         
      //  ...   
      //  这里为任务主体代码   
      //  ...     
   }
 }

在这里插入图片描述
任务会先调用vTaskDelayUntil()使任务进入阻塞态,等到时间到了就从阻塞中解除,然后执行主体代码,任务主体代码执行完毕。会继续调用vTaskDelayUntil()使任务进入阻塞态,然后就是循环这样子执行。即使任务在执行过程中发生中断,那么也不会影响这个任务的运行周期,仅仅是缩短了阻塞的时间而已,到了要唤醒的时间依旧会将任务唤醒。
xTimeIncrement:任务周期时间
pxPreviousWakeTime:上一次唤醒的时间点
xTimeToWake:下一次唤醒的系统时间点
xConstTickCount:进入延时的时间点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述无论是溢出还是没有溢出,都要求在下次唤醒任务之前,当前任务主体代码必须被执行完。也就是说任务执行的时间必须小于任务周期时间xTimeIncrement。

任务会先调用vTaskDelayUntil()使任务进入阻塞态,等到时间到了就从阻塞中解除,然后执行主体代码,任务主体代码执行完毕。会继续调用vTaskDelayUntil()使任务进入阻塞态,然后就是循环这样子执行。即使任务在执行过程中发生中断,那么也不会影响这个任务的运行周期,仅仅是缩短了阻塞的时间而已,到了要唤醒的时间依旧会将任务唤醒。

6. 任务设计要点

中断服务函数是一种需要特别注意的上下文环境,它运行在非任务的执行环境下,在这个上下文环境中不能使用挂起当前任务的操作,不允许调用任何会阻塞运行的API函数接口。

做为一个优先级明确的实时系统,如果一个任务中的程序出现了死循环操作(此处的死循环是指没有阻塞机制的任务循环体),那么比这个任务优先级低的任务都将无法执行。
任务设计时,就应该保证任务在不活跃的时候,任务可以进入阻塞态以交出CPU使用权,这就需要我们自己明确知道什么情况下让任务进入阻塞态,保证低优先级任务可以正常运行。在实际设计中,一般会将紧急的处理事件的任务优先级设置得高一些。

空闲任务(idle任务)是FreeRTOS系统中没有其他工作进行时自动进入的系统任务。因为处理器总是需要代码来执行——所以至少要有一个任务处于运行态。
FreeRTOS系统还把空闲任务用于一些其他的功能,比如当系统删除一个任务或一个动态任务运行结束时,在执行删除任务的时候,并不会释放任务的内存空间,只会将任务添加到回收列表中,真正的系统资源回收工作在空闲任务完成,空闲任务是唯一一个不允许出现阻塞情况的任务。

除此之外,还需要注意任务的执行时间。
任务的执行时间一般是指两个方面,一是任务从开始到结束的时间,二是任务的周期。
在我们设计的时候,必须考虑任务的时间,一般来说处理时间更短的任务优先级应设置更高一些。

7. 实验

任务管理实验是将任务常用的函数进行一次实验,在野火STM32开发板上进行该试验,通过创建两个任务,一个是LED任务,另一个是按键任务,LED任务是显示任务运行的状态,而按键任务是通过检测按键的按下与否来进行对LED任务的挂起与恢复

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值