uC/OS-II操作系统分析 (二)

 

 

 

1.时间管理

 

1.1OSTimeDly() 延时程序

void OSTimeDly (INT16U ticks)

  1. Ticks 延时脉冲数 ,通常与 OS_TICKS_PER_SEC 相联系以更精确的定时, OS_TICKS_PER_SEC OS_CORE.H 中宏定义,也就是说与处理器相关联

  1. 1 <= ticks <= 65535

 

void OSTimeDly (INT16U ticks)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

if (ticks > 0) /* ticks 有效 */

{

OS_ENTER_CRITICAL(); /* 关中断 */

if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) /* 当前任务从就绪表移除 */

{ /* 并检查该优先级组是否都没有就绪任务了 */

OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* 如果是, OSRdyGrp 的相应位置 0 */

}

OSTCBCur->OSTCBDly = ticks; /* 设置 TCB OSTCBDly 变量为 ticks */

OS_EXIT_CRITICAL(); /* 开中断 */

OSSched(); /* 任务切换 */

}

}

 

1.1.1 程序流程图

1 OSTimeDly() 流程图

 

 

 

1.2OSTimeTick()

 

void OSTimeTick (void)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_TCB *ptcb;

 

OSTimeTickHook(); /* Call user definable hook */

#if OS_TIME_GET_SET_EN > 0

OS_ENTER_CRITICAL(); /* Update the 32-bit tick counter */

OSTime++;

OS_EXIT_CRITICAL();

#endif

if (OSRunning == TRUE) {

ptcb = OSTCBList; /* Point at first TCB in TCB list */

while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { /* Go through all TCBs in TCB list */

OS_ENTER_CRITICAL();

if (ptcb->OSTCBDly != 0) { /* Delayed or waiting for event with TO */

if (--ptcb->OSTCBDly == 0) { /* Decrement nbr of ticks to end of delay */

if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* */

OSRdyGrp |= ptcb->OSTCBBitY; /**/

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

} else { /* Yes, Leave 1 tick to prevent ... */

ptcb->OSTCBDly = 1; /* ... loosing the task when the ... */

} /* ... suspension is removed. */

}

}

ptcb = ptcb->OSTCBNext; /* Point at next TCB in TCB list */

OS_EXIT_CRITICAL();

}

}

}

 

1.3OSTimeDlyHMSM() 按时分秒延时函数

INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli)

  1. INT8U hours 延时的小时数( INT8U 决定最多延长小于 257 小时的时间)

  2. INT8U minutes 延时的分钟数

  3. INT8U seconds 延时的秒数

  4. INT8U milli 延时的微秒数(最大 999

说明的几点

  1. OSTimeDly ()能接受的最大 ticks 65535 ,导致超过 65536ticks OSTimeDlyHMSM ()将不允许被 OSTimeDlyResume ()。

  2. 注意 OS_TICKS_PER_SEC 这个宏定义,整个函数的关键点还是它的设置。它表示一秒钟产生多少个 ticks ,也就是频率。一个 100Hz 的时钟, OS_TICKS_PER_SEC 应该定义为 100

 

#if OS_TIME_DLY_HMSM_EN > 0

INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli)

{

INT32U ticks;

INT16U loops;

if (hours > 0 || minutes > 0 || seconds > 0 || milli > 0) {

if (minutes > 59) {

return (OS_TIME_INVALID_MINUTES); /* 计算时分秒微妙等参数是否合法 */

}

if (seconds > 59) {

return (OS_TIME_INVALID_SECONDS);

}

if (milli > 999) {

return (OS_TIME_INVALID_MILLI);

}

ticks = ((INT32U)hours * 3600L + (INT32U)minutes * 60L + (INT32U)seconds) * OS_TICKS_PER_SEC + OS_TICKS_PER_SEC * ((INT32U)milli + 500L / OS_TICKS_PER_SEC) / 1000L;

/* 计算总的延时 ticks */

loops = (INT16U)(ticks / 65536L); /* 计算需要多少个 65536 的循环来完成延时 */

ticks = ticks % 65536L; /* 计算整数倍 65536 延时意外剩余的 ticks 延时 */

OSTimeDly((INT16U)ticks);

while (loops > 0) {

OSTimeDly(32768);

OSTimeDly(32768);

loops--;

}

return (OS_NO_ERR);

}

return (OS_TIME_ZERO_DLY);

}

