(1)空闲任务的建立及运行过程
.系统变量常量配置
在程序的最开头,先定义你需要的任务的堆栈大小,优先级,此时CPU已经将系统的一些变量,常量储存于实际物理地址了(例如任务堆栈)
#define .....
...
2.运行到OSInit();
首先是一个主函数,CPU运行第一个函数OSInit();在这里,CPU初始化一些系统变量的值,例如一些任务记数器等.
然后创建两个基本的任务:空闲任务(CPU闲置时就连续运行此任务),统计任务(统计空闲任务,以便计算CPU的使用率).
void Main(void)
{
OSInit();
OSTaskCreate(Main_Task, (void *)0, (OS_STK *)&Main_Stack[TASK_STACK_SIZE-1], Main_PRIO);
OSStart();
}
2.0 初始化一个任务控制快单向链表, .OSTCBNext=下一个, OSTCBFreeList为第一个,如果这个链表被取出一个,则OSTCBFreeList指向空链表里的第一个
2.1 建立空闲任务的过程
2.11 OSTaskStkInit 根据任务函数入口,传递的参数,栈顶,选择项,4个参数决定物理栈顶指针,这个栈里还有其他参数,比如PC值,这些参数都保存在这个物理栈里,在任务开始运行时,将这些值取出,而当任务因为某种原因中断了,则保存这些值,这样下次就能从中断的那个状态再次运行这个任务.
初始化堆栈,从栈顶依次压入,任务函数入口,各个寄存器,这样恢复任务的时候先恢复各个寄存器,最后才将任务函数入口压入PC,从而运行任务
2.12 OSTCBInit 初始化一个任务控制块
将各个参数填入这个控制块,并且生成一个双向任务链表,每次初始化的任务控制块将会添加入链表的左端,这个双向链表在时钟节拍中会用到.
最后在就绪表里将此任务对应的位置一,表示这个任务已经就绪了.
2.13 如果以上都成功了,则任务记数器+1. 接下来会检查OSRunning,如果它为0,说明系统还未运行,这样空闲任务就建立了,等待OSStart 函数开始运行系统,如果OSRunning 为1,说明系统已经运行,这样就执行一次任务调度,任务调度的作用是,如果刚刚建立的任务优先级最高,就运行这个任务. 以下分析任务调度函数
2.131 OSSched 如果任务调度的条件成立,则将就绪表里优先级最高的任务赋予OSPrioHighRdy(等待运行里优先级最高的任务)(这个地方有个疑问:在这个地方运行完后,OSPrioHighRdy和OSPrioRdy会变成什么) 如果这个最高优先级的任务还没运行,那么任务切换计数器+1,执行OS_TASK_SW 任务切换函数. 接下来解析任务切换函数功能
2.1311 OS_TASK_SW 保存处理器的值,将当前任务的堆栈指针保存到当前任务的OS_TCB, (第一次运行OS,这个TCB是否为空闲任务的TCB?) , OSTCBCur , OSPrioCur 赋予最高优先级任务,堆栈指针赋予最高优先级任务指针,将堆栈中的内容恢复,执行中断返回指令,这样就运行了最高优先级任务了,这里就是空闲任务. (疑问:第一次的堆栈有何作用?还是本来就没用?)
2.2 建立完空闲任务,这时空闲任务就运行了,这里又有个疑问,此时系统的最高优先级任务为空闲任务,那么当空闲任务挂起进行任务调度时,那么会运行的不会又是空闲任务? 还是没有跳会到主程序流程? 可能空闲任务里保存了两块堆栈,主流程堆栈和自身的堆栈. 这里不是很理解...不管先,继续往下走,假设系统跳回到任务建立那,接下来也就是要建立统计任务了.
(2)始终节拍函数,统计任务OSTickISR 时钟节拍函数
时钟一到,保存寄存器值,当前的堆栈指针SP赋予OSTCBCur.OSTCBStkPtr,调用OSTimeTick()
OSTimeTick 节拍服务函数
将每个TCB中的.OSTCBDly-1,如果OSTCBDly为0了,任务原先也没有被挂起,就将任务置为就绪态,如果原先被挂起,就先将OSTCBDly为1. 这里有条语句ptcb=OSTCBList ,OSTCBList是?
接着恢复处理器寄存器的值,返回原先的状态.
前面提出的疑问这里突然也得到解决, 因为第一次建立空闲函数,此时OSRUNNING还是为0,所以还不会出现程序在空闲任务处循环的情况,因为空闲任务根本不会运行,这里程序会继续往下走,建立统计任务
OSTaskStat
文章评论(0条评论)
登录后参与讨论