图1
(1) OS_CPU.H文件
包含μC/OSII所需要的常量、宏和自定义类型等。
① OS_CPU.H定义的数据类型。在这次移植中μC/OSII重新定义了数据类型,如下所示:
typedefunsigned charBOOLEAN;
typedefunsigned charINT8U;
typedefsigned charINT8S;
typedefunsigned shortINT16U;
typedefsignedshortINT16S;
typedefunsigned intINT32U;
typedefsignedintINT32S;
typedeffloatFP32;
typedefdoubleFP64;
typedefunsigned intOS_STK;
typedefunsigned intOS_CPU_SR;
② 修改与ARM处理器相关的内容。不同处理器的堆栈增长方向是不一样的,ARM
CortexM3的堆栈是从高地址往低地址增长的,OS_STK_GROWTH设为1,程
序如下:
#defineOS_STK_GROWTH1
(2) OS_CPU_C.C文件
在OS_CPU_C.C定义的C函数中,OSTaskStkInit(
)函数与CPU相关,所以移植代码需要修改该函数。其程序如下(初始化任务时调用此函数初始化任务使用的堆栈):
OS_STK * OSTaskStkInit(void (*task)(void *p_arg),void *p_arg,OS_STK
*ptos,INT16U opt) {
OS_STK *stk;
(void)opt;//防止编译警告
stk=ptos;//装载栈顶指针,即堆栈数组最后的地址模拟中断发生的堆栈情况
*(stk)=(INT32U)0x01000000L;//xPSR
*(stk) =(INT32U)task;//PC,任务入口
*(stk) =(INT32U)0xFFFFFFFEL;//R14(LR)
*(stk) =(INT32U)0x12121212L;//R12
*(stk) =(INT32U)0x03030303L;//R3
*(stk) =(INT32U)0x02020202L;//R2
*(stk) =(INT32U)0x01010101L;//R1
*(stk) =(INT32U)p_arg;//R0,输入参数p_arg模拟任务进程,保存其他寄存器到堆栈
*(stk) =(INT32U)0x11111111L;//R11
*(stk) =(INT32U)0x10101010L;//R10
*(stk) =(INT32U)0x09090909L;//R9
*(stk) =(INT32U)0x08080808L;//R8
*(stk) =(INT32U)0x07070707L;//R7
*(stk) =(INT32U)0x06060606L;//R6
*(stk) =(INT32U)0x05050505L;//R5
*(stk) =(INT32U)0x04040404L;//R4
return(stk);
}
(3) OS_CPU_A.ASM文件
μC/OSII的移植需要编写5个简单的汇编语言函数。
① OS_ENTER _CRITICAL( ): 关闭中断源。
② OS_EXIT_CRITICAL( ): 重开中断源。
③ OSStartHighRdy( ): 运行当前优先级最高的任务。
④ OSCtxSw( ): 一个任务放弃CPU使用权时调用。
⑤ OSIntCtxSw(): 在退出中断服务函数OSIntExit( )中被调用,实现中断级任务切换。
因为LM3S单片机目前只支持8位中断优先级中的高3位,所以这里把1左移5位即是00100000B,其宏定义为OS_CRITICAL_INT_PRIOEQU(1<<5)。
ARM CortexM3使用OSPendSV( )函数快捷地进行上下文切换。OSPendSV( )的C语言表述程序如下:
OSPendSV:关中断;
if(PSP !=NULL) {
保存R4~R11到任务堆栈SP_process;
OSTCBCur>OSTCBStkPtr = SP_process;
}
OSTaskSwHook( );
OSPrioCur = OSPrioHighRdy;
OSTCBCur = OSTCBHighRdy;
PSP = OSTCBHighRdy>OSTCBStkPtr;
从新任务堆栈中恢复R4~R11;
恢复中断;
异常返回;
完成上述工作后,只要再根据目标板的实际情况编写Target目录中的3个文件,μC/OSII就可以运行在LM3S8962单片机上了。
3 实际应用
移植工作完成后,编写了一段程序,可以进行CAN通信,按键控制LED灯,通过RS232串口与主机相连实现对SD卡的读写等操作。下面是程序的部分代码:
staticOS_STKTask_CardStk[TASK_CARD_STK_SIZE]; /*卡操作任务堆栈*/
staticOS_STKGstkStart[TASK_START_STK_SIZE];/*启动任务的堆栈*/
static OS_STKGstkLed[TASK_LED_STK_SIZE];/*LED任务的堆栈*/
static OS_STKGstkKey[TASK_KEY_STK_SIZE];/*按键任务的堆栈*/
static OS_STKGstkCan[TASK_CAN_STK_SIZE];/*CAN通信任务的堆栈*/
OS_EVENT *Uart0ReviceMbox;/*串口接收数据邮箱*/
OS_EVENT *DispSem;/*按键信号量 */
OS_EVENT *DispSem1;/*CAN接收信号量*/
在Main.H中定义任务优先级为:
#defineTASK_START_PRIO0
#defineTASK_CARD_PRIO1
#defineTASK_LED_PRIO2
#defineTASK_KEY_PRIO3
#defineTASK_CAN_PRIO4
其中创建任务的任务代码为:
static void taskStart (void*parg) {
(void)parg;
DispSem = OSSemCreate(1);
DispSem1 = OSSemCreate(0);
targetInit();/*初始化目标单片机*/
#if OS_TASK_STAT_EN > 0
OSStatInit();/*使能统计功能*/
#endif
/*在这里创建其他任务*/
OSTaskCreate (taskLed, (void *)0,&GstkLed[TASK_LED_STK_SIZE 1],
TASK_LED_PRIO);/*初始化taskLed任务*/
OSTaskCreate ( Task_Card,/*创建SD卡操作任务*/
(void *)0,
&Task_CardStk[TASK_CARD_STK_SIZE 1],
TASK_CARD_PRIO );
OSTaskCreate (taskKey, (void *)0,/*创建按键操作任务*/
&GstkKey[TASK_KEY_STK_SIZE 1],
TASK_KEY_PRIO);
OSTaskCreate (taskCan, (void *)0,/*创建CAN操作任务 */
&GstkCan[TASK_CAN_STK_SIZE 1],
TASK_CAN_PRIO);
while (1) {
OSTaskSuspend(OS_PRIO_SELF);/*启动任务可在这里挂起*/
}
}
SDExample为方便观察SD卡操作任务编写的GUI界面,选好与程序对应的串口波特率,连接好硬件。从图2可以看到,对SD卡可以进行成功操作。
图2
结语
μC/OSII作为一个优秀的实时操作系统,已经被移植到各种体系结构的微处理器上。本设计实现了其在LM3S8962上的成功移植,并通过一个实例验证了移植的正确性。本次移植只是做了一些基础性工作,在此基础上还可进行进一步的开发,充分利用LM3S系列单片机的性能和μC/OSII的特点,在检测与维修领域发挥一定作用。
参考文献
[1] Labrosse Jean J. 嵌入式实时操作系统μC/OSII[M]. 邵贝贝,等译.第2版. 北京:
北京航空航天大学出版社,2003.
[2] 赵宁,陈明,何鹏举.嵌入式操作系统μC/OSII在ARM上的移植与应用[J].计算机技术与应用,2004(4):29 31.
[3] 周立功,等.CortexM3开发指南——基于LM3S8000,2007.
[4] 周立功.ARM微控制器基础与实战[M].北京:北京航空航天大学出版社,2003.
庞海涛(硕士研究生),主要研究方向为光电检测技术。
文章评论(0条评论)
登录后参与讨论