1、μC/OS-Ⅱ是怎样处理临界段代码的?
μC/OS-Ⅱ为了处理临界段代码,避免同时有其它任务或中断服务进入临界段代码,因此需要关中断,处理完毕后再开中断。μC/OS-Ⅱ在文件OS_CPU.H中定义两个宏(macros)来关中断和开中断,以便避开不同C编译器厂商选择不同的方法来处理关中断和开中断。μC/OS-Ⅱ中的这两个宏调用分别是:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。这两个宏的定义取决于所用的微处理器。
2、什么是任务,怎样把用户的任务交给μC/OS-Ⅱ?
一个任务看起来像其它C的函数,通常是一个无限的循环。这里要强调的是任务是没有返回值的,故返回参数必须定义成void。还有一点,任务可以自我删除,当任务完成以后,任务可以自我删除,代码并非真的删除了,只是简单地不再理会这个任务了,这个任务的代码也不会再运行。
3、任务是怎样调度的?
μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那一个任务。 确定哪个任务优先级最高是由调度器(Scheduler)完成的,在程序代码中任务级的调度是由函数OSSched()完成的,中断级的调度是由另一个函数OSIntExt()完成的。
void OSSched (void)
{
INT8U y;
OS_ENTER_CRITICAL();
if ((OSLockNesting | OSIntNesting) == 0) { (1)
y = OSUnMapTbl[OSRdyGrp]; (2)
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); (2)
if (OSPrioHighRdy != OSPrioCur) { (3)
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; (4)
OSCtxSwCtr++; (5)
OS_TASK_SW(); (6)
}
}
OS_EXIT_CRITICAL();
}
首先关中断,再有个判断条件:如果在中断服务子程序中调用OSSched(),此时中断嵌套层数OSIntNesting>0,或者由于用户至少调用了一次给任务调度上锁函数OSSchedLock(),使OSLockNesting>0。如果不是在中断服务子程序调用OSSched(),并且任务调度是允许的,即没有上锁,则任务调度函数将找出那个进入就绪态且优先级最高的任务[L3.8(2)],进入就绪态的任务在就绪任务表中有相应的位置位。一旦找到那个优先级最高的任务,OSSched()检验这个优先级最高的任务是不是当前正在运行的任务,以此来避免不必要的任务调度[L3.8(3)]。
注意,在μC/OS 中曾经是先得到OSTCBHighRdy然后和OSTCBCur做比较。因为这个比较是两个指针型变量的比较,在8位和一些16位微处理器中这种比较相对较慢。而在μC/OS-Ⅱ中是两个整数的比较。并且,除非用户实际需要做任务切换,在查任务控制块优先级表OSTCBPrioTbl[]3-10时,不需要用指针变量来查OSTCBHighRdy。综合这两项改进,即用整数比较代替指针的比较和当需要任务切换时再查表,使得μC/OS-Ⅱ比μC/OS在8位和一些16位微处理器上要更快一些。
为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是通过将以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的[L3.8(4)]。接着,统计计数器OSCtxSwCtr加1,以跟踪任务切换次数[L3.8(5)]。
最后宏调用OS_TASK_SW()来完成实际上的任务切换[L3.8(6)]。(任务切换很简单,由以下两步完成:将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先级的任务的寄存器值从栈中恢复到寄存器中。在μC/OS-Ⅱ中,就绪任务的栈结构总是看起来跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,μC/OS-Ⅱ运行就绪态的任务所要做的一切, 只是恢复所有的CPU寄存器并运行中断返回指令。为了做任务切换,运行OS_TASK_SW(),人为模仿了一次中断。多数微处理器有软中断指令或者陷阱指令TRAP来实现上述操作。中断服务子程序或陷阱处理(Trap hardler),也称作事故处理(exception handler),必须提供中断向量给汇编语言函数OSCtxSw()。OSCtxSw()除了需要OS_TCBHighRdy指向即将被挂起的任务,还需要让当前任务控制块OSTCBCur指向即将被挂起的任务,参见第8章,移植μC/OS-Ⅱ,有关于OSCtxSw()的更详尽的解释。)
OSSched()的所有代码都属临界段代码。在寻找进入就绪态的优先级最高的任务过程中,为防止中断服务子程序把一个或几个任务的就绪位置位,中断是被关掉的。为缩短切换时间,OSSched()全部代码都可以用汇编语言写。为增加可读性,可移植性和将汇编语言代码最少化,OSSched()是用C 写的。
4、应用程序CPU的利用率是多少,μC/OS-Ⅱ是怎样知道的?
usage = (INT8S)(100L - 100L * run / OSIdleCtrMax);通过调用统计任务OSTaskStat()知道的。
具体过程可以参考邵贝贝那本μC/OS-Ⅱ书第三章。
5、怎样写中断服务子程序?
用户中断服务子程序:
1、保存全部CPU寄存器; (1)
2、调用OSIntEnter或OSIntNesting直接加1; (2)
3、执行用户代码做中断服务; (3)
4、调用OSIntEnter; (4)
5、恢复所有CPU寄存器; (5)
6、执行中断返回指令; (6)
以下列出OSIntEnter,OSIntEnter中断开始和推出函数代码。
通知μC/OS-Ⅱ,中断服务子程序开始了:
void OSIntEnter (void)
{
OS_ENTER_CRITICAL();
OSIntNesting++;
OS_EXIT_CRITICAL();
}
通知μC/OS-Ⅱ,脱离了中断服务:
void OSIntExit (void)
{
OS_ENTER_CRITICAL(); (1)
if ((--OSIntNesting | OSLockNesting) == 0) { (2)
OSIntExitY = OSUnMapTbl[OSRdyGrp]; (3)
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) +
OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if (OSPrioHighRdy != OSPrioCur) {
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OSIntCtxSw(); (4)
}
}
OS_EXIT_CRITICAL();
}
< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />
6、什么是时钟节拍,μC/OS-Ⅱ是怎样处理时钟节拍的?
μC/OS需要用户提供周期性信号源,用于实现时间延时和确认超时。而这个信号源所给其提供的时钟信号,时钟节拍源可以是专门的硬件定时器,也可以是来自50/60Hz交流电源的信号。
用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用OSStart()之后。换句话说,在调用OSStart()之后做的第一件事是初始化定时器中断。μC/OS-Ⅱ中的时钟节拍服务是通过在中断服务子程序中调用OSTimeTick()实现的。程序清单L3.20时钟节拍中断服务子程序的示意代码:
void OSTickISR(void)
{
保存处理器寄存器的值;
调用OSIntEnter()或是将OSIntNesting加1;
调用OSTimeTick();
调用OSIntExit();
恢复处理器寄存器的值;
执行中断返回指令;
}
7、μC/OS-Ⅱ是怎样初始化的,以及怎样启动多任务?
先调用系统初始化函数OSIint(),初始化μC/OS-Ⅱ所有的变量和数据结构(见OS_CORE.C)。详细讲解请参看邵贝贝编写的μC/OS-Ⅱ书中第三章相关内容。
多任务的启动是用户通过调用OSStart()实现的。值得注意的是:启动μC/OS-Ⅱ之前,用户至少要建立一个应用任务。以下是一个程序清单:
void main (void)
{
OSInit(); /* 初始化uC/OS-II */
.
.
通过调用OSTaskCreate()或OSTaskCreateExt()创建至少一个任务;
.
.
OSStart(); /* 开始多任务调度!OSStart()永远不会返回 */
}
OSStart()的代码如程序清单:
void OSStart (void)
{
INT8U y;
INT8U x;
if (OSRunning == FALSE) {
y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSRdyTbl[y]];
OSPrioHighRdy = (INT8U)((y << 3) + x);
OSPrioCur = OSPrioHighRdy;
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; (1)
OSTCBCur = OSTCBHighRdy;
OSStartHighRdy(); (2)
}
}
OSStart()从任务就绪表中找出那个用户建立的优先级最高任务的任务控制块[L3.25(1)]。然后,OSStart()调用高优先级就绪任务启动函数OSStartHighRdy()[L3,25(2)],(见汇编语言文件OS_CPU_A.ASM),这个文件与选择的微处理器有关。实质上,函数OSStartHighRdy()是将任务栈中保存的值弹回到CPU寄存器中,然后执行一条中断返回指令,中断返回指令强制执行该任务代码。注意OSStartHighRdy()将永远不返回到OSStart()。下面是调用OSStart()之后的数据结构图:
原文链接:http://cspiao1986.blog.163.com/blog/static/7011397420119392930838?suggestedreading