#endif

 

1.4OSTimeDlyResume() 延时期任务结束延时程序

INT8U OSTimeDlyResume (INT8U prio)

  1. Prio 延时回复任务的优先级

说明

  1. 任务处在延时中,即便被延时恢复也不一定可以就绪,因为他可能也正被挂起,这种情况在在代码中又体现,也就是说只有在没有被挂起的情况下才能处于就绪状态

#if OS_TIME_DLY_RESUME_EN > 0

INT8U OSTimeDlyResume (INT8U prio)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_TCB *ptcb;

 

if (prio >= OS_LOWEST_PRIO) {

return (OS_PRIO_INVALID);

}

OS_ENTER_CRITICAL();

ptcb = (OS_TCB *)OSTCBPrioTbl[prio]; /* 获得 prio 的任务 TCB */

if (ptcb != (OS_TCB *)0) { /* 如果 TCB 存在 */

if (ptcb->OSTCBDly != 0) { /* 如果该 TCB 延时不为 0 (正被演示) */

ptcb->OSTCBDly = 0; /* 清除延时数 */

if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* 确保未被挂起 */

OSRdyGrp |= ptcb->OSTCBBitY; /* 将任务加入就绪列表 */

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

OS_EXIT_CRITICAL();

OS_Sched(); /* 进行任务切换 */

} else {

OS_EXIT_CRITICAL(); /* 任务被挂起 不做操作 */

}

return (OS_NO_ERR);

} else {

OS_EXIT_CRITICAL();

return (OS_TIME_NOT_DLY); /* 返回任务未被 delay */

}

}

OS_EXIT_CRITICAL();

return (OS_TASK_NOT_EXIST); /* The task does not exist */

}

#endif

 

1.4.1 程序流程图

2 OSTimeDlyResume() 流程图

1.5系统时间, OSTimeGet() OSTimeSet()

 

OS_EXT volatile INT32U OSTime; /* 系统时间的当前值 ,用 ticks表示 */

 

#if OS_TIME_GET_SET_EN > 0

void OSTimeSet (INT32U ticks)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

 

OS_ENTER_CRITICAL();

OSTime = ticks;

OS_EXIT_CRITICAL();

}

#endif

 

INT32U OSTimeGet (void)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

INT32U ticks;

OS_ENTER_CRITICAL();

ticks = OSTime;

OS_EXIT_CRITICAL();

return (ticks);

}

#endif

 

 

2.TCB 任务控制块

 

2.1OS_TCBInit() 任务控制块初始化函数

2.1.1 源代码分析

Prio 任务优先级

Ptos 任务栈顶指针 pointer top to stack

Pbos 任务栈底指针 pointer bottom to stack

Id 任务的 ID 0-65536

Stk_size 堆栈在堆栈单元(?)中的尺寸,与 OS_STK的定义有关

INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)

{

*************

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

*****************///

OS_TCB *ptcb;

OS_ENTER_CRITICAL();

ptcb = OSTCBFreeList; /* 将当前 TCB 加入到空闲 TCB 列表指针 */

if (ptcb != (OS_TCB *)0) { /* 如果当前指针不为空 */

OSTCBFreeList = ptcb->OSTCBNext; /* 更新加入后的空闲列表指针 */

OS_EXIT_CRITICAL();

ptcb->OSTCBStkPtr = ptos; /* 参数付给当前 TCB 需求的参数 */

ptcb->OSTCBPrio = (INT8U)prio;

ptcb->OSTCBStat = OS_STAT_RDY;

ptcb->OSTCBDly = 0;

// 这一段代码放置 待注释和解释

#if OS_TASK_CREATE_EXT_EN > 0

ptcb->OSTCBExtPtr = pext;

ptcb->OSTCBStkSize = stk_size;

ptcb->OSTCBStkBottom = pbos;

ptcb->OSTCBOpt = opt;

ptcb->OSTCBId = id;

#else

pext = pext; /* Prevent compiler warning if not used */

stk_size = stk_size;

pbos = pbos;

opt = opt;

id = id;

#endif

#if OS_TASK_DEL_EN > 0

ptcb->OSTCBDelReq = OS_NO_ERR; /* OSTaskDelReq() 函数相联系的变量 */

#endif

// 处理任务就绪列表

ptcb->OSTCBY = prio >> 3; /* 存储就绪优先级组的信息 */

ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY]; /* 存储上面变量的具体位 */

ptcb->OSTCBX = prio & 0x07; /* 存储就绪优先级组中的 8 个优先级情况 */

ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX]; /* 存储上面变量的具体位情况 */

