1多任务基本运行机制:
在单核处理器上,任何时刻只能有一个任务占用CPU并运行,RTOS的任务调度使得多个任务对CPU实现了分时复用功能。
在一个时间片内会有一个任务占用CPU并执行,在一个时间片结束时(实际上时基础是中定时器发生中断时)进行任务调度。当多个任务的优先级不同时,FreeRTOS还会使用基于优先级的抢占式任务调度方法。
优先级数字越小表示优先级越低。
当一个任务的时间片完成后,他就会将CPU的当前场景保存下来,也就是CPU各个核心寄存器的值,压入自己的空间,然后另一个任务接管CPU的使用权。此时task2就会用自己栈空保存的数据恢复CPU场景,因此得以继续在上次的状态运行。
因为时间片很短,默认时1ms,所以在用户看来,多个任务都是在同一个时间运行。
2任务的状态:
2.1就绪状态:
任务创建之后就处于就绪装填,根据抢占式任务调度的特点,任务调度的结果可以有一下几种状态:
2.1.1如果当前没有其他任务处于运行转台,就绪任务会立即进行运行状态;
2.1.2如果就绪任务的优先级高于或等于当前任务的优先级,就绪任务的就进入运行状态;
2.1.3如果就绪任务的优先级低于当前运行的任务,就绪的任务继续处于就绪状态。
2.2运行状态:
当有CPU并运行的任务就处于运行状态。处于运行状态的任务在空闲的时候就会让出CPU的使用权。处于运行状态的任务有两种方式主动让出CPU的使用权:
2.2.1执行函数vTaskSuspend()进入挂起状态;
2.2.2执行阻塞类函数进入阻塞状态,运行任务交出CPU使用权后,任务调度器就可以使其他就绪任务进入运行状态。
2.3阻塞状态:
阻塞装填就是任务暂时让出CPU的使用权,处于一种等待的状态。运行的任务可以调用辆类函数进入阻塞状态。
2.3.1时间延迟函数,如vTaskDelay();
2.3.2用于进程间通讯的事件请求xSemaphoreTake()。
3.挂起状态:
挂起状态的任务就是暂停任务,挂起状态的任务不参与调度器的调度。其他3种任务都可以通过调用函数vTaskSuspend()进入挂起状态,挂起后的状态不能自动推出挂起状态,需要在其他任务中调用vTaskResume()函数使其解除挂起状态。
4.空闲任务:
osKernelStart()启动FreeRTOS的任务调度器时,会自动创建一个空闲任务,空闲任务的优先级为为0。与空闲任务相关的几个主要配置参数是:
3.1 configUSE_TICK_HOOK:是否使用空闲任务的回调函数,若配置为1,则可以利用空闲任务的回调函数,系统空闲时做一些其他的处理;
3.2 configIDLE_SHOULD_YIELD:空闲任务是否对同优先级用户任务主动让出CPU使用权,这会影响任务结构。
3.3 configUSE_TICKLESS_IDLE:是否在空闲任务时关闭基础定时器时钟,若设置为1,可实现系统的低功耗。
5.任务调度方式:
FreeRTOS有两种任务调度算法,基于优先级的抢占式,和合作式调度,其中抢占式调度算法又可以使用时间片或不使用时间片。
6.使用时间片的抢占式调度方式:
FreeRTOS基础时钟的一个定时周期称为一个时间片,默认值为1ms。当使用时间片时,在基础时钟的每次中断里会要求进行一次上下文切换,,函数xPortSysTickHandler()就是systick定时中断的处理函数。
在低优先级任务运行时,高优先级的任务总是能够抢占获得CPU的使用权,那在没有其他任务运行时呢,空闲任务就处于运行状态,否则就处于堵塞状态,如果多个任务的优先级相同且处于就绪状态,那么他们就会轮流获得CPU的使用权。
7.不使用时间片的抢占式调度方法:
是哟ing时间片的抢占式调度方法在每个systick中断里都进行一次上下文切换请求,从而进行任务调度只是对于相同优先级的任务不再使用时间片,平均分配CPU时间。不使用时间片的抢占式调度只在以下情况下才进行任务调度:
7.1 有更高级别的任务进入就绪状态时;
7.2 运行状态的任务进入阻塞状态或挂起状态;
所以,不使用时间片时,进行上下文切换的频率比使用时间片时低,从而降低CPU的负担。但是,对于同优先级的任务,可能会出现占用CPU时间相差很大的情况。
8.合作式任务调度方法:
使用合作式调度方法时,FreeRTOS不主动进行上下文切换,而是运行状态的任务进入阻塞状态,或显示地调用taskYIELD()函数让出CPU使用权时才进行上下文切换。
任务也不会发生抢占,所以也不使用时间片。
函数taskYIELD()的作用就是主动申请进行一次上下文切换。