1. 为什么需要空闲任务与阻塞延时
在上一章节中,任务体内的延时使用的是软件延时,即还是让CPU空等来达到延时的效果。而使用RTOS的很大优势就是榨干CPU的性能,永远不能让它闲着。
RTOS中的延时叫阻塞延时,即任务需要延时的时候,任务会放弃CPU的使用权,CPU可以去干其它的事情,当任务延时时间到,重新获取CPU使用权,任务继续运行,这样就充分地利用了CPU的资源,而不是干等着。
如果没有其它任务可以运行,这个时候CPU就运行空闲任务。因为系统保证必须每时每刻都有一个可以运行的任务。
2. 实现空闲任务的步骤
1.定义空闲任务栈,空闲任务的栈在在main.c中定义。
2.定义空闲任务的任务控制块
3.定义空闲任务函数主体
4.创建空闲任务
3. 实现阻塞延时
vTaskDelay()
阻塞延时的阻塞是指任务调用该延时函数后,任务会被剥离CPU使用权,然后进入阻塞状态,直到延时结束,任务重新获取CPU使用权才可以继续运行。
需要在任务控制块中添加成员变量xTicksToDelay
4. 修改vTaskSwitchContext()函数
调用tashYIELD()会产生PendSV中断,在PendSV中断服务函数中会调用上下文切换函数vTaskSwitchContext(),该函数的作用是寻找最高优先级的就绪任务,然后更新pxCurrentTCB。
思路如下:
如果当前任务是空闲任务,那么就去尝试执行任务1或者任务2,看看他们的延时时间是否结束,如果任务的延时时间均没有到期,那就返回继续执行空闲任务。
如果当前任务是任务1或者任务2的话,检查下另外一个任务,如果另外的任务不在延时中,就切换到该任务。否则,判断下当前任务是否应该进入延时状态,如果是的话,就切换到空闲任务,否则就不进行任何切换。
5. SysTick中断服务函数
在这个函数中会判断每个任务的任务控制块中的延时成员xTicksToDelay的值是否为0,如果为0就要将对应的任务就绪,如果不为0就继续延时。
如果一个任务要延时,一开始xTicksToDelay肯定不为0,当xTicksToDelay变为0的时候表示延时结束。
那么xTicksToDelay是以什么周期在递减?在哪里递减?
在FreeRTOS中,这个周期由SysTick中断提供,操作系统里面的最小的时间单位就是SysTick的中断周期,我们称之为一个tick,SysTick中断服务函数在port.c.c中实现。
函数:xPortSysTickHandler()
6. 更新时基xTaskIncrementTick
更新系统时基计数器xTickCount,它是用于记录系统运行的时间的,每当一次SysTick中断,它的值就加一。xTickCount是一个在port.c中定义的全局变量,在函数vTaskStartScheduler()中调用xPortStartScheduler()函数前初始化。
扫描就绪列表中所有任务的xTicksToDelay,如果不为0,则减1。
7. SysTick初始化
SysTick初始化函数在port.c中定义
函数:
vPortSetupTimerInterrupt()
设置重装再寄存器的值
设置系统定时器的时钟等于内核时钟
使能SysTick 定时器中断
使能SysTick 定时器
这个函数在xPortStartScheduler()中被调用