// 这一段代码放置 待注释和解释

#if OS_EVENT_EN > 0

ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Task is not pending on an event */

#endif

 

#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)

ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; /* Task is not pending on an event flag */

#endif

 

#if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))

ptcb->OSTCBMsg = (void *)0; /* No message received */

#endif

 

#if OS_VERSION >= 204

OSTCBInitHook(ptcb);

#endif

 

OSTaskCreateHook(ptcb); /* Call user defined hook */

OS_ENTER_CRITICAL();

OSTCBPrioTbl[prio] = ptcb;

ptcb->OSTCBNext = OSTCBList; /* Link into TCB chain */

ptcb->OSTCBPrev = (OS_TCB *)0;

if (OSTCBList != (OS_TCB *)0) {

OSTCBList->OSTCBPrev = ptcb;

}

OSTCBList = ptcb;

OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

OS_EXIT_CRITICAL();

return (OS_NO_MORE_TCB);

}

 

 

 

2.2TCB 的结构体定义

2.2.1TCB主要的数据

对于普通的 OSTaskCreate()来说, TCB主要的数据有:

  1. OS_STK *OSTCKStkPtr 当前栈顶指针

  2. Struct os_tcb *OSTCBNext 指向 TCB 列表中当前 PCB 的下一个 TCB

  3. Struct os_tcb *OSTCBPrev 指向 TCB 列表中当前 PCB 的上一个 TCB

  4. INT16U OSTCBDly; 延迟任务、等待事件等需要的延时,要是任务就绪,其值必须为 0

  5. INT8U OSTCBStat; 任务状态 /*******///

  6. INT8U OSTCBPrio; 任务优先级

以下四个参数用于定位优先级的就绪表有关

  1. INT8U OSTCBX;

  2. INT8U OSTCBY;

  3. INT8U OSTCBBitX;

  4. INT8U OSTCBBitY;

  1. #if OS_TASK_DEL_EN > 0 // 如果定义了该变量为 1 默认为定义了

  1. BOOLEAN OSTCBDelReq; 用于与 OSTaskDelReq() 函数相联系,请求删除标志

2.2.2 TCB结构体源代码分析

typedef struct os_tcb {

OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */

 

#if OS_TASK_CREATE_EXT_EN > 0

void *OSTCBExtPtr; /* Pointer to user definable data for TCB extension */

OS_STK *OSTCBStkBottom; /* Pointer to bottom of stack */

INT32U OSTCBStkSize; /* Size of task stack (in number of stack elements) */

INT16U OSTCBOpt; /* Task options as passed by OSTaskCreateExt() */

INT16U OSTCBId; /* Task ID (0..65535) */

#endif

 

struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */

struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */

#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) || (OS_SEM_EN > 0) || (OS_MUTEX_EN > 0)

OS_EVENT *OSTCBEventPtr; /* 指向 ECB 的指针 */

#endif

**********

#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)

void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost() */

#endif

 

#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)

#if OS_TASK_DEL_EN > 0

OS_FLAG_NODE *OSTCBFlagNode; /* Pointer to event flag node */

#endif

OS_FLAGS OSTCBFlagsRdy; /* Event flags that made task ready to run */

#endif

**********

 

INT16U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */

INT8U OSTCBStat; /* Task status */

INT8U OSTCBPrio; /* Task priority (0 == highest, 63 == lowest) */

 

INT8U OSTCBX; /* Bit position in group corresponding to task priority (0..7) */

INT8U OSTCBY; /* Index into ready table corresponding to task priority */

INT8U OSTCBBitX; /* Bit mask to access bit position in ready table */

INT8U OSTCBBitY; /* Bit mask to access bit position in ready group */

 

#if OS_TASK_DEL_EN > 0

BOOLEAN OSTCBDelReq; /* 用于与 OSTaskDelReq() 函数相联系,请求删除标志 */

#endif

} OS_TCB

 

