在主函数中,创建完成了需要的task之后,是创建信号量,邮箱,消息队列等任务间通信的结构
这些结构拥有一个相同的特点,他们都需要时间控制块ECB和ECB查找表的支持,这个机制类似于最高优先级查找表,能够选出相应优先级对应的事件控制块是不是已经进入就绪,任务的就绪使用OSxxPost函数实现
我们来看一个完整的信号量的实现函数组
OSSemCreate
- /*
- *********************************************************************************************************
- * CREATE A SEMAPHORE
- *
- * Description: This function creates a semaphore.
- *
- * Arguments : cnt is the initial value for the semaphore. If the value is 0, no resource is
- * available (or no event has occurred). You initialize the semaphore to a
- * non-zero value to specify how many resources are available (e.g. if you have
- * 10 resources, you would initialize the semaphore to 10).
- *
- * Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the
- * created semaphore
- * == (void *)0 if no event control blocks were available
- *********************************************************************************************************
- */
- OS_EVENT *OSSemCreate (INT16U cnt)
- {
- OS_EVENT *pevent;
- #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0;
- #endif
- if (OSIntNesting > 0) { /* See if called from ISR ... */
- return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
- }
- OS_ENTER_CRITICAL();
- pevent = OSEventFreeList; /* Get next free event control block */
- if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
- OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
- }
- OS_EXIT_CRITICAL();
- if (pevent != (OS_EVENT *)0) { /* Get an event control block */
- pevent->OSEventType = OS_EVENT_TYPE_SEM;
- pevent->OSEventCnt = cnt; /* Set semaphore value */
- pevent->OSEventPtr = (void *)0; /* Unlink from ECB free list */
- #if OS_EVENT_NAME_SIZE > 1
- pevent->OSEventName[0] = '?'; /* Unknown name */
- pevent->OSEventName[1] = OS_ASCII_NUL;
- #endif
- OS_EventWaitListInit(pevent); /* Initialize to 'nobody waiting' on sem. */
- }
- return (pevent);
- }
首先,这个函数有一个叫做cnt的参数,这表示初始化的资源数,或者事件发生数
如果初始化为0表示没有发生,没有资源,如果初始化为10,表示已经发生了10次?
下面是返回值,如果返回值为NULL说明没有初始化成功信号量
如果成功,返回一个非空的指针,指向初始化好的ECB
第一步,检测是否在中断嵌套中,如果在嵌套中则不能成功初始化,返回NULL
第二步,关中断,从链表OSEventFreeList的表头取得一个空ECB,赋值给*pevent
如果链表不是空链表,那么表头指针指向下一个ECB元素,将这个ECB贡献出来
第三步,开中断,如果这个ECB不是空,pevent不是NULL,对这个ECB进行初始化
pevent->OSEventType = OS_EVENT_TYPE_SEM;//设置ECB类型为信号量
pevent->OSEventCnt = cnt; /* Set semaphore value *///设置初始值为cnt参数
pevent->OSEventPtr = (void *)0; /* Unlink from ECB free list *///将原本指向下一个ECB的指针指向空
第四步,写一个?进名字数组中
第五步,OS_EventWaitListInit初始化EventWaitList,每一个初始化了的ECB会对应一个EWL,对应的Post函数能够将ECB中的EWL的对应项置1,具体我们在Post函数中再看
函数OS_EventWaitListInit
- /*
- *********************************************************************************************************
- * INITIALIZE EVENT CONTROL BLOCK'S WAIT LIST
- *
- * Description: This function is called by other uC/OS-II services to initialize the event wait list.
- *
- * Arguments : pevent is a pointer to the event control block allocated to the event.
- *
- * Returns : none
- *
- * Note : This function is INTERNAL to uC/OS-II and your application should not call it.
- *********************************************************************************************************
- */
- #if OS_EVENT_EN
- void OS_EventWaitListInit (OS_EVENT *pevent)
- {
- #if OS_LOWEST_PRIO <= 63
- INT8U *ptbl;
- #else
- INT16U *ptbl;
- #endif
- INT8U i;
- pevent->OSEventGrp = 0; /* No task waiting on event */
- ptbl = &pevent->OSEventTbl[0];
- for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
- *ptbl++ = 0;
- }
- }
- #endif
将EWL初始化为0和0数组
悬挂等待函数
- /*
- *********************************************************************************************************
- * PEND ON SEMAPHORE
- *
- * Description: This function waits for a semaphore.
- *
- * Arguments : pevent is a pointer to the event control block associated with the desired
- * semaphore.
- *
- * timeout is an optional timeout period (in clock ticks). If non-zero, your task will
- * wait for the resource up to the amount of time specified by this argument.
- * If you specify 0, however, your task will wait forever at the specified
- * semaphore or, until the resource becomes available (or the event occurs).
- *
- * err is a pointer to where an error message will be deposited. Possible error
- * messages are:
- *
- * OS_NO_ERR The call was successful and your task owns the resource
- * or, the event you are waiting for occurred.
- * OS_TIMEOUT The semaphore was not received within the specified
- * timeout.
- * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
- * OS_ERR_PEND_ISR If you called this function from an ISR and the result
- * would lead to a suspension.
- * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
- *
- * Returns : none
- *********************************************************************************************************
- */
- 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 = 0;
- #endif
- #if OS_ARG_CHK_EN > 0
- if (err == (INT8U *)0) { /* Validate 'err' */
- return;
- }
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- *err = OS_ERR_PEVENT_NULL;
- return;
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
- *err = OS_ERR_EVENT_TYPE;
- return;
- }
- if (OSIntNesting > 0) { /* See if called from ISR ... */
- *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
- return;
- }
- if (OSLockNesting > 0) { /* See if called with scheduler locked ... */
- *err = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
- return;
- }
- 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->OSTCBPendTO = OS_FALSE;
- 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->OSTCBPendTO == OS_TRUE) { /* See if we timedout */
- 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;
- }
我们可以看到这个函数有三个参数,一个ECB指针,一个timeout变量,一个err指针,木有返回值
ECB不用说,是我们要等待的信号量的ECB指针,timeout以系统tick为单位等待时间如果过长就返回一个TIMEOUT的错误在err指针里
*OS_NO_ERR The call was successful and your task owns the resource
* or, the event you are waiting for occurred.
*OS_TIMEOUT The semaphore was not received within the specified
* timeout.
*OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
*OS_ERR_PEND_ISR If you called this function from an ISR and the result
* would lead to a suspension.
*OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
这是err返回值的选项!
第一步,检查err指针,检查ECB指针是否为NULL指针
第二步,检查pevent->OSEventType != OS_EVENT_TYPE_SEM 如果ECB的等待类型不是信号量,那就搞错了应当使用的函数,比如消息队列你可以用消息队列对应的pend函数
检查是否在IRQ中使用pend函数,不能再IRQ中使用pend,导致IRQ时间太长,而且嵌套,导致系统混乱
检查系统调度是否被锁定,如果被锁定也不能使用pend函数,如果使用pend函数,系统又不调度,那么系统将不再进入下一个task
第三步,关中断,如果cnt>0,cnt--,返回NO_ERR,开中断,结束
第四步,将当前的task设置进入等待delay状态
OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */
OSTCBCur->OSTCBPendTO = OS_FALSE;
OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */
第五步,调用OS_EventTaskWait设置相应的EWL
- /*
- *********************************************************************************************************
- * MAKE TASK WAIT FOR EVENT TO OCCUR
- *
- * Description: This function is called by other uC/OS-II services to suspend a task because an event has
- * not occurred.
- *
- * Arguments : pevent is a pointer to the event control block for which the task will be waiting for.
- *
- * Returns : none
- *
- * Note : This function is INTERNAL to uC/OS-II and your application should not call it.
- *********************************************************************************************************
- */
- #if OS_EVENT_EN
- void OS_EventTaskWait (OS_EVENT *pevent)
- {
- INT8U y;
- OSTCBCur->OSTCBEventPtr = pevent; /* Store pointer to event control block in TCB */
- y = OSTCBCur->OSTCBY; /* Task no longer ready */
- OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
- if (OSRdyTbl[y] == 0) {
- OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Clear event grp bit if this was only task pending */
- }
- pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */
- pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
- }
- #endif
完成三件事,第一,将事件等待指针,指向ECB,第二,将task就绪表中的相应位置为没有就绪
第三,将ECB中的wait list中task的相应位置为等待
第六步,关中断,调度,开中断。
第七步,如果OSTCBCur->OSTCBPendTO == OS_TRUE(time out),执行OS_EventTO(pevent);
反向清除TCB和ECB中的等待信息,清除EWL中task 相应位和等待指针,因为没有post处理
如果不是time out不需要进行TCB和ECB信息的清理,因为在POST函数中有处理
我们来看用post怎么解除ECB中的等待信息
他大爷
阅读(4484) | 评论(0) | 转发(0) |