原创 菜鸟学uC/OS(二)

2008-9-12 09:51 3973 7 8 分类: MCU/ 嵌入式

菜鸟学uC/OS(二)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


By <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />Norman


2008-07-07


 


内核结构分析与理解


 


又被其他事情耽误了两天,不过也好,天天看心头都看毛了。每天看一点可能消化的好一点。废话不多说,学习先^_^


学习内容:


怎样处理临界段代码


什么是任务


怎样通知用户任务


任务是怎样调度的


怎样写中断


时钟节拍


系统初始化


这是邵贝贝老师译文中的学习任务,看后觉得这样挺模糊的。先走一遍再说。


首先是临界段代码:


两个宏:OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()


作者给出三种方式处理临界段代码,这三种方法各有其优缺点,具体可以看书。我所关心的是如何编写。宏定义嘛,比较简单,不过对于不同的处理器和编译器,就要去熟悉指令了,否则也无法实现。在学习中,看到作者使用了两个函数:OSCPUSaveSR()OSCPURestoreSR(),我硬是没有找到在哪里定义的。后来查阅了一些资料,隐约觉得他们应该也是宏定义,定义的是一系列的汇编指令,只不过作者没有使用第三种方法处理中断,所以就没有具体编写了。(这是我看很多移植到文章中写过这样的汇编指令,所以有此想法)可能很弱,但是我确实么有经验啊。先作此想吧。


任务:


这个没有什么好说的,需要注意到是一般不提倡使用0123以及OS_LOWEST_PRIO-3OS_LOWEST_PRIO-2OS_LOWEST_PRIO-1OS_LOWEST_PRIO,因为它们或者是内核任务所需,或者是未来版本系统的保留。再有就是有一个就是在任务状态中,有一个中断服务态(ISR running),在从中断服务子程序中返回之前,系统需要判定优先级,记住,是之前。


任务控制块:


任务控制块数据结构的定义可以多熟悉熟悉,尤其是一些重要的成员。比如OSTCBXOSTCBYOSTCBBitOSTCBBitY等。


注意,TCB在初始化之前(uCOS_II初始化的时候)就创建了空的TCB列表,当任务创建的时候,将一个空的TCB的指针付赋值给任务的TCB就完成了初始化,而OSTCBFreeList则移动向下一个空的TCB。由于空任务控制块列表是提前创建的,因此,任务控制块的个数是确定的,(OS_N_SYS_TASKS+OS_MAX_TASKS)。


就绪表:


这个可是一个比较重要的东西。其主要内容是几个变量:OSRdyGrpOSRdyTbl[]和几个表OSMapTbl[]OSUnMapTbl[]以及就绪表本身。这些东西实现几个功能:使任务进入优先级、脱离优先级以及找出就绪态优先级最高的任务等。具体算法如下:


进入就绪态:


OSRdyGrp |= OSMapTbl[prio >> 3];/*OSRdyGrp相应位置1,找到行号*/


OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];/*OSRdyTbl[OSRdyGrp对应的行]相应位置1*/


脱离就绪态:


其实是个反操作,不过要注意OSRdyTbl[]全部为0才可以将OSRdyGrp相应位清零。


if((OSRdyTbl[prio >>3 ] &= ~OSMapTbl[prio & 0x07]) == 0)


       OSRdyGrp &= ~OSMapTbl[prio >> 3];


这里,用到了常用的置位清零的方法: |=      &= ~。


最高优先级定位:


y = OSUnMapTbl[OSRdyGrp];


x = OSUnMapTbl[OSRdyTbl[y]];


prio = (y << 3) + x;


这里涉及到OSUnMapTbl表,其实这个表的基本思想就是找到变量OSRdyGrpOSrdyTbl[y]的最小位的位置。在网上查找的一段解释很好地印证了我的这一想法。


UC/OS2要得到目前就绪任务中最高优先级任务需要三个公式和一张表: Y = OSUnMapTbl[OSRdyGrp]; X = OSUnMapTbl[OSRdyTbl[y]]; prio = (Y << 3) + X; OSUnMapTbl[] 公式很简单: Y是求出最高优先级的行; X是求出最高优先级的列; OSUnMapTbl[]只有一个目的,就是得到OSRdyGrpOSRdyTbl[y]最小位的位置。 如果OSRdyGrp0x11的话,最小位的位置是0位,查OSUnMapTbl[]就得到Y=0,如果OSRdyGrp0x12的话,最小位位置是1位,查OSUnMapTbl[]就得到Y=1。同理可以的到X的值。再通过prio = Y*8 + X 就可以得到最高优先级。当然,我们可以通过移位或者逐次相与来得到最高优先级,但都没有查表的速度快。不过可以节约ROM空间。】