2.2.3 (OS_TCB*)0 (OS_TCB*)1的说明:

(OS_TCB *)0 可以理解 为在该优先级无任务,因为 UCOS不允许多个任务共一个优先级。 (OS_TCB*)1 则为有任务。

2.2.4 TCB相关的全局变量

OS_EXT OS_TCB *OSTCBCur; /* 指向当前 TCB的指针 */

OS_EXT OS_TCB *OSTCBFreeList; /* TCB空闲列表指针 */

OS_EXT OS_TCB *OSTCBHighRdy; /* 最高优先级 TCB指针 R-to-R */

OS_EXT OS_TCB *OSTCBList; /* TCB双向链表指针 */

OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1];

/* 创建某优先级 TCB的表,可用于查找相应优先级的 TCB*/

OS_EXT OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS]; /* Table of TCBs */

3.临界区中断开关 OS_ENTER_CRITICAL() OS_EXIT_CRITICAL()

OS_ENTER_CRITICAL() OS_EXIT_CRITICAL() //OS_CPU.H 中找到 见书 P213

进入临界代码区之前需要关闭中断

#define OS_CRITICAL_METHOD 2 //系统默认为 2

// 方法一简单执行速度快(只有一条指令),但是有弊端,关闭中断后,若调用 uCOS 系统函数,结束后中断可能将打开,这应该是不允许的。换句话讲,他不允许中断嵌套

#if OS_CRITICAL_METHOD == 1

#define OS_ENTER_CRITICAL() asm CLI /* Disable interrupts*/

#define OS_EXIT_CRITICAL() asm STI /* Enable interrupts */

#endif

// 方法二是先将中断关闭的状态保存到堆栈中,然后关闭中断。与之对应的 OS_EXIT_CRITICAL() 的操作是从堆栈中恢复中断状态。它允许使用中断嵌套,如中断关闭后,调用系统函数,其中也涉及到中断开关,而里面的不影响外面的中断,及允许中断嵌套。

#if OS_CRITICAL_METHOD == 2

#define OS_ENTER_CRITICAL() asm {PUSHF; CLI} /* Disable interrupts */

#define OS_EXIT_CRITICAL() asm POPF /* Enable interrupts */

#endif

 

#if OS_CRITICAL_METHOD == 3

#define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR()) /* Disable interrupts */

#define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr)) /* Enable interrupts */

#endif

4.ECB 事件控制块及相关函数

 

4.1OS_EVENT 结构体的定义

#if (OS_EVENT_EN > 0) && (OS_MAX_EVENTS > 0)

typedef struct {

INT8U OSEventType; /* 事件控制块类型 */

INT8U OSEventGrp; /* 等待任务列表组信息 */

INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* 等待事件发生的任务列表 */

INT16U OSEventCnt; /* 当事件是一个信号量时, OSEventCnt 是用于信号量的计数器 */

void *OSEventPtr; /* Pointer to message or queue structure */

} OS_EVENT;

#endif

 

4.2EVENT相关宏定义

#define OS_EVENT_TYPE_UNUSED 0

#define OS_EVENT_TYPE_MBOX 1

#define OS_EVENT_TYPE_Q 2

#define OS_EVENT_TYPE_SEM 3

#define OS_EVENT_TYPE_MUTEX 4

#define OS_EVENT_TYPE_FLAG 5

4.3OS_EventWaitListInit() 初始化一个事件控制块

 

初始化 OS_EVENT 变量的等待任务列表信息

#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) || (OS_SEM_EN > 0) || (OS_MUTEX_EN > 0)

void OS_EventWaitListInit (OS_EVENT *pevent)

