ucosii支持事件,事件包括信号量、消息等机制。需要配置OS_EVENT_EN、OS_MAX_EVENTS等相关的宏。
事件控制块(ECB)
事件控制块(ECB)是事件管理的核心数据结构。其定义如下:
typedef struct os_event {
INT8U OSEventType; //事件类型,具体有信号量、消息邮箱、消息队列、互斥信号量、事件标志组,都相关的宏
void *OSEventPtr; //指向下一个ECB或者是消息或是队列的指针
INT16U OSEventCnt; //信号量的计数值,就只跟信号量有关系,跟其他事件没有关系
OS_PRIO OSEventGrp; //等待事件标志表
OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; //等待事件标志组
#if OS_EVENT_NAME_EN > 0u
INT8U *OSEventName; //事件名称
#endif
} OS_EVENT;
} OS_EVENT;
#endif
等待事件表和等待事件标志组跟就绪表和就绪组基本上一样。
事件控制块在ucosii中以数组的方式定义OS_EVENT OSEventTbl[OS_MAX_EVENTS];
OS_MAX_EVENTS可以根据需要自己配置,系统默认值是10。
空闲的时间控制块都组成一个单链表,并且由指针OSEventFreeList指向该链表。
事件控制块初始化函数OS_InitEventList
该函数在系统开始前做在调用OSInit()进行初始化的时候需要用到该函数。
该函数主要功能的将ucosii中定义的事件控制块形成链表,并且对各个时间控制块的成员进行相应的初始化。
等待事件设置函数OS_EventTaskWait
这个函数是将对应的事件控制块以及相应的事件进行设置。这个函数是将对应的事件控制块以及相应的事件和申请任务进行设置。将当前的任务在对应ECB中登记,更新任务的运行状态。
void OS_EventTaskWait (OS_EVENT *pevent) //os_core.c中定义
{
INT8U y;
OSTCBCur->OSTCBEventPtr = pevent; //将任务控制块的事件控制块指针指向该事件控制块
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; //更新表和数组
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
y = OSTCBCur->OSTCBY;
OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0u) { /* Clear event grp bit if this was only task pending */
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
}
if (OSRdyTbl[y] == 0u) { /* Clear event grp bit if this was only task pending */
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
}
}
取消等待事件(OS_EventTaskRemove)就是将该上面函数的逆。
等待事件中的任务就绪OS_EventTaskRdy
当有事件发生的时候,就有必要更新事件控制块,同时将在ECB事件表和就绪组进行更新,并将注册的任务(此时应该已经是阻塞了)的状态进行更新
INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk,INT8U pend_stat)
该函数的参数解释:OS_EVENT *pevent 对应的事件控制块 void *pmsg 消息指针,只有在用到消息的时候才会用到
INT8U msk 清除状态的掩码。前面我们知道,TCB中的OSTCBStat中不同位关于不同事件的标志位,该掩码就是用来消除因等待该事件而OSTCBStat相应的位。
NT8U pend_stat 表示等待(阻塞)任务等待结束,任务就绪的原因。可能是这几个值
#define OS_STAT_PEND_OK 0u //正常结束,是事件发生
#define OS_STAT_PEND_TO 1u //等待超时
#define OS_STAT_PEND_ABORT 2u //异常
其代码主要如下:
找到最高优先级的注册任务
y = OSUnMapTbl[pevent->OSEventGrp];
x = OSUnMapTbl[pevent->OSEventTbl[y]];
prio = (INT8U)((y << 3u) + x);
ptcb = OSTCBPrioTbl[prio]; //指向任务等待优先级最高的任务控制块
ptcb->OSTCBDly = 0u; //将其等待事件清零(因为在等待的时间里,时间发生了)
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)
ptcb->OSTCBMsg = pmsg; //发送消息
#else
pmsg = pmsg; /* Prevent compiler warning if not used */
#endif
pmsg = pmsg; /* Prevent compiler warning if not used */
#endif
ptcb->OSTCBStat &= (INT8U)~msk; //更新任务控制块的状态
ptcb->OSTCBStatPend = pend_stat; //跟新相应任务控制块的阻塞状态
/* See if task is ready (could be susp'd) */
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {
OSRdyGrp |= ptcb->OSTCBBitY; //更新就绪数组和就绪表
OSRdyTbl[y] |= ptcb->OSTCBBitX;
}
}
OS_EventTaskRemove(ptcb, pevent); //将该任务从该等待事件中取消
#if (OS_EVENT_MULTI_EN > 0u)
if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { //若是多事件等待,相关的操作,这个在后面再介绍
OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
ptcb->OSTCBEventPtr = (OS_EVENT *)pevent;
}
#endif
#endif
return (prio); //返回就绪状态的优先级