uCOS学习笔记(二)——从加电到多任务执行

来源:互联网 发布:软件大学生职业规划 编辑:程序博客网 时间:2024/06/09 19:08

uCOS学习笔记(二)

3、ucos操作系统的处理器中自加电至开始多任务执行之间的过程

以MSP430为例,在处理器加电后,CPU从0C00h地址处取指(msp430flash、ram统一编址),那么也是说编译后的二进制代码要存储在0C00h起的位置上。对于嵌入式系统这个入口就是main函数的入口,也就是整个程序的入口,对于非嵌入式操作系统这个入口其实是bios的main用于引导操作系统在内存中建立自身环境。

那么对于嵌入式操作系统的应用中,进入main后(这里main指的是当前程序的main函数),然后系统初始化,建立两个任务空闲任务和统计任务,然后可以按照用户需要调用OSTaskCreate函数生成用户需要的任务,到此只是机械地堆积了几个任务,然而他们怎么有序的执行呢,需要操作系统提供一种强制切换机制,应该这样设计:也就是在完成系统初始化后,设计一个函数开启任务调度,在这个函数内包含有:1、初始化时钟节拍的周期,2、开启时钟节拍中断,3、找到就绪表中优先级最高的任务执行之。

首先通过当前最高优先级找到当前最高优先级任务的任务控制块OS_TCB的首地址,所有的任务控制块的首地址都是保存在OSTCBPrioTb1[]中的,并且为了减少资源浪费,作者在这里只开辟了OS_LOWEST_PRIO + 1大小的数组,找到最高优先级任务的任务控制块首地址后,调用一个非常关键的函数完成任务的执行,即OSStartHighRdy(),这个函数采用汇编实现,主要作用就是将任务栈中保存的值弹回到CPU寄存器中,然后执行一条中断返回指令,中断返回指令强制执行该任务代码(依稀记得linux也是这么实现由setup.s到系统main函数的),从现在开始用户所建立任务中最高优先级任务就开始执行了(这个和linux中由head.s到main.c过程类似)。

任务的调度,在任务执行完后调用OSTimeDly(OS_TICKS_PER_SEC),一般延时两个时钟节拍,在延时函数内会调用OSSched(),先进行一些判断,比如调度器是否上锁,然后得到当前最高优先级,从而得到最高优先级任务的任务控制块的首地址,和上面的OSStartHighRdy()功能类似,接下来需要完成的是将被挂起的任务的CPU寄存器推入堆栈,接着将最高优先级任务的任务栈中保存的值弹回到CPU寄存器中,后面来一句中断返回指令,中断返回指令强制执行较高优先级任务代码,这样就实现了任务的切换。

这样做的好处有,每个任务可以单独被调度,可以单独设定延时项,并且调度是在OSTimeDly(OS_TICKS_PER_SEC)内调用OSSched()实现的,将这个两个函数绑定在一起避免不必要的错误,当然如果要使用μC/OS那么也得按照这个规则,在每个任务的最后要加上OSTimeDly(OS_TICKS_PER_SEC)。

还有一个重要的内容是时钟节拍,事实上时钟节拍和任务调度间没有直接的联系,他们的联系是依赖于OSTimeDly(OS_TICKS_PER_SEC)函数,当时钟节拍中断到来时,进入中断服务函数中执行,任务失去CPU的控制权,在μC/OS中,这个函数是void OSTickISR(void),执行时,首先保存当前的寄存器,DS,ES,DI,SI,BP,SP,BX,DX,CX,AX,完了给每个任务控制块节拍延时减一,延时为零时,将此任务加入就绪表中,调度函数OSSched()会完成剩下的工作,这是时钟节拍的功能。