uC/OS-II源码分析
内核结构
本文引用地址:https://www.eepw.com.cn/article/201609/304898.htm!--[if !supportLists]-->1, !--[endif]-->临界区,OS_ENTER_CRITICAL和OS_EXIT_CRITICAL
为了处理临界区代码,必须关中断,等处理完毕后,再开中断。关中断可以避免其他任务或中断进入临界区代码。uC/OS-II定义了这两个宏来实现,但注意一条:调用uC/OS-II功能函数时,中断应该总是开着的。
1)当OS_CRITICAL_METHOD= = 1时,简单实现如下:
#defineOS_ENTER_CRITICAL()disable_int()
#defineOS_EXIT_CRITICAL()enable_int()
但这样有一个问题,如果禁止中断的情况下调用uC/OS-II功能函数,那么从功能函数返回时,中断可能变成允许的了,而实际上还是希望是禁止的。
2)当OS_CRITICAL_METHOD= = 2时,实现如下:
#defineOS_ENTER_CRITICAL()
asm(“PUSHPSW”);
asm(“DI”);
#defineOS_EXIT_CRITICAL()
asm(“POPPSW”);
执行OS_ENTER_CRITICAL()时,先将中断状态保存到堆栈,然后关中断;执行OS_EXIT_CRITICAL()时,再从堆栈中恢复原来的中断开/关状态。这种方法不会改变中断状态,避免前面的问题。
3)当OS_CRITICAL_METHOD= = 3时,实现如下:
#defineOS_ENTER_CRITICAL()
cpu_sr=get_processor_psw();
disable_interrupts();
#defineOS_EXIT_CRITICAL()
set_processor_psw(cpu_sr);
将处理器状态字保存在局部变量中。
!--[if !supportLists]-->2, !--[endif]-->任务是一个无限循环,返回类型为void,参数void*,用于传数据给任务。任务可以调用OSTaskDel(OS_PRIO_SELF)进行自我删除。任务有5种状态:
!--[if !supportLists]-->1) !--[endif]-->睡眠态。任务驻留在程序空间(ROM或RAM),还未交给uC/OS-II来管理。
!--[if !supportLists]-->2) !--[endif]-->就绪态。OSTaskCreate()或OSTaskCreateExt()来创建一个任务后,就进入就绪态。任务可以调用OSTaskDel返回到睡眠态,或调用该函数让另一个任务进入睡眠态。
!--[if !supportLists]-->3) !--[endif]-->运行态。OSStart()启动多任务运行。它只在启动时调用一次,运行就绪列表中优先级最高的任务。就绪的任务只有当所以优先级比其高的任务转为等待状态,或者是被删除了,才能进入运行态。
!--[if !supportLists]-->4) !--[endif]-->等待状态。正在运行的任务可以调用OSTimeDly()或OSTimeDlyHMSM()将自身延迟一段时间进入等待状态,一直到延迟时间到来。这两个函数会强制执行任务切换,选择下一个优先级最高的任务运行。等待时间过去后,系统服务函数OSTimeTick()使延迟了的任务进入就绪态。
正在运行的任务也可能需要等待某一事件的发生,可以调用:OSFlagPend(),OSSemPend(),OSMutexPend(),OSMboxPend(),OSQPend()等函数。若某事件未发生,则任务进入等待状态,直到事件发生。当任务因等待事件被挂起时,下一个优先级最高的任务得到CPU。当事件发生了或超时,被挂起的任务进入就绪态。事件发生的报告可能来自另一个任务或中断服务子程序。
!--[if !supportLists]-->5) !--[endif]-->中断服务态 。被中断的任务进入中断服务态,从而被挂起,中断服务子程序得到CPU,后者可能报告一个或多个事件发生,从而使一个或多个任务进入就绪态。因此从中断服务子程序返回前,uC/OS-II要判断被中断的任务的优先级和就绪列表中其他任务的优先级高低,选择最高的任务进入运行态。
!--[if !supportLists]-->6) !--[endif]-->当所以任务都在等待事件发生或等待延迟的时间结束时,uC/OS-II运行OSTaskIdle()任务。
!--[if !supportLists]-->3, !--[endif]-->任务控制块(OS_TCB)
建立一个任务时,一个OS_TCB就被赋值。当任务的CPU被剥夺时,用它来保存任务的状态,当任务重新得到CPU时,它也能保证任务从当时被中断的那一点继续执行。OS_TCB全部驻留在RAM中。
typedefstructos_tcb
{
OS_STK*OSTCBStkPtr;/*指向当前任务堆栈栈顶的指针*/
#ifOS_TASK_CREATE_EXT_EN>0
void*OSTCBExtPtr;/*指向用户定义的任务控制块扩展*/
OS_STK*OSTCBStkBottom;/*指向栈底的指针*/
INT32UOSTCBStkSize;/*栈中可容纳的元素数目(
uC/OS-II允许每个任务的堆栈容量任意,)*/
INT16UOSTCBOpt;/*传给OSTaskCreateExt()的任务选择项*/
INT16UOSTCBId;/*TaskID(0..65535)*/
#endif
structos_tcb*OSTCBNext;/*TCB列表中指向下一个TCB的指针*/
structos_tcb*OSTCBPrev;/*TCB列表中指向上一个TCB的指针*/
#if((OS_Q_EN>0)(OS_MAX_QS>0))||(OS_MBOX_EN>0)||(OS_SEM_EN>0)||(OS_MUTEX_EN>0)
OS_EVENT*OSTCBEventPtr;/*指向事件控制块的指针*/
#endif
#if((OS_Q_EN>0)(OS_MAX_QS>0))||(OS_MBOX_EN>0)
void*OSTCBMsg;/*指向传递给任务的消息的指针,消息来自OSMboxPost()orOSQPost()*/
#endif
#if(OS_VERSION>=251)(OS_FLAG_EN>0)(OS_MAX_FLAGS>0)
#ifOS_TASK_DEL_EN>0
OS_FLAG_NODE*OSTCBFlagNode;/*指向事件标志节点的指针*/
#endif
OS_FLAGSOSTCBFlagsRdy;/*使任务进入就绪态的事件标志*/
#endif
INT16UOSTCBDly;/*让任务延时若干节拍或把任务挂起一段时间等待某一事件发生时使用的计时变量*/
INT8UOSTCBStat;/*任务状态*/
INT8UOSTCBPrio;/*任务优先级(0==highest,63==lowest)*/
//下面四个变量用于加速任务进入就绪态或进入等待事件发生状态的过程,算法比较巧妙
INT8UOSTCBX;/*Bitpositioningroupcorrespondingtotaskpriority(0..7)*/
INT8UOSTCBY;/*Indexintoreadytablecorrespondingtotaskpriority
评论