定位到uCOS-II/Source/目录,这部分是系统的核心代码。先看ucos_ii.h文件:
OS_PRIO_SELF被宏定义为0xFF,从注释上看OS_PRIO_SELF代表的是任务自身的优先级。为什么是0xff?这宏是适用于当你不知道任务的优先级但是又要操作任务的优先级的时候,uCOS-II的内部函数会将其转换为真正优先级的代码。例如你想用OSTaskDel()删除当前任务但是你又不知道当前任务的优先级,可以写为:
OSTaskDel(OS_PRIO_SELF); #if OS_TASK_STAT_EN > 0 #define OS_N_SYS_TASKS 2u /* Number of system tasks */ #else #define OS_N_SYS_TASKS 1u #endifOS_TASK_STAT_EN是一个配置宏,OS_TASK_STAT_EN > 0表示使用系统中的统计任务。统计任务是属于系统任务,默认开启且无法被删除的系统任务还有一个空闲任务。当使能了系统统计任务,那么OS_N_SYS_TASKS=2,反之OS_N_SYS_TASKS=1。
#define OS_TASK_STAT_PRIO (OS_LOWEST_PRIO - 1) #define OS_TASK_IDLE_PRIO (OS_LOWEST_PRIO)OS_TASK_STAT_PRIO、OS_TASK_IDLE_PRIO分别是统计任务、空闲任务的优先级,OS_LOWEST_PRIO为系统任务的最低优先级。假设系统为最多支持32个任务,那么任务的最低优先级为31(优先级数值越大,优先级越低)。倒数两个低优先级分别赋给统计任务和空闲任务。OS_TASK_STAT_PRIO = 30,OS_TASK_IDLE_PRIO = 29。统计任务用于统计系统各种状态参数,如内存/CPU使用率等,空闲任务在系统中无任务可执行时才轮到它执行。
#if OS_LOWEST_PRIO <= 63 #define OS_EVENT_TBL_SIZE ((OS_LOWEST_PRIO) / 8 + 1) /* Size of event table */ #define OS_RDY_TBL_SIZE ((OS_LOWEST_PRIO) / 8 + 1) /* Size of ready table */ #else #define OS_EVENT_TBL_SIZE ((OS_LOWEST_PRIO) / 16 + 1) /* Size of event table */ #define OS_RDY_TBL_SIZE ((OS_LOWEST_PRIO) / 16 + 1) /* Size of ready table */ #endifOS_RDY_TBL_SIZE是任务就绪表的下标取值范围,OS_LOWEST_PRIO=31, 这里计算得出OS_RDY_TBL_SIZE等于4,即下标取值为0~3。OS_EVENT_TBL_SIZE同理。
#define OS_TASK_IDLE_ID 65535u /* ID numbers for Idle, Stat and Timer tasks */ #define OS_TASK_STAT_ID 65534u #define OS_TASK_TMR_ID 65533uIdle、Stat、Timer任务的ID,为什么是65535?因为uCOS-II最多支持2^16个任务,其ID最大为65535。在uCOS-II中id值并没什么用处。
#define OS_EVENT_EN (((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) || (OS_SEM_EN > 0) || (OS_MUTEX_EN > 0)) #define OS_TCB_RESERVED ((OS_TCB *)1)OS_EVENT_EN为1表示开启系统的事件功能机制。
#define OS_STAT_RDY 0x00u /* Ready to run (就绪态) */ #define OS_STAT_SEM 0x01u /* Pending on semaphore (因等待信号量而被挂起) */ #define OS_STAT_MBOX 0x02u /* Pending on mailbox (因等效MBox而被挂起) */ #define OS_STAT_Q 0x04u /* Pending on queue (因等待消息队列而被挂起) */ #define OS_STAT_SUSPEND 0x08u /* Task is suspended (挂起态) */ #define OS_STAT_MUTEX 0x10u /* Pending on mutual exclusion semaphore (因等待Mutex而被挂起) */ #define OS_STAT_FLAG 0x20u /* Pending on event flag group (因等待flag而被挂起) */ #define OS_STAT_MULTI 0x80u /* Pending on multiple events (因等待MULTI而被挂起,MULTI指代所有事件类型的综合) */ #define OS_STAT_PEND_ANY (OS_STAT_SEM | OS_STAT_MBOX | OS_STAT_Q | OS_STAT_MUTEX | OS_STAT_FLAG)如上宏表示任务当前的运行状态,是TCB中OSTCBStat成员的取值选项。
#define OS_STAT_PEND_OK 0u /* 已经挂起结束或没有挂起 */ #define OS_STAT_PEND_TO 1u /* 在有超时机制的挂起状态中 */ #define OS_STAT_PEND_ABORT 2u /* 挂起出错 */如上宏表示任务当前的挂起状态,也是TCB中OSTCBStatPend成员的取值选项。
#define OS_EVENT_TYPE_UNUSED 0u #define OS_EVENT_TYPE_MBOX 1u #define OS_EVENT_TYPE_Q 2u #define OS_EVENT_TYPE_SEM 3u #define OS_EVENT_TYPE_MUTEX 4u #define OS_EVENT_TYPE_FLAG 5u #define OS_TMR_TYPE 100u如上宏表示系统中的事件类型。
#define OS_FLAG_WAIT_CLR_ALL 0u /* Wait for ALL the bits specified to be CLR (i.e. 0) */ #define OS_FLAG_WAIT_CLR_AND 0u #define OS_FLAG_WAIT_CLR_ANY 1u /* Wait for ANY of the bits specified to be CLR (i.e. 0) */ #define OS_FLAG_WAIT_CLR_OR 1u #define OS_FLAG_WAIT_SET_ALL 2u /* Wait for ALL the bits specified to be SET (i.e. 1) */ #define OS_FLAG_WAIT_SET_AND 2u #define OS_FLAG_WAIT_SET_ANY 3u /* Wait for ANY of the bits specified to be SET (i.e. 1) */ #define OS_FLAG_WAIT_SET_OR 3u #define OS_FLAG_CONSUME 0x80u /* Consume the flags if condition(s) satisfied */ #define OS_FLAG_CLR 0u #define OS_FLAG_SET 1u跟flag事件相关的宏定义。
#if OS_TICK_STEP_EN > 0 #define OS_TICK_STEP_DIS 0u /* Stepping is disabled, tick runs as mormal */ #define OS_TICK_STEP_WAIT 1u /* Waiting for uC/OS-View to set OSTickStepState to _ONCE */ #define OS_TICK_STEP_ONCE 2u /* Process tick once and wait for next cmd from uC/OS-View */ #endifuC/OS-View使用。uC/OS-View是一个基于uCOS-II的中间件监控程序,通过串口同windows平台上的客户端程序Viewer配合使用,可以实时显示uCOS-II及其所有任务的当前状态,如任务栈起始地址,栈大小,任务名称,任务当前状态,任务被执行次数和CPU占用率等。最重要的一点是,uC/OS-View已经被Micrium无情抛弃了,所以先不细究。
#define OS_DEL_NO_PEND 0u #define OS_DEL_ALWAYS 1u删除事件函数,如OSSemDel()、OSMboxDel()等,其opt参数的取值选项。前者表示若有任务在等待/使用该事件则不删除,后者则总是删除。
/* ********************************************************************************************************* * OS???Pend() OPTIONS * * These #defines are used to establish the options for OS???PendAbort(). ********************************************************************************************************* */ #define OS_PEND_OPT_NONE 0u /* NO option selected */ #define OS_PEND_OPT_BROADCAST 1u /* Broadcast action to ALL tasks waiting */ /* ********************************************************************************************************* * OS???PostOpt() OPTIONS * * These #defines are used to establish the options for OSMboxPostOpt() and OSQPostOpt(). ********************************************************************************************************* */ #define OS_POST_OPT_NONE 0x00u /* NO option selected */ #define OS_POST_OPT_BROADCAST 0x01u /* Broadcast message to ALL tasks waiting */ #define OS_POST_OPT_FRONT 0x02u /* Post to highest priority task waiting */ #define OS_POST_OPT_NO_SCHED 0x04u事件相关宏定义。
#define OS_TASK_OPT_NONE 0x0000u /* 不使用 */ #define OS_TASK_OPT_STK_CHK 0x0001u /* 栈空间还剩下多少 */ #define OS_TASK_OPT_STK_CLR 0x0002u /* 清理栈 */ #define OS_TASK_OPT_SAVE_FP 0x0004u /* 保存浮点单元的寄存器 */CM3内核不支持浮点单元的(CM4内核支持)。OS_TASK_OPT_SAVE_FP用于保存浮点指针(在进行上下文切换时)。 这几个宏在用于创建任务的函数OSTaskCreateExt()的参数使用。OSTaskCreate()是早期uCOS-II创建任务的函数,OSTaskCreateExt()则后期添加上的,也是用于创建任务。前者原型为:
INT8U OSTaskCreate (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio)后者的原型为:
INT8U OSTaskCreateExt (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, /* top */ INT8U prio, INT16U id, OS_STK *pbos, /* button */ INT32U stk_size, /* 栈的大小 */ void *pext, /* 用户扩展数据 */ INT16U opt)后者多了5个参数,其中opt参数取值为以上宏。
/* ********************************************************************************************************* * TIMER OPTIONS (see OSTmrStart() and OSTmrStop()) ********************************************************************************************************* */ #define OS_TMR_OPT_NONE 0u /* No option selected */ #define OS_TMR_OPT_ONE_SHOT 1u /* Timer will not automatically restart when it expires */ #define OS_TMR_OPT_PERIODIC 2u /* Timer will automatically restart when it expires */ #define OS_TMR_OPT_CALLBACK 3u /* OSTmrStop() option to call 'callback' w/ timer arg. */ #define OS_TMR_OPT_CALLBACK_ARG 4u /* OSTmrStop() option to call 'callback' w/ new arg. */ /* ********************************************************************************************************* * TIMER STATES ********************************************************************************************************* */ #define OS_TMR_STATE_UNUSED 0u #define OS_TMR_STATE_STOPPED 1u #define OS_TMR_STATE_COMPLETED 2u #define OS_TMR_STATE_RUNNING 3u定时器相关的宏定义。
#define OS_ERR_NONE 0u #define OS_ERR_EVENT_TYPE 1u #define OS_ERR_PEND_ISR 2u ... #define OS_ERR_TMR_NAME_TOO_LONG 140u #define OS_ERR_TMR_INVALID_STATE 141u #define OS_ERR_TMR_STOPPED 142u #define OS_ERR_TMR_NO_CALLBACK 143u系统使用的错误码。
#define OS_NO_ERR OS_ERR_NONE #define OS_TIMEOUT OS_ERR_TIMEOUT //... #define OS_FLAG_GRP_DEPLETED OS_ERR_FLAG_GRP_DEPLETED版本后小于2.84的系统使用的错误码。
flag也属于事件(event)的一种,像Mutex、信号量和消息盒子等也属于event。由于flag的设计及使用与众不同,用OS_EVENT结构体无法表征,所以单独使用OS_FLAG_GRP结构体描述。
#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) #if OS_FLAGS_NBITS == 8 /* Determine the size of OS_FLAGS (8, 16 or 32 bits) */ typedef INT8U OS_FLAGS; #endif #if OS_FLAGS_NBITS == 16 typedef INT16U OS_FLAGS; #endif #if OS_FLAGS_NBITS == 32 typedef INT32U OS_FLAGS; #endif系统中的flag是8位、16位、32位可选的。
typedef struct os_flag_grp { /* Event Flag Group */ INT8U OSFlagType; /* 前只有OS_EVENT_TYPE_FLAG这种类型的flag */ void *OSFlagWaitList; /* 指向flag链表的首节点 */ OS_FLAGS OSFlagFlags; /* 要等待flag中的哪几个bit */ #if OS_FLAG_NAME_SIZE > 1 INT8U OSFlagName[OS_FLAG_NAME_SIZE]; #endif } OS_FLAG_GRP; 每个flag节点用OS_FLAG_NODE结构体描述: typedef struct os_flag_node { void *OSFlagNodeNext; /* Pointer to next NODE in wait list */ void *OSFlagNodePrev; /* Pointer to previous NODE in wait list */ void *OSFlagNodeTCB; /* 正在排队等待flag的任务的TCB */ void *OSFlagNodeFlagGrp; /* 指向flag所在的节点 */ OS_FLAGS OSFlagNodeFlags; /* 要等待的flag的BIT几 */ INT8U OSFlagNodeWaitType; /* 等待flag的等待类型。Type of wait: */ /* OS_FLAG_WAIT_AND */ /* OS_FLAG_WAIT_ALL */ /* OS_FLAG_WAIT_OR */ /* OS_FLAG_WAIT_ANY */ } OS_FLAG_NODE;每个flag节点用双向链表的方式管理。
在c语言中动态分配内存使用malloc()和free()两个c库函数,它们是属于c库的内容,所以uCOS-II要支持这两个函数来实现动态内存分配,就要移植c库。对于运行RTOS的嵌入式软件来说,显得庞大。所以uCOS-II自定义了动态内存分配相关的函数。如下即为函数相关的描述结构体:
#if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0) typedef struct os_mem { /* MEMORY CONTROL BLOCK */ void *OSMemAddr; /* Pointer to beginning of memory partition */ void *OSMemFreeList; /* Pointer to list of free memory blocks */ INT32U OSMemBlkSize; /* Size (in bytes) of each block of memory */ INT32U OSMemNBlks; /* Total number of blocks in this partition */ INT32U OSMemNFree; /* Number of memory blocks remaining in this partition */ #if OS_MEM_NAME_SIZE > 1 INT8U OSMemName[OS_MEM_NAME_SIZE]; /* Memory partition name */ #endif } OS_MEM; typedef struct os_mem_data { void *OSAddr; /* Pointer to the beginning address of the memory partition */ void *OSFreeList; /* Pointer to the beginning of the free list of memory blocks */ INT32U OSBlkSize; /* Size (in bytes) of each memory block */ INT32U OSNBlks; /* Total number of blocks in the partition */ INT32U OSNFree; /* Number of memory blocks free */ INT32U OSNUsed; /* Number of memory blocks used */ } OS_MEM_DATA; #endif队列相当于环形缓冲区,需要4个指针:分别指向头、指向尾指针、指向下一个数据要放入的位置、指向下一个要放出数据的位置。
#if OS_Q_EN > 0 typedef struct os_q { /* QUEUE CONTROL BLOCK */ struct os_q *OSQPtr; /* 指向下一个Queue */ void **OSQStart; /* Queue中的第一个元素 */ void **OSQEnd; /* Queue中的最后一个元素 */ void **OSQIn; /* Pointer to where next message will be inserted in the Q */ void **OSQOut; /* Pointer to where next message will be extracted from the Q */ INT16U OSQSize; /* Queue中元素的个数。单位是元素的个数,不是字节数 */ INT16U OSQEntries; /* 当前队列用来存放数据的空间的内容用了多少 */ } OS_Q; typedef struct os_q_data { void *OSMsg; /* Queue的有效消息 */ INT16U OSNMsgs; /* 有效消息的个数 */ INT16U OSQSize; /* 数据总大小 */ */ #if OS_LOWEST_PRIO <= 63 INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */ INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */ #else INT16U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */ INT16U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */ #endif } OS_Q_DATA; #endif见前面文章《uCOS-II系统中的任务》。链接为http://blog.csdn.net/qq_29344757/article/details/77625053
接下来就是uCOS-II的核心函数的声明。ucos_ii.h文件就粗略阅读到这里,下来将阅读本目录下的其他.c文件。