任务的调度:


关键词:保存与恢复。是的,任务的调度,确切地说是任务的切换就是两步:将被挂起的任务的处理器寄存器压入堆栈;然后将高优先级任务的寄存器值从堆栈中恢复到寄存器中。这里需要注意,为了做到任务切换,uCOS_II运行OS_TASK_SW(),人为模仿了一次中断——软中断。OS_TASK_SW()是一个宏调用,通常都含有微处理器的软中断指令。


在切换过程中,有两个指针需要注意:OSTCBCurOSTCBHighRdy。在切换任务之前,OSTCBCur指向当前正在运行的低优先级任务TCBOSTCBHighRdy指向将要调度运行的就绪的最高优先级任务TCBCPUSP指针指向当前运行的任务堆栈栈顶,而OSTCBHighRdy——>OSTCBStkPtr指向的是将要调度运行的任务的堆栈栈顶。调用OS_TASK_SW()之后,CPU寄存器保存到当前运行的低优先级任务堆栈中,然后,堆栈指针被保存到低优先级任务的TCB中,而使得低优先级任务的OSTCBCur——>OSTCBStkPtr指向堆栈的同一位置——栈顶。任务切换的后期阶段,OSTCBHighRdy——>OSTCBStkPtr指向恢复前的任务堆栈栈顶,CPUSP指针复制该地址,并将该栈中的内容恢复到CPU中继续执行。OSTCBCurOSTCBHighRdy都会指向高优先级任务的TCB


任务切换示意:


Void OSCtxSw(void)


{


       将寄存器压入当前堆栈;


       SOTCBCur——>OSTCBStkPtr = SP;/*SP指向将挂起任务栈顶,然后保存堆栈到TCB*/


       OSTCBCur = OSTCBHighRdy;/*开始切换*/


       SP = OSTCBHighRdy——>OSTCBStkPtr;/*恢复堆栈前先要找到调度任务的堆栈栈顶*/


       将寄存器弹出;


       执行中断返回指令;


}


调度上锁与解锁:


记住一点,调用OSSchedLock()之后,用户应用程序不得调用可能会使当前任务挂起的系统功能函数,否则用户会锁住系统。OSLockNesting变量用于跟踪OSSchedLock()函数被调用的次数。


空闲任务:


空闲任务中,有一个Hook函数,可以在此执行一些功能例如进入低功耗模式等。空闲任务OS_TaskIdle永远是出于就绪态的,不能使用使任务挂起的函数。


统计任务:


这个任务的其他作用目前还不是很清楚,只知道作者在书中用来做CPUUsage统计。统计任务在初始化的时候,应用程序的任务还没有创建,因此,能够运行的就只有空闲和统计任务,因此,计数应该是最大的,而应用程序中的任务创建之后,就没有那么多次来运行空闲任务了,通过这种原理能够得到CPU的利用率。


统计任务初始化的时候,还没有创建应用程序的任务,因此,在系统初始化之后,管理的任务就只有OSStart()OSTaskStat()OSTaskIdle()三个任务,这三个任务按照一定的设定规律运行,在初始化之后得到一个OSTaskIdle的最大运行次数作为计算的依据。


uCOS_II的中断:


同之前单片机时代的中断是相似的。


大概过程如下:


用户中断服务子程序:


       保存全部CPU寄存器


       调用OSIntEnter()或者OSIntNesting直接加1


       if(OSIntNesting == 1)


       {


              OSTCBCur ——>OSTCBStkPtr = SP;


       }


       清中断源


重新开中断


       执行用户代码做中断服务


       调用OSIntExit()


       恢复所有CPU寄存器


       执行中断返回指令


 


整个过程就差不多这个样子了,不过具体的情况还应该有些差别,例如是否重新调度,是否发生中断嵌套等等。


这里还有一个中断级调度——OSIntCtxSW(),这是因为中断发生已经保存了寄存器,如果调用OS_TASK_SW()就会再做一次,没有必要。


uCOS_II的时钟节拍:


严重注意开启时钟节拍器的时间,必须在多任务系统启动之后,也就是在调用OSStart()之后,再开启时钟节拍器。也就是说,调用OSStart()之后应该做的第一件事就是初始化定时器中断。