{

INT8U *ptbl;

pevent->OSEventGrp = 0x00; /* No task waiting on event */

ptbl = &pevent->OSEventTbl[0];

#if OS_EVENT_TBL_SIZE > 0

*ptbl++ = 0x00;

#endif

#if OS_EVENT_TBL_SIZE > 1

*ptbl++ = 0x00;

#endif

#if OS_EVENT_TBL_SIZE > 2

*ptbl++ = 0x00;

#endif

#if OS_EVENT_TBL_SIZE > 3

*ptbl++ = 0x00;

#endif

#if OS_EVENT_TBL_SIZE > 4

*ptbl++ = 0x00;

#endif

#if OS_EVENT_TBL_SIZE > 5

*ptbl++ = 0x00;

#endif

#if OS_EVENT_TBL_SIZE > 6

*ptbl++ = 0x00;

#endif

 

#if OS_EVENT_TBL_SIZE > 7

*ptbl = 0x00;

#endif

}

#endif

 

 

4.4OS_EventTaskRdy()使任务进入就绪态

4.4.1源码分析

INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)

  1. OS_EVENT *pevent 进入就绪态的任务事件指针

  2. Void *msg

  3. INT8U msk 该参数是用于将 TCB 中的 OSTCBStat 相应位清零,和所发生事件的类型相对应。

#if OS_EVENT_EN > 0

INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)

{

OS_TCB *ptcb;

INT8U x;

INT8U y;

INT8U bitx;

INT8U bity;

INT8U prio;

 

 

y = OSUnMapTbl[pevent->OSEventGrp]; /* 得到等待列表最高优先级信息 */

bity = OSMapTbl[y];

x = OSUnMapTbl[pevent->OSEventTbl[y]];

bitx = OSMapTbl[x];

prio = (INT8U)((y << 3) + x); /* 计算任务优先级 */

if ((pevent->OSEventTbl[y] &= ~bitx) == 0x00) { /* 将任务从等待列表中删去 */

pevent->OSEventGrp &= ~bity; /* 如果是该等待列表组唯一个等待任务,组清零 */

}

ptcb = OSTCBPrioTbl[prio]; /* 找到指向这个优先级的任务 TCB */

ptcb->OSTCBDly = 0; /* 延时变量清零 ,即就绪 */

ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* 清除事件控制块 */

#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)

ptcb->OSTCBMsg = msg; /* 将消息发送给等待的 TCB */

#else

msg = msg; /* Prevent compiler warning if not used */

#endif

ptcb->OSTCBStat &= ~msk; /* 清除等待事件的相应状态 */

if (ptcb->OSTCBStat == OS_STAT_RDY) { /* 如果任务未被挂起 */

OSRdyGrp |= bity; /* 将任务加入就绪表 */

OSRdyTbl[y] |= bitx;

}

return (prio);

}

#endif

 

4.4.2 流程图

3 OS_EventTaskRdy() 流程图

 

4.5OS_EventTaskWait() 任务进入等待某事件发生状态

4.5.1源码分析

void OS_EventTaskWait (OS_EVENT *pevent)

{

OSTCBCur->OSTCBEventPtr = pevent; /* ECB 指针放到 TCB OSTCBEventPtr */

if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) { /* 从就绪表中清除 */

OSRdyGrp &= ~OSTCBCur->OSTCBBitY;

}

pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* 加入等待列表 */

pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;

}

#endif

 

4.5.2 流程图

4 OSEventTaskWait 流程图

 

4.6OS_EventTo() 由于等待超时将任务置为就绪态

4.6.1源码分析

#if OS_EVENT_EN > 0

void OS_EventTO (OS_EVENT *pevent)

{

if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) {

pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY; /* 从等待列表中清除 */

}

OSTCBCur->OSTCBStat = OS_STAT_RDY; /* TCB 的状态位置为就绪 */

OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* 不再等待事件 */

}

#endif

 

 

 

5.消息

5.1信号量

5.1.1 OSSemCreate()创建信号量

  1.  
    1.  
      1.  
        1. 源码分析
  1. INT16U cnt 信号量计数值

说明:

μC/OS-II 中,信号量一旦建立就不能删除了,因此也就不可能将一个已分配的任务控制块再放回到空闲 ECB 链表中

OS_EVENT *OSSemCreate (INT16U cnt)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_EVENT *pevent;

 

 

**********

if (OSIntNesting > 0) { /* */

return ((OS_EVENT *)0); /* */

}

******///

OS_ENTER_CRITICAL();

pevent = OSEventFreeList; /* 获得空闲 ECB */

if (OSEventFreeList != (OS_EVENT *)0) { /* 看空闲 PCB 池是否已满 */

/****

OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* */

****/

}

OS_EXIT_CRITICAL();

if (pevent != (OS_EVENT *)0) { /* 如果得到一个 ECB */

pevent->OSEventType = OS_EVENT_TYPE_SEM; /* 设置 ECB 类型 */

///*******

pevent->OSEventCnt = cnt; /* 设置信号量计数值 */

*******///

pevent->OSEventPtr = (void *)0; /* ECB 空闲列表中脱掉 */

OS_EventWaitListInit(pevent); /* 初始化,令其初始无等待任务 */

}

return (pevent);

}

 

5 OSSemCreate ()流程图

 

5.1.2 OSSemPend() 任务等待一个信号量

源代码分析
  1. OS_EVENT *pevent

  2. INT16U timeout

  3. INT8U *err

void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

 

 

if (OSIntNesting > 0) { /* See if called from ISR ... */

*err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */

return;

}

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */

*err = OS_ERR_PEVENT_NULL;

return;

}

if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */

*err = OS_ERR_EVENT_TYPE;

return;

}

#endif

OS_ENTER_CRITICAL();

if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... */

pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return;

}

/* Otherwise, must wait until event occurs */

OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */

****

OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */

****

OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */

OS_EXIT_CRITICAL();

///*** 是否有可能不需要进行任务切换

OS_Sched(); /* Find next highest priority task ready */

OS_ENTER_CRITICAL();

if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { /* Must have timed out if still waiting for event*/

OS_EventTO(pevent);

OS_EXIT_CRITICAL();

*err = OS_TIMEOUT; /* Indicate that didn't get event within TO */

return;

}

OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

}

 

流程图

 

 

6 OSSemPend() 流程图

 

5.1.3 OSSemPost()发送一个信号量

源代码分析
  1. OS_EVENT *pevent 信号量的指针

INT8U OSSemPost (OS_EVENT *pevent)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* 查看 ECB 是否有效 */

return (OS_ERR_PEVENT_NULL);

}

if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* 查看 ECB 类型是否为消息 */

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

if (pevent->OSEventGrp != 0x00) { /* 看等待列表中是否有等待该消息的任务 */

OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* 有则将最高 prio 的任务就绪 */

OS_EXIT_CRITICAL();

OS_Sched(); /* 可能发生调度,进行任务切换 */

return (OS_NO_ERR);

}

if (pevent->OSEventCnt < 65535) { /* 如果信号计数值没有溢出的可能 */

pevent->OSEventCnt++; /* 信号量计数值加 1 */

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

OS_EXIT_CRITICAL(); /* 这里信号计数值已发生溢出 */

return (OS_SEM_OVF);

}

 

流程图

7 OSSemPost() 流程图

 

5.1.4 OSSemAccept() 无等待的请求一个信号量

源码分析
  1. OS_EVENT *pevent ECB 的指针,指向请求的信号量

说明:

  1. 中断服务子程序要请求信号量时,只能用 OSSemAccept() 而不能用 OSSemPend() ,因为中断服务子程序是不允许等待的

 

#if OS_SEM_ACCEPT_EN > 0

INT16U OSSemAccept (OS_EVENT *pevent)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

INT16U cnt;

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* 检查 ECB 是否有效 */

return (0);

}

if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* 检查事件类型是否正确,是否为消息 */

return (0);

}

#endif

OS_ENTER_CRITICAL();

cnt = pevent->OSEventCnt;

if (cnt > 0) { /* 资源是否有用 */

pevent->OSEventCnt--; /* 如果有用,资源数减一 */

}

OS_EXIT_CRITICAL();

return (cnt); /* 返回原有的资源数,用以说明该资源是否可用,另外也可以看到该资源数的的多少 */

}

#endif

 

流程图

8 OSSemAccept 流程图

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值