2478ucostouchOK总体思路.docx
- 文档编号:27976776
- 上传时间:2023-07-07
- 格式:DOCX
- 页数:21
- 大小:23.47KB
2478ucostouchOK总体思路.docx
《2478ucostouchOK总体思路.docx》由会员分享,可在线阅读,更多相关《2478ucostouchOK总体思路.docx(21页珍藏版)》请在冰豆网上搜索。
2478ucostouchOK总体思路
uC/OS-II移植到ARM7
1.OS_CPU.H的相应修改
OS_CPU.H包括了与编译器相关的数据类型定义和与微处理器相关的常数、宏以及类型。
不同微处理器中有不同的字长,所以必须定义一系列数据类型以确保移植的正确性;同时针对ARM7体系结构的特点,利用2个宏,OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL)选择了开/关中断方式。
2.OS_CPU_C.C的相应修改
OS_CPU_C.C包括了10个与操作系统相关的用C语言编写的函数:
OSTaskStklnit(),OSTaskCre-ateHook(),OSTaskDelHook(),OSTaskSwHook(),OSTaskIdleHook(),OSTaskStatHook(),OS-TimeTickHook),OSInitHookBegin),OSInitHook-End(),OSTCBInitHook()。
OSTaskStklnit()函数是系统运行时必须调用的,初始化任务的栈结构,
针对ARM7体系结构的特点进行初始化栈,将所有寄存器保存在堆栈中;后9个函数是钩子函数,可以不加代码,只需声明即可。
3.OS_CPU_ASM.S的相应修改
OS_CPU_ASM.S包括了4个与操作系统和微处理器硬件相关的用汇编语言编写的函数:
OS-StartHighRdy),OSCtxsw(),OSIntCtxSw),0-STickISR()。
OSStartHighRdy)函数使系统运行优先级最高的就绪任务;因为使用了软中断指令SWI,所以可将OSCtxsw)函数和OSIntCtxSw)函数用一段代码实现,完成中断任务的堆栈操作;OSTickISR()函数提供一个周期性的时钟源,实现时间的延迟和超时功能。
UCOS软件工程
思路分析
(一)从main函数开始,UC/OS-IImain函数的大致流程如下:
main(){
BSP_IntDisAll();
OSInit();
TaskCreate();
OSStart();
}
首先调用BSP_IntDisAll()关闭所有中断和OSInit进行初始化,然后使用TaskCreate创建几个进程/Task,最后调用OSStart,操作系统就开始运行了。
OSInit
OSInit完成以下初始化:
voidOSInit(void)
{
OSInitHookBegin();/*Callportspecificinitializationcode*/
OS_InitMisc();/*Initializemiscellaneousvariables*/
OS_InitRdyList();/*InitializetheReadyList*/
OS_InitTCBList();/*InitializethefreelistofOS_TCBs*/
OS_InitEventList();/*InitializethefreelistofOS_EVENTs*/
(OS_FLAG_EN>0)&&(OS_MAX_FLAGS>0)
OS_FlagInit();/*Initializetheeventflagstructures*/
#endif
#if(OS_MEM_EN>0)&&(OS_MAX_MEM_PART>0)
OS_MemInit();/*Initializethememorymanager*/
#endif
#if(OS_Q_EN>0)&&(OS_MAX_QS>0)
OS_QInit();/*Initializethemessagequeuestructures*/
#endif
OS_InitTaskIdle();/*CreatetheIdleTask*/
#ifOS_TASK_STAT_EN>0
OS_InitTaskStat();/*CreatetheStatisticTask*/
#endif
#ifOS_TMR_EN>0
OSTmr_Init();/*InitializetheTimerManager*/
#endif
OSInitHookEnd();/*Callportspecificinit.code*/
#ifOS_DEBUG_EN>0
OSDebugInit();
#endif
}
逐一分析:
1.OSInitHookBegin(void)在OS_CPU_C.C中
功能:
被OSInit()在开始的时候调用,是系统初始化开始接口函数
2.OS_InitMisc(void)在OS_CORE.C中
功能:
完成的是一些其他变量的初始化:
OSIntNesting =0;
OSLockNesting=0;
OSTaskCtr =0;
OSRunning =OS_FALSE;
OSCtxSwCtr =0;
OSIdleCtr =0L;
其中包括:
中断嵌套标志OSIntNesting,调度锁定标志OSLockNesting,OS标志OSRunning等。
OSRunning在这里设置为OS_FALSE,在后面(OS_CPU_A.ASM内)OSStartHighRdy中会被设置为TRUE表示OS开始工作。
3.OS_InitRdyList(void)在OS_CORE.C中
功能:
初始化就绪Task列表
staticvoidOS_InitRdyList(void)
{
INT8Ui;
#ifOS_LOWEST_PRIO<=63
INT8U*prdytbl;
#else
INT16U*prdytbl;
#endif
OSRdyGrp=0;/*Clearthereadylist*/
prdytbl=&OSRdyTbl[0];
for(i=0;i *prdytbl++=0; } OSPrioCur=0; OSPrioHighRdy=0; OSTCBHighRdy=(OS_TCB*)0; OSTCBCur=(OS_TCB*)0; } 首先将OSRdyTbl[]数组中全部初始化0,同时将OSPrioCur/OSTCBCur初始化为0,OSPrioHighRdy/OSTCBHighRdy也初始化为0。 4.OS_InitTCBList(void)在OS_CORE.C中 功能: 初始化TCB列表 static void OS_InitTCBList(void) { INT8U i; OS_TCB *ptcb1; OS_TCB *ptcb2; OS_MemClr((INT8U*)&OSTCBTbl[0], sizeof(OSTCBTbl)); OS_MemClr((INT8U*)&OSTCBPrioTbl[0],sizeof(OSTCBPrioTbl)); ptcb1=&OSTCBTbl[0]; ptcb2=&OSTCBTbl[1]; for(i=0;i<(OS_MAX_TASKS+OS_N_SYS_TASKS-1);i++){ ptcb1->OSTCBNext=ptcb2; #ifOS_TASK_NAME_SIZE>1 ptcb1->OSTCBTaskName[0]='? '; ptcb1->OSTCBTaskName[1]=OS_ASCII_NUL; #endif ptcb1++; ptcb2++; } ptcb1->OSTCBNext=(OS_TCB*)0; #ifOS_TASK_NAME_SIZE>1 ptcb1->OSTCBTaskName[0]='? '; ptcb1->OSTCBTaskName[1]=OS_ASCII_NUL; #endif OSTCBList =(OS_TCB*)0; OSTCBFreeList =&OSTCBTbl[0]; } 首先把整个数组使用OSTCBNext指针连接成链表链起来,然后将OSTCBList初始化为0,也就是还没有TCB,因为还没有Task产生,OSTCBFreeList指向OSTCBTbl[]数组的第一个表示所有TCB都处于Free状态。 5.OS_InitEventList()在OS_CORE.C中 功能: 初始化Event列表。 static void OS_InitEventList(void) { #ifOS_EVENT_EN&&(OS_MAX_EVENTS>0) #if(OS_MAX_EVENTS>1) INT16U i; OS_EVENT *pevent1; OS_EVENT *pevent2; OS_MemClr((INT8U*)&OSEventTbl[0],sizeof(OSEventTbl)); pevent1=&OSEventTbl[0]; pevent2=&OSEventTbl[1]; for(i=0;i<(OS_MAX_EVENTS-1);i++){ pevent1->OSEventType =OS_EVENT_TYPE_UNUSED; pevent1->OSEventPtr =pevent2; #ifOS_EVENT_NAME_SIZE>1 pevent1->OSEventName[0]='? '; pevent1->OSEventName[1]=OS_ASCII_NUL; #endif pevent1++; pevent2++; } pevent1->OSEventType =OS_EVENT_TYPE_UNUSED; pevent1->OSEventPtr =(OS_EVENT*)0; #ifOS_EVENT_NAME_SIZE>1 pevent1->OSEventName[0] ='? '; pevent1->OSEventName[1] =OS_ASCII_NUL; #endif OSEventFreeList =&OSEventTbl[0]; #else OSEventFreeList =&OSEventTbl[0]; OSEventFreeList->OSEventType =OS_EVENT_TYPE_UNUSED; OSEventFreeList->OSEventPtr =(OS_EVENT*)0; #ifOS_EVENT_NAME_SIZE>1 OSEventFreeList->OSEventName[0]='? '; OSEventFreeList->OSEventName[1]=OS_ASCII_NUL; #endif #endif #endif } 将EventTbl[]数组中的OSEventType都初始化为OS_EVENT_TYPE_UNUSED。 OS_InitTaskIdle() 跳过其他的如Mem等的初始化,看看IdleTask的初始化。 (void)OSTaskCreateExt(OS_TaskIdle, (void*)0, &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE-1], OS_IDLE_PRIO, OS_TASK_IDLE_ID, &OSTaskIdleStk[0], OS_TASK_IDLE_STK_SIZE, (void*)0, OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR); IdleTask的初始化是调用OSTaskCrete系列的函数创建一个Task 初始化StateTask也是类似调用OSTaskCreate系列函数创建StatTask。 这里只是创建了该Task的各个结构还没有真正运行该Task,直到OSStart中才依据优先级调度运行。 6.OS_FlagInit() OS_FlagInit()是uc/os内部函数,应用程序不得调用该函数 7.OS_MemInit() OS_MemInit()作用是初始化动态内存 (二) OSTaskCreateExt OSTaskCreateExt负责创建Task所需的数据结构,该函数原形如下所示: OSTaskCreateExt((void(*)(void*))App_TaskStart,/*指向任务代码指针*/ (void*)0,/*指向一个传递参数的数据块*/ (OS_STK*)&App_TaskStartStk[APP_CFG_TASK_START_STK_SIZE-1],/*指向堆栈栈顶*/ (INT8U)APP_CFG_TASK_START_PRIO,/*任务优先级*/ (INT16U)APP_CFG_TASK_START_PRIO,/*任务标示(暂时不用的)*/ (OS_STK*)&App_TaskStartStk[0],/*指向栈底*/ (INT32U)APP_CFG_TASK_START_STK_SIZE,/*堆栈大小*/ (void*)0,/*定义数据指针*/ (INT8U)(OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR));/*进行任务堆栈检查,清空堆栈*/ OSTaskCreateExt函数的执行流程: (在OS_TASK.C中) #ifOS_ARG_CHK_EN>0 if(prio>OS_LOWEST_PRIO){ if(prio>OS_LOWEST_PRIO); } #endif OS_ENTER_CRITICAL(); if(OSIntNesting>0){ OS_EXIT_CRITICAL(); return(OS_ERR_TASK_CREATE_ISR); } if(OSTCBPrioTbl[prio]==(OS_TCB*)0){ OSTCBPrioTbl[prio]=(OS_TCB*)1; OS_EXIT_CRITICAL(); psp=OSTaskStkInit(task,p_arg,ptos,0); err=OS_TCBInit(prio,psp,(OS_STK*)0,0,0,(void*)0,0); if(err==OS_ERR_NONE){ if(OSRunning==OS_TRUE){ OS_Sched(); } }else{ OS_ENTER_CRITICAL(); OSTCBPrioTbl[prio]=(OS_TCB*)0; OS_EXIT_CRITICAL(); } return(err); } OS_EXIT_CRITICAL(); return(OS_PRIO_EXIST); OS_LOWEST_PRIO在ucos-ii.h中被定义为63,表示Task的优先级从0到63,共64级。 首先判断prio是否超过最低优先级,如果是,则返回OS_PRIO_INVALID错误。 然后调用OS_ENTER_CRITICAL(),进入临界段,在临界段中的代码执行不允许被中断。 这个宏是自定义的,一般是进行关中断操作。 这个宏和OS_EXIT_CRITICAL()相对应,这个宏表示离开临界段。 OSTaskCreate不允许在中断中调用,因此会判断OSIntNesting是否大于0,如果大于0,表示正在中断嵌套,返回OS_ERR_TASK_CREATE_ISR错误。 接着判断该prio是否已经有Task存在,由于uC/OS-II只支持每一个优先级一个Task,因此如果该prio已经有进程存在,OSTaskCreate会返回OS_PRIO_EXIST错误。 相反,如果该prio先前没有Task存在,则将OSTCBPrioTbl[prio]置1,表示该prio已被占用,然后调用OSTaskStkInit初始化堆栈,调用OS_TCBInit初始化TCB,如果OSRunning为TRUE表示OS正在运行,则调用OS_Sched进行进程调度;否则返回。 关于OSTaskStkInit和OS_TCBInit这两个函数。 OSTaskStkInit是一个用户自定义的函数,因为uC/OS-II在设计时无法知道当前处理器在进行进程调度时需要保存哪些信息,OSTaskStkInit就是初始化堆栈,让Task看起来就好像刚刚进入中断并保存好寄存器的值一样,当OS_Sched调度到该Task时,只需切换到该堆栈中,将寄存器值Pop出来,然后执行一个中断返回指令IRET即可。 OSTaskStkInit的原型如下: OS_STK*OSTaskStkInit(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT16Uopt) 和OSTaskCreate类似,task是进程入口地址,pdata是参数地址,ptos是堆栈指针,而opt只是作为一个预留的参数Option而保留。 返回的是调整以后的堆栈指针。 在OSTaskStkInit中,一般是将pdata入栈,flag入栈,task入栈,然后将各寄存器依次入栈。 OS_TCBInit初始化TCB数据结构,下面只提取主要部分来看: INT8U OS_TCBInit(INT8Uprio,OS_STK*ptos,OS_STK*pbos,INT16Uid,INT32Ustk_size,void*pext,INT16Uopt) { OS_TCB *ptcb; #ifOS_CRITICAL_METHOD==3 OS_CPU_SRcpu_sr=0; #endif OS_ENTER_CRITICAL(); ptcb=OSTCBFreeList; if(ptcb! =(OS_TCB*)0){ OSTCBFreeList =ptcb->OSTCBNext; OS_EXIT_CRITICAL(); ptcb->OSTCBStkPtr =ptos; ptcb->OSTCBPrio =prio; ptcb->OSTCBStat =OS_STAT_RDY; ptcb->OSTCBStatPend=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 2478 ucostouchOK 总体 思路