在内核程序中,中断服务程序写的比较长,这是由其功能决定的,如果想将其缩短,可以写成调用任务的形式:从中断发送一个消息给创建好的节拍邮箱通知节拍服务任务开始时钟节拍。


【在ucos ii的时钟节拍函数中,需要执行用户定义的时钟节拍外连函数OSTimeTickHook (),以及对任务链表进行扫描并且递减任务的延时。这样就造成了时钟节拍函数OSTimeTick ()有两点不足:


在时钟中断中处理额外的任务OSTimeIickHook (),这样增加了中断处理的负担,影响了定时服务的准确性;② 在关中断情况下扫描任务链表,任务越多所需要时间越长,而长时间关中断对中断响应有不利影响,是中断处理应当避免的。】


uCOS_II的初始化和启动:


uCOS_II在调用任何其他服务之前,首先要调用系统初始化函数OSInit()初始化所有的变量和数据结构(OS_CORE.C)。


uCOS_II的启动是通过调用OSStart()实现的,在启动uCOS_II之前,至少应该建立一个应用任务。OSStart()调用高优先级任务启动函数OSStartHighRdy(),这是一个与处理器有关的函数,需要用汇编语言编写,其作用是将任务栈中保存的值弹回到CPU寄存器中,然后执行一条中断返回指令,中断返回指令强制执行该任务代码。


 


总结:


内核的分析比较困扰我,因为以前没有操作系统相关知识,书上写的东西我也是一知半解的,对照书中所讲,结合源码,对uCOS_II的内核结构有了一定的了解,框架搭起来之后,以后再慢慢完善结构吧。


 


(待续)

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户611915 2012-9-27 17:01

OSCPUSaveSR MRS R0, CPSR ; Set IRQ and FIQ bits in CPSR to disable all interrupts ORR R1, R0, #0xC0 MSR CPSR_c, R1 MRS R1, CPSR ; Confirm that CPSR contains the proper interrupt disable flags AND R1, R1, #0xC0 CMP R1, #0xC0 BNE OSCPUSaveSR ; Not properly disabled (try again) MOV PC, LR ; Disabled, return the original CPSR contents in R0 OSCPURestoreSR MSR CPSR_c, R0 MOV PC, LR
相关推荐阅读
用户1407551 2010-06-08 11:28
Protel 带网络复制和粘贴
今天有人问到为什么复制PCB之后网络就消失了,我说,你没有告诉它要不要复制网络,软件不知道你要干啥。复制之后,Paste Special,keep net name即可。其实,这些个软件应该都是有这种...
用户1407551 2010-04-26 19:52
关于Libero8.5安装和卸载的问题!
似乎半年多以前赶一个项目,用到了Actel的FPGA,安装Libero的时候遇到一些困难,想不到过了这么长时间,还有朋友遇到这个问题。回去看了看帖子,还是决定记下来以免以后又不知所措。 基本上这个问题...
用户1407551 2010-04-26 10:44
『转』上拉电阻和下拉电阻
上拉电阻下拉电阻的总结上拉电阻:[52RD.com]1、当TTL电路驱动COMS电路时,如果TTL电路输出的高电平低于COMS电路的最低高电平(一般为3.5V),这时就需要在TTL的输出端接上拉电阻,...
用户1407551 2010-04-26 10:30
『转』吸电流、拉电流、灌电流、上下拉电阻、高阻态
 吸电流、拉电流输出、灌电流输出拉即泄,主动输出电流,从输出口输出电流;灌即充,被动输入电流,从输出端口流入;吸则是主动吸入电流,从输入端口流入。   吸电流和灌电流就是从芯片外电路通过引脚流入芯片内...
用户1407551 2010-04-23 15:01
『转』分贝
分贝分贝表示一种单位,即两种电或声功率之比或两种电压或电流值或类似声量之比;分贝还是一种测量声音相对响度的单位。  fēnbèi   [decibel]   (1)∶表示两种电或声功率之比的一种单位,...
用户1407551 2010-04-22 11:26
电阻的精度和温漂
1、电阻温度系数(TCR)表示电阻当温度改变1度时,电阻值的相对变化,当温度每升高1℃时,导体电阻的增加值与原来电阻的比值。单位为ppm/℃(即10E(-6)·℃)。定义式如下:TCR=dR/R.dT...
EE直播间
更多
我要评论
1
7
关闭 站长推荐上一条 /3 下一条