打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
嵌入式系统UCOS2学习
http://blog.sina.com.cn/s/blog_5f0bed160100tqnv.html
2011
3、非空闲任务控制块双向链表
ucos-II的任务状态
l 睡眠态(Dormant):指任务驻留在程序空间之中,还没有交给μC/OS-Ⅱ管理。把任务交给μC/OS-Ⅱ是通过调用下述两个函数之一:OSTaskCreate()或OSTaskCreateExt()。一个任务可以通过调用OSTaskDel()返回到睡眠态,或通过调用该函数让另一个任务进入睡眠态。
l 就绪态:当任务一旦建立,这个任务就进入就绪态准备运行。
l 运行态:调用OSStart()可以启动多任务。OSStart()函数运行进入就绪态的优先级最高的任务。就绪的任务只有当所有优先级高于这个任务的任务转为等待状态,或者是被删除了,才能进入运行态。
l 等待状态:正在运行的任务可以通过调用两个函数之一将自身延迟一段时间,这两个函数是OSTimeDly()或OSTimeDlyHMSM()。这个任务于是进入等待状态。正在运行的任务期待某一事件的发生时也要等待,手段是调用以下几个函数之一:OSFlagPend()、OSSemPend()、OSMutexPend()、OSMboxPend(),或OSQPend()。如果某事件未发生,调用后任务进入了等待状态(WAITING)。
l 中断服务态:正在运行的任务是可以被中断的,除非该任务将中断关了,或者μC/OS-Ⅱ将中断关了。被中断了的任务就进入了中断服务态(ISR)。
任务控制块TCB的管理
1、任务块数组定义
(OS_EXT OS_TCB OSTCBTbl[OS_MAX_TASKS+OS_N_SYS_TASKS];)
应用程序中可以有的最多任务数(OS_MAX_TASKS)是在文件OS_CFG.H中定义的。这个最多任务数也是μC/OS-Ⅱ分配给用户程序的最多任务控制块OS_TCBs的数目。将OS_MAX_TASKS的数目设置为用户应用程序实际需要的任务数可以减小RAM的需求量。所有的任务控制块OS_TCBs都是放在任务控制块列表数组OSTCBTbl[]中的。请注意,μC/OS-Ⅱ分配给系统任务OS_N_SYS_TASKS若干个任务控制块,见文件μC/OS-Ⅱ.H,供其内部使用。目前,一个用于空闲任务,另一个用于任务统计(如果OS_TASK_STAT_EN是设为1的)。
2、空闲任务块单向链表的创建
(空任务控制块指针:OSTCBFreeList
OS_EXT OS_TCB *OSTCBFreeList; )
在μC/OS-Ⅱ初始化的时候,如图3.2所示,所有任务控制块OS_TCBs被链接成单向空任务链表(OS_core.c:OS_InitTCBList()函数完成)。当任务一旦建立,空任务控制块指针OSTCBFreeList指向的任务控制块便赋给了该任务,然后OSTCBFreeList的值调整为指向下链表中下一个空的任务控制块。一旦任务被删除,任务控制块就还给空任务链表。
3、非空闲任务控制块双向链表
(OS_EXT OS_TCB *OSTCBList;)
.OSTCBNext和.OSTCBPrev用于任务控制块OS_TCBs的双重链接。每个任务的任务控制块OS_TCB在任务建立的时候被链接到链表中,在任务删除的时候从链表中被删除。双重连接的链表使得任一成员都能被快速插入或删除。该链表在时钟节拍函数OSTimeTick()中使用,用于刷新各个任务的任务延迟变量.OSTCBDly。
就绪表及优先级相关计算
图3.3μC/OS-Ⅱ就绪表
表 T3.1 OSMapTbl[]={0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,0x80};
Index
BitMask (Binary)
0
00000001
1
00000010
2
00000100
3
00001000
4
00010000
5
00100000
6
01000000
7
10000000
任务就绪表由2个变量表示
OS_EXT INT8U OSRdyGrp;
OS_EXT INT8UOSRdyTbl[OS_RDY_TBL_SIZE];
OSRdyGrp:共8bits,用于分组标志
OSRdyTbl[]:共8个字节,字节的每位表示任务的组内标志(每个字节表示一组)。
在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl[]中的相应元素的相应位也置位。就绪表OSRdyTbl[]数组的大小取决于OS_LOWEST_PR1O(见文件OS_CFG.H)。
任务优先级0-63,可用6bits表示。将其分为两部分:高3bits和低3bits。
其中,高3位用于表示该任务所在的组;低3位用于表示该任务组内的位置。
程序清单 L3.5使任务进入就绪态
OSRdyGrp |= OSMapTbl[prio>> 3];//组标志置位
OSRdyTbl[prio>> 3] |= OSMapTbl[prio& 0x07];//组内标志置位
(prio>>3的值为任务所在的组,prio&0x07的值表示任务所在的位)
其中OSRdyGrp、OSRdyTbl和OSMapTbl的表示如下图。
图3.3μC/OS-Ⅱ就绪表
表 T3.1 OSMapTbl[]={0x01, 0x02,0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
Index
Bit Mask(Binary)
0
00000001
1
00000010
2
00000100
3
00001000
4
00010000
5
00100000
6
01000000
7
10000000
程序清单 L3.6从就绪表中删除一个任务
if ((OSRdyTbl[prio>> 3] &=~OSMapTbl[prio & 0x07]) == 0)
OSRdyGrp&= ~OSMapTbl[prio >>3];
以上代码将就绪任务表数组OSRdyTbl[]中相应元素的相应位清零,而对于OSRdyGrp,只有当被删除任务所在任务组中全组任务一个都没有进入就绪态时,才将相应位清零。也就是说OSRdyTbl[prio>>3]所有的位都是零时,OSRdyGrp的相应位才清零。
程序清单 L3.7找出进入就绪态的优先级最高的任务
y =OSUnMapTbl[OSRdyGrp];//优先级最高的所在的组
x =OSUnMapTbl[OSRdyTbl[y]];//组内优先级最高的位
prio = (y<< 3) + x;//还原成优先级
为了找到那个进入就绪态的优先级最高的任务,并不需要从OSRdyTbl[0]开始扫描整个就绪任务表,只需要查另外一张表,即优先级判定表OSUnMapTbl([256])(见文件OS_CORE.C)。OSRdyTbl[]中每个字节的8位代表这一组的8个任务哪些进入就绪态了,低位的优先级高于高位。利用这个字节为下标来查OSUnMapTbl这张表,返回的字节就是该组任务中就绪态任务中优先级最高的那个任务所在的位置。这个返回值在0到7之间。
OSUnMapTbl中的每个元素表示0x00~0xFF的每个数的二进制表示中最低位1出现的位置。
任务调度
任务级的任务调度器:OS_Sched()->OS_TASK_SW->OSCtxSw()
如果在中断服务子程序中调用OSSched(),此时中断嵌套层数OSIntNesting>0,或者由于用户至少调用了一次给任务调度上锁函数OSSchedLock(),使OSLockNesting>0,任务调度函数OSSched()将退出,不做任务调度。
任务调度函数OS_Sched将找出那个进入就绪态且优先级最高的任务OSPrioHighRdy[L3.8(2)],进入就绪态的任务在就绪任务表中有相应的位置位。一旦找到那个优先级最高的任务,OSSched()检验这个优先级最高的任务是不是当前正在运行的任务,以此来避免不必要的任务调度[L3.8(3)]。为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是通过将以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的[L3.8(4)]。接着,统计计数器OSCtxSwCtr加1,以跟踪任务切换次数[L3.8(5)]。最后宏调用OS_TASK_SW()来完成实际上的任务切换[L3.8(6)]。
任务切换很简单,由以下两步完成,将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先级的任务的寄存器值从栈中恢复到寄存器中。还需要让当前任务控制块OSTCBCur指向即将被执行的任务。
程序清单 L3.11任务切换的示意代码:OSCtxSw
voidOSCtxSw(void)
{
将R1、R2、R3……等寄存器的值推入当前堆栈;
OSTCBCur->OSTCBStkPtr =SP;
OSTCBCur = OSTCBHighRdy;
SP =OSTCBCur->OSTCBStkPtr;
将R1、R2、R3……等寄存器的值从堆栈弹出;
执行中断返回指令;
}
基于ARM920T的OSCtxSw实现分析:
首先必须了解,在将ucos-II移植到ARM920T时,使用了如下结构的任务栈:
程序清单:基于ARM920T的OSCtxSw实现分析
注意:ARM需手动保存pc和psw
OSCtxSw
; Special optimised code below:
;1、根据任务栈结构,分别压栈,保存旧任务的现场
stmfd sp!,{lr} ; push pc (lr should bepushed in place of PC)
stmfd sp!,{r0-r12,lr} ; push lr& register file
mrs r4,cpsr
stmfd sp!,{r4} ; push currentpsr
mrs r4,spsr
stmfd sp!,{r4} ; push currentspsr
; 2、OSPrioCur =OSPrioHighRdy
ldr r4,=OSPrioCur
ldr r5,=OSPrioHighRdy
ldrb r6,[r5]
strb r6,[r4]
; 3、Get current task TCBaddress:r5= OSTCBCur
ldr r4,=OSTCBCur; r4 =&OSTCBCur
ldr r5,[r4]
;4、OSTCBCur->OSTCBStkPtr= SP;
str sp,[r5] ; store sp in preemptedtasks's TCB
bl OSTaskSwHook ; call Task SwitchHook
; 5、Get highest priority taskTCB address:r6= OSTCBHighRdy
ldr r6,=OSTCBHighRdy
ldr r6,[r6]
; 6、SP = OSTCBHighRdy->OSTCBStkPtr;
ldr sp,[r6] ; get new task's stackpointer
; 7、OSTCBCur =OSTCBHighRdy
str r6,[r4] ; set new current task TCBaddress
;8、根据任务栈结构,分别出栈,恢复新任务的现场
ldmfd sp!,{r4} ; pop new task'sspsr
msr SPSR_cxsf,r4
ldmfd sp!,{r4} ; pop new task'spsr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ; pop new task'sr0-r12,lr & pc
//基于CortexM3的任务级切换:
刚开始启动内核时候,也是通过触发PendSV异常实现最高优先级任务执行。
OSStartHighRdy
LDR    R0,=NVIC_SYSPRI2
; Set the PendSV exception priority等于号表示取等于号后面的NVIC_SYSPRI2所值的的Memory Address里的值付给R0
;将NVIC_SYSPRI2本身作为地址传递给R0
LDR    R1, =NVIC_PENDSV_PRI
;将NVIC_PENDSV_PRI传递个R1
STRB    R1,[R0]   ;STRB means " Store bytefrom register to memory "
;将R1的内容付给R0所指向的地址
MOVS    R0,#0                                             ; Set the PSP to 0 for initial context switch call
MSR    PSP, R0
LDR    R0,__OS_Running                                   ; OSRunning = TRUE
MOVS    R1,#1
STRB    R1,[R0]
LDR    R0,=NVIC_INT_CTRL                                 ; Trigger the PendSV exception (causes context switch)
LDR    R1, =NVIC_PENDSVSET
STR    R1, [R0]  ;将R1的值付给R0的内容所指向的地址
;STR means " Store word from register to memory"
CPSIE  I  ;开总中断                                      ; Enable interrupts at processor level
OSStartHang
B      OSStartHang
主动任务切换,通过PendSV 异常来实现。
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From task level)
;void OSCtxSw(void)
; Note(s) : 1) OSCtxSw() is called when OS wants to perform a taskcontext switch.  Thisfunction triggers the PendSV exception which iswhere the real work is done.
通过触发一个PendingSV异常实现任务切换。
;*********************************************************************************************************
OSCtxSw    ;悬起PSV异常
;PUSH    {R0,R1} ;自己添加的代码
LDR    R0,=NVIC_INT_CTRL                                 ; Trigger the PendSV exception (causes context switch)
LDR    R1, =NVIC_PENDSVSET
STR    R1, [R0]
;POP    {R0, R1} ;自己添加的代码
BX     LR ;程序结束
;*********************************************************************************************************
中断级的任务调度器:OSIntExt()
脱离中断函数OSIntExit()[L3.15(4)]标志着中断服务子程序的终结,OSIntExit()将中断嵌套层数计数器减1。当嵌套计数器减到零时,所有中断,包括嵌套的中断就都完成了,此时μC/OS-Ⅱ要判定有没有优先级较高的任务被中断服务子程序(或任一嵌套的中断)唤醒了。如果有优先级高的任务进入了就绪态,μC/OS-Ⅱ就返回到那个高优先级的任务,OSIntExit()返回到调用点[L3.15(5)]。保存的寄存器的值是在这时恢复的,然后是执行中断返回指令[L3.16(6)]。注意,如果调度被禁止了(OSIntNesting>0),μC/OS-Ⅱ将被返回到被中断了的任务。
OSIntExit()看起来非常像OSSched()。但有三点不同。第一点,OSIntExit()使中断嵌套层数减1[L3.17(2)]而调度函数OSSched()的调度条件是:中断嵌套层数计数器和锁定嵌套计数器(OSLockNesting)二者都必须是零。第二个不同点是,OSRdyTbl[]所需的检索值Y是保存在全程变量OSIntExitY中的[L3.17(3)]。这是为了避免在任务栈中安排局部变量。这个变量在哪儿和中断任务切换函数OSIntCtxSw()有关,(见9.04.03节,中断任务切换函数)。最后一点,如果需要做任务切换,OSIntExit()将调用OSIntCtxSw()[L3.17(4)]而不是调用OS_TASK_SW(),正像在OSSched()函数中那样。
基于ARM920T的OSIntCtxSw()实现分析:
程序清单:基于ARM920T的OSIntCtxSw()实现分析:
_IntCtxSw
; OSIntCtxSwFlag = 0
mov r1,#0
str r1,[r0]
;现将这些寄存器的值重新恢复。
ldmfd sp!,{r0-r3,r12,lr}
;将r0-r3重新保存回中断模式下的栈空间
stmfd sp!,{r0-r3}
;保存中断模式下的栈顶指针sp到r1:r1 =sp_irq
mov r1,sp
add sp,sp,#16; sp_irq += 16;
;计算被中断任务的中断返回地址: r2 = lr– 4
sub r2,lr,#4
;取中断前的状态寄存器到r3
mrs r3,spsr
orr r0,r3,#NOINT;屏蔽中断
;返回用户模式(切换到用户堆栈),以便下面保存中断现场
msr cpsr_cxsf,r0
;ldr r0,=.+8
;movs pc,r0;自动切换到用户堆栈
;根据任务栈结构,分别压栈,保存旧任务的现场
stmfd sp!,{r2} ; push old task'spc
stmfd sp!,{r4-r12,lr} ; push old task'slr,r12-r4
;r1为中断栈的栈顶指针,r4 =r1
mov r4,r1 ; Special optimised codebelow
;r3为中断前状态寄存器cpsr,r5 =r3
mov r5,r3
;将保存在中断栈中的r0-r3保存到任务栈中,r4为中断栈的栈顶指针
ldmfd r4!,{r0-r3}
stmfd sp!,{r0-r3} ; push old task'sr3-r0
;保存任务的cpsr到任务栈
stmfd sp!,{r5} ; push old task'spsr
;保存任务的spsr到任务栈
mrs r4,spsr
stmfd sp!,{r4} ; push old task'sspsr
; OSPrioCur =OSPrioHighRdy
ldr r4,=OSPrioCur
ldr r5,=OSPrioHighRdy
ldrb r5,[r5]
strb r5,[r4]
; Get current task TCB address:r5=OSTCBCur
ldr r4,=OSTCBCur
ldr r5,[r4]
;OSTCBCur->OSTCBStkPtr =SP;
str sp,[r5] ; store sp in preemptedtasks's TCB
bl OSTaskSwHook ; call Task SwitchHook
; Get highest priority task TCBaddress:r6= OSTCBHighRdy
ldr r6,=OSTCBHighRdy
ldr r6,[r6]
;SP = OSTCBHighRdy->OSTCBStkPtr;
ldr sp,[r6] ; get new task's stackpointer
; OSTCBCur =OSTCBHighRdy
str r6,[r4] ; set new current task TCBaddress
;根据任务栈结构,分别出栈,恢复新任务的现场
ldmfd sp!,{r4} ; pop new task'sspsr
msr SPSR_cxsf,r4
ldmfd sp!,{r4} ; pop new task'spsr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ; pop new task'sr0-r12,lr & pc
基于CortexM3中断返回实现任务切换如下:
;************************************************************************* ;Notes:    1)OSIntCtxSw() is called by OSIntExit() when it determines a contextswitch is needed as the result of an interrupt. This function simply triggers a PendSV exception which will behandled when there are no more interrupts active and interrupts areenabled.
;这个函数发生在OSIntExit退出时,此时触发一个PendingSV异常,这个异常如果此时没有其他中断发生,这个异常会被捕获并且执行。。。。********************************
OSIntCtxSw   ;悬起PSV异常
;PUSH    {R0,R1} ;自己添加的代码
LDR    R0,=NVIC_INT_CTRL                                 ; Trigger the PendSV exception (causes context switch)
LDR    R1, =NVIC_PENDSVSET
STR    R1, [R0]
;POP    {R0, R1} ;自己添加的代码
BX     LR
//异常捕获执行代码:
;*********************************************************************************************************
;                                        HANDLE PendSV EXCEPTION
;                                           void OSPendSV(void)
;
; Note(s) : 1) OSPendSV is used to cause a contextswitch.  This is a recommended method forperforming   context switches with Cortex-M3.  This is becausethe Cortex-M3 auto-saves half of the
;             processor context on any exception, and restores same on returnfrom exception.  So only
;             saving of R4-R11 is required and fixing up the stackpointers.  Using the PendSV exception
;             this way means that context saving and restoring is identicalwhether it is initiated from
;             a thread or occurs due to an interrupt or exception.
;
;          2) Pseudo-code is:
;             a) Get the process SP, if 0 then skip (goto d) the saving part(first context switch);
;             b) Save remaining regs r4-r11 on process stack;
;             c) Save the process SP in its TCB,OSTCBCur->OSTCBStkPtr = SP;
;             d) Call OSTaskSwHook();
;             e) Get current high priority, OSPrioCur = OSPrioHighRdy;
;             f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
;             g) Get new process SP from TCB, SP =OSTCBHighRdy->OSTCBStkPtr;
;             h) Restore R4-R11 from new process stack;
;             i) Perform exception return which will restore remainingcontext.
;
;          3) On entry into OSPendSV handler:
;             a) The following have been saved on the process stack (byprocessor):
;                xPSR, PC, LR, R12, R0-R3
;             b) Processor mode is switched to Handler mode (from Threadmode)
;             c) Stack is Main stack (switched from Process stack)
;             d)OSTCBCur     points to the OS_TCB of the task to suspend
;                OSTCBHighRdy  points to the OS_TCB of the task toresume
;
;          4) Since OSPendSV is set to lowest priority in the system (byOSStartHighRdy() above), we
;             know that it will only be run when no other exception or interruptis active, and
;             therefore safe to assume that context being switched out was usingthe process stack (PSP).
;*********************************************************************************************************
利用PendSV实现任务切换,This is because the Cortex-M3 auto-saves half ofthe
; processor context on any exception, So only
; saving of R4-R11 is required and fixing up the stack pointers.Using the PendSV exception this way means that context saving andrestoring is identical whether it is initiatedfrom a thread or occurs due to an interrupt orexception。上面的意思就是说,无论从任务实现切换,还是从中断引发切换,都无所谓,一样对待。。。
Since OSPendSV is set to lowest priority in the system (byOSStartHighRdy() above), we know that it will onlybe run when no other exception or interrupt is active,and therefore safe to assume that context beingswitched out was using the process stack (PSP).
上面的意思是:因为OSPendingSV被设置为最低优先级(通过OSStartHighRdy),所有当没有其他中断在运行的时候,这个PendSV异常才会运行,避免了在中断中实现任务切换的隐患。
;Cortex-M3进入异常服务例程时,自动压栈了R0-R3,R12,LR(R14,连接寄存器),PSR(程序状态寄存器)和PC(R15).并且在返回时自动弹出
OSPendSV
MRS    R3,PRIMASK
CPSID   I
MRS    R0, PSP
; PSP is process stackpointer 将PSP的内容付给R0
CBZ    R0, OSPendSV_nosave
; skip register save the firsttime 如果是第一次进入,则跳过寄存器压栈的操作
SUBS    R0, R0,#0x20
; save remaining regs r4-11 on processstack
STM    R0, {R4-R11};
//STM instructions store the word values in the registers inreglist to memory addresses based on Rn
LDR    R1,__OS_TCBCur
; OSTCBCur->OSTCBStkPtr =SP;
LDR    R1, [R1]
;在R1起始处偏移了R1内容个offset的Memory里的数据然后给R1
STR    R0,[R1]
; R0 is SP of process being switchedout
;将R0的值写入到R1内容所指向的地址中
; at this point, entire context of process has been saved
OSPendSV_nosave
PUSH   {R14}
; need to save LR exc_return value
LDR    R0,__OS_TaskSwHook
; OSTaskSwHook();
BLX    R0
POP    {R14}
LDR    R0,__OS_PrioCur
; OSPrioCur = OSPrioHighRdy;
LDR    R1, __OS_PrioHighRdy
LDRB    R2,[R1]
STRB    R2,[R0]
LDR    R0,__OS_TCBCur
; OSTCBCur  = OSTCBHighRdy;
LDR    R1, __OS_TCBHighRdy
LDR    R2, [R1]
STR    R2, [R0]
LDR    R0,[R2]
; R0 is new process SP; SP =OSTCBHighRdy->OSTCBStkPtr;
LDM    R0,{R4-R11}
; restore r4-11 from new process stack
ADDS    R0, R0,#0x20
MSR    PSP,R0
; load PSP with new process SP
ORR    LR, LR,#0x04
; ensure exception return uses processstack
;MSR    PRIMASK, R3  ;
BX     LR                                                 ; exception return will restore remaining context
任务调度注意事项:
调用OSSchedLock()以后,用户的应用程序不得使用任何能将现行任务挂起的系统调用。也就是说,用户程序不得调用OSMboxPend()、OSQPend()、OSSemPend()、OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()或OSTimeDlyHMSM(),直到OSLockNesting回零为止。因为调度器上了锁,用户就锁住了系统,任何其它任务都不能运行。
空闲任务OSTaskIdle()是永远处于就绪状态的,故不要在OSTaskIdleHook()中调用任何可以使任务挂起的Pend函数、OStimeDly???函数以及OSTaskSuspend()函数。
2008-11-4
ucOS-II的中断处理
初始化中断向量,编写中断引导程序
程序清单 L3.15 μC/OS-II中的中断服务子程序.
用户中断服务子程序:
保存全部CPU寄存器; (1)
调用OSIntEnter或OSIntNesting直接加1;(2)
执行用户代码做中断服务; (3)
调用OSIntExit(); (4)
恢复所有CPU寄存器; (5)
执行中断返回指令; (6)
用户代码应该将全部CPU寄存器推入当前任务栈[L3.15(1)]。注意,有些微处理器,例如Motorola68020(及68020以上的微处理器),做中断服务时使用另外的堆栈(ARM也是)。
μC/OS-Ⅱ可以用在这类微处理器中,当任务切换时,寄存器是保存在被中断了的那个任务的栈中的。
程序清单: 基于ARM920T的中断处理过程
UCOS_IRQHandler//中断入口地址,在中断向量表初始化时被设置
;保存现场,先将任务的现场保存到中断栈中
stmfd sp!,{r0-r3,r12,lr}
;调用相关函数
bl OSIntEnter
bl C_IRQHandler
;调用OSIntExit函数,该函数判断是否有更高优先级的任务进入就绪
bl OSIntExit
;if(OSIntCtxSwFlag == 1)_IntCtxSw()
ldr r0,=OSIntCtxSwFlag
ldr r1,[r0]
cmp r1,#1
;有更高优先级的任务进入了就绪状态,则进行中断级的任务切换,返回执行新的任务
beq _IntCtxSw
;恢复现场
ldmfd sp!,{r0-r3,r12,lr}
;下面的指令令pc =lr-4实现中断返回,同时将spsr_irq的值复制到CPSR,实现模式切换(即返回到用户模式)
subs pc,lr,#4
Ⅱ初始化
在调用μC/OS-Ⅱ的任何其它服务之前,μC/OS-Ⅱ要求用户首先调用系统初始化函数OSIint()。OSIint()初始化μC/OS-Ⅱ所有的变量和数据结构(见OS_CORE.C)。
OSInit()建立空闲任务idletask,这个任务总是处于就绪态的。空闲任务OSTaskIdle()的优先级总是设成最低,即OS_LOWEST_PRIO。如果统计任务允许OS_TASK_STAT_EN和任务建立扩展允许都设为1,则OSInit()还得建立统计任务OSTaskStat()并且让其进入就绪态。OSTaskStat的优先级总是设为OS_LOWEST_PRIO-1。
图3.7调用OSInit()之后的数据结构
μC/OS-Ⅱ还初始化了5个空数据结构缓冲区,如图F3.8所示。每个缓冲区都是单向链表,允许μC/OS-Ⅱ从缓冲区中迅速得到或释放一个缓冲区中的元素。
图3.8空缓冲区(图中还有OSFlagFreeList链表未画出)
Ⅱ的启动
多任务的启动是用户通过调用OSStart()实现的。然而,启动μC/OS-Ⅱ之前,用户至少要建立一个应用任务。多任务启动以后变量与数据结构中的内容如图F3.9所示。
图3.9调用OSStart()以后的变量与数据结构
这里笔者假设用户建立的任务优先级为6,注意,OSTaskCtr指出已经建立了3个任务。OSRunning已设为“真”,指出多任务已经开始,OSPrioCur和OSPrioHighRdy存放的是用户应用任务的优先级,OSTCBCur和OSTCBHighRdy二者都指向用户任务的任务控制块。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
UC/OS-II的详细移植笔记 两种处理器的移植比较(S1C33209&&S3C44BOX)
我的ucos学习分析
uCOS II的移植步骤
【转】OSIntCtxSw的详解和编写
uC/OS-II源码分析(六)任务级的调度
ucos学习资料
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服