3)OS_STK_GROWTH
绝大多数的微处理器和微控制器的堆栈是从上往下长的。但是某些处理器是用另外一种方式工作的。μC/OS-Ⅱ被设计成两种情况都可以处理,只要在结构常量OS_STK_GROWTH中指定堆栈的生长方式就可以了。
置OS_STK_GROWTH 为0 表示堆栈从下往上长。
置OS_STK_GROWTH 为1 表示堆栈从上往下长。
用c语言编写6个与操作系统相关的函数(OS_CPU_C.C)
1. OsTaskStKInit()
OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInit()来初始化任务的堆
栈结构。因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。
图12-2 显示了OSTaskStkInt()放到正被建立的任务堆栈中的东西。这里我们定义了堆栈是
从上往下长的。
在用户建立任务的时候,用户传递任务的地址,pdata 指针,任务的堆栈栈顶和任务的
优先级给OSTaskCreate()和OSTaskCreateExt()。一旦用户初始化了堆栈,OSTaskStkInit
()就需要返回堆栈指针所指的地址。OSTaskCreate()和OSTaskCreateExt()会获得该地
址并将它保存到任务控制块(OS_TCB)中。
- OS_STK * OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
- {
- unsigned int * stk;
- stk = (unsigned int *)ptos; /* 装载堆栈指针*/
- opt++;
- /* 为新任务建立堆栈*/
- *--stk = (unsigned int) task; /* pc */
- *--stk = (unsigned int) task; /* lr */
- *--stk = 12; /* r12 */
- *--stk = 11; /* r11 */
- *--stk = 10; /* r10 */
- *--stk = 9; /* r9 */
- *--stk = 8; /* r8 */
- *--stk = 7; /* r7 */
- *--stk = 6; /* r6 */
- *--stk = 5; /* r5 */
- *--stk = 4; /* r4 */
- *--stk = 3; /* r3 */
- *--stk = 2; /* r2 */
- *--stk = 1; /* r1 */
- *--stk = (unsigned int) pdata; /* r0 */
- *--stk = (SUPMODE); /* cpsr */
- *--stk = (SUPMODE); /* spsr */
- return ((OS_STK *)stk);
- }
2).OSTaskCreateHook
当用OSTaskCreate()和OSTaskCreateExt ()建立任务的时候就会调用OSTaskCreateHook
()。该函数允许用户或使用移植实例的用户扩展μC/OS-Ⅱ功能。当μC/OS-Ⅱ设置完了自己的内部结构后,会在调用任务调度程序之前调用OSTaskCreateHook()。该函数被调用的时候中断是禁止的。因此用户应尽量减少该函数中的代码以缩短中断的响应时间。当OSTaskCreateHook()被调用的时候,它会收到指向已建立任务的OS_TCB 的指针,这样它就可以访问所有的结构成员了。
函数原型:
void OSTaskCreateHook (OS_TCB *ptcb)
3).OsTaskDelHook()
当任务被删除的时候就会调用OSTaskDelHook()。该函数在把任务从μC/OS-Ⅱ的内部
任务链表中解开之前被调用。当OSTaskDelHook()被调用的时候,它会收到指向正被删除任务的OS_TCB 的指针,这样它就可以访问所有的结构成员了。OSTaskDelHook()可以来检验TCB 扩展是否被建立(一个非空指针)并进行一些清除操作。
函数原型:
void OSTaskDelHook (OS_TCB *ptcb)
4.OsTaskSwHook()
当发生任务切换的时候就会调用OSTaskSwHook()。OSTaskSwHook()可以直接访问
OSTCBCur 和OSTCBHighRdy,因为它们是全局变量。OSTCBCur 指向被切换出去的任务OS_TCB,而OSTCBHighRdy 指向新任务OS_TCB。注意在调用OSTaskSwHook()期间中断一直是被禁止的。因此用户应尽量减少该函数中的代码以缩短中断的响应时间。
函数原型:
void OSTaskSwHook (void)
5.OsTaskStatHook()
OSTaskStatHook()每秒钟都会被OSTaskStat()调用一次。用户可以用OSTaskStatHook
()来扩展统计功能。例如,用户可以保持并显示每个任务的执行时间,每个任务所用的CPU 份额,以及每个任务执行的频率等。
函数原型:
void OSTaskStatHook (void)
6.OsTimeTickHook()
OSTimeTickHook()在每个时钟节拍都会被OSTaskTick()调用。实际上,OSTimeTickHook
()是在节拍被μC/OS-Ⅱ真正处理,并通知用户的移植实例或应用程序之前被调用的。
函数原型:
void OSTimeTickHook (void)
后5 个函数为钩子函数,可以不加代码。只有当OS_CFG.H 中的OS_CPU_HOOKS_EN
被置为1 时才会产生这些函数的代码。
用汇编语言编写4个与处理器相关的函数(OS_CPU_a.asm)
(1)OsStartHighRdy();运行优先级最高的就绪任务
- OSStartHighRdy
- LDR r4, addr_OSTCBCur ; 得到当前任务TCB 地址
- LDR r5, addr_OSTCBHighRdy ; 得到最高优先级任务TCB 地址
- LDR r5, [r5] ; 获得堆栈指针
- LDR sp, [r5] ; 转移到新的堆栈中
- STR r5, [r4] ; 设置新的当前任务TCB 地址
- LDMFD sp!, {r4} ;
- MSR SPSR, r4
- LDMFD sp!, {r4} ; 从栈顶获得新的状态
- MSR CPSR, r4 ; CPSR 处于SVC32Mode 摸式
- LDMFD sp!, {r0-r12, lr, pc } ; 运行新的任务
(2)OS_TaSK_SW();任务级的任务切换函数
- OS_TASK_SW
- STMFD sp!, {lr} ; 保存pc
- STMFD sp!, {lr} ; 保存lr
- STMFD sp!, {r0-r12} ; 保存寄存器和返回地址
- MRS r4, CPSR
- STMFD sp!, {r4} ; 保存当前的PSR
- MRS r4, SPSR
- STMFD sp!, {r4} ; 保存SPSR
- ; OSPrioCur = OSPrioHighRdy
- LDR r4, addr_OSPrioCur
- LDR r5, addr_OSPrioHighRdy
- LDRB r6, [r5]
- STRB r6, [r4]
- ; 得到当前任务TCB 地址
- LDR r4, addr_OSTCBCur
- LDR r5, [r4]
- STR sp, [r5] ; 保存sp 在被占先的任务的TCB
- ; 得到最高优先级任务TCB 地址
- LDR r6, addr_OSTCBHighRdy
- LDR r6, [r6]
- LDR sp, [r6] ; 得到新任务堆栈指针
- ; OSTCBCur = OSTCBHighRdy
- STR r6, [r4] ; 设置新的当前任务的TCB 地址
- ;保存任务方式寄存器
- LDMFD sp!, {r4}
- MSR SPSR, r4
- LDMFD sp!, {r4}
- MSR CPSR, r4
- ; 返回到新任务的上下文
- LDMFD sp!, {r0-r12, lr, pc}