一个任务就是实现某一功能的一个函数,任务内部一般有一个死循环结构,任何时候都不允许退出。只有当一个任务功能结束,确实需要它结束自己时,才可以退出死循环,调用vTaskDelete删除自己,或在其它函数中调用该函数删除它。
在单核处理器上,任何时候都只能有一个任务占据 CPU 运行。但 freertos 通过任务调度,可以使多个任务对 CPU 进行分时复用。
假设有两个相同优先级的任务,task1 先执行。在一个时间片里只能有一个任务占据 CPU 并执行,当时间片结束时进行任务调度。
时间片什么时候结束?
在上一讲有一个设置参数位TICK_RATE_HZ,这就是设置时钟频率,默认 1000hz。映射到硬件上就是系统 systick 定时器中断时,发生任务调度。
当发生任务调度时,系统将 cpu 使用权交给 task2,此时 task1 会先将 cpu 场景,即各个核心寄存器的值压入自己的栈;task2 获得 CPU 使用权时,会用自己保存的数据恢复 cpu 场景,因此可以在上次运行的状态继续运行。通过这种方式,可以使相同优先级的任务均匀分配 cpu 时间。
“均匀分配”并不意味着“平均分配”,根据任务实际需要,每个任务可以占据不相等的时间片长度。
任务优先级不相同使 rtos 会进行基于优先级的抢占式任务调度,这点之后再讲。

就像在操作系统中学到的一样,任务的状态分为就绪 ready、运行 running、阻塞 blocked、挂起 suspended 四个状态。
就绪状态是任务被创建后进入的初始状态。
处于就绪态表示:
基于抢占式调度方式,当一个任务处于就绪态时,调度结果分为以下三种情况:
运行状态指任务正在占用 CPU 并执行指令。
在单核系统中,同一时刻只能有一个任务处于运行态。处于运行态的任务拥有 CPU 使用权。
当任务没有实际工作需要处理时,应主动让出 CPU 使用权。
否则会导致:
1)调用 vTaskSuspend()
作用:
2)调用阻塞类函数
例如:
作用:
当运行任务进入挂起态或阻塞态后:
阻塞状态表示任务暂时让出 CPU 使用权,进入等待某个条件满足的状态。
处于阻塞态的任务:
本质是因“等待条件”而主动退出运行。
只有处于运行态(Running)的任务,才能调用相关函数进入阻塞态。
就绪态或挂起态任务不能直接进入阻塞态。
典型函数:
vTaskDelay()vTaskDelayUntil()作用:
典型场景:
xSemaphoreTake())作用:
属于“基于事件”的等待。
Running → Blocked
调用延时或等待资源函数。
Blocked → Ready
满足以下任一条件:
挂起状态表示任务被人为暂停执行。
处于挂起态的任务:
挂起是一种“强制退出调度系统”的状态。
任意状态的任务(Running / Ready / Blocked)都可以通过调用vTaskSuspend()
进入挂起状态。
调用该函数后,任务立即从当前状态移除,进入 Suspended 状态。
1)不会自动恢复
与阻塞态不同,挂起态不会因:
而自动回到就绪态。
2)完全脱离调度器管理
调度器不会考虑挂起任务,即使其优先级很高。
必须由其他任务或中断调用:
vTaskResume()或xTaskResumeFromISR()
作用:
Suspended → Ready
优先级的数量在MAX_PRIORITIES中定义,默认为 56。最低的优先级是 0,最高的优先级是宏定义-1 。除此之外,CMSIS2 还提供了一些预设的优先级,在cmsis_os2.h中查看。
当调用 osKernelStart() 启动 FreeRTOS 调度器时,系统会自动创建一个空闲任务(Idle Task)。
特点:
作用:
configUSE_TICK_HOOK作用:
控制是否使用 Tick 钩子函数。
取值:
启用后:
注意:
Tick Hook 在中断上下文中执行,不能调用阻塞函数。
configIDLE_SHOULD_YIELD控制空闲任务是否会对“同优先级任务”主动让出 CPU。
取值:
影响:
configUSE_TICKLESS_IDLE是否启用 Tickless Idle(无节拍空闲模式)。
取值:
启用后:
当有事件(中断)使系统提前或按期唤醒时,内核会在恢复调度前对内核节拍计数进行补偿。
调度特性:
行为特性:
空闲任务是 FreeRTOS 的基础系统任务,
用于保证系统调度完整性,并提供资源回收与低功耗扩展能力。