赞
踩
本文主要是对UCOS-II中队列的建立过程进行分析及总结。
第一步:OS操作系统会在初始化函数OSInit中对事件进行初始化。
第二步:OS操作系统会在初始化函数OSInit中对队列进行初始化。
第一步和第二步初始化的结果如下图所示,图中只是两个结构体的架构图,其中有些细节需要指出:
1)在初始化完成后,事件结构体中OSEventType为未使用类型。
2)在初始化完成后,事件结构体中OSEventPtr指向下一个事件结构体(该指针代表事件的类型,这里指向下一个指针只是为了临时放置,以便于得到下一个空闲的事件结构体,注意该指针的类型为空指针)

第三步:系统在需要的地方创建消息队列,函数如下所示,通过OSQCreate函数来创建队列。
队列如何工作?
在创建完成队列之后,我们下面来看下,消息队列是如何工作的。由下面的代码可以看出,在OS系统中,建立的是一个环形队列。
- //数据存入队列
- if (pq->OSQEntries >= pq->OSQSize)
- {
- OS_EXIT_CRITICAL();
- return (OS_ERR_Q_FULL);
- }
- *pq->OSQIn++ = pmsg; /* Insert message into queue */
- pq->OSQEntries++; /* Update the nbr of entries in the queue */
- if (pq->OSQIn == pq->OSQEnd)
- {
- pq->OSQIn = pq->OSQStart;
- }
- //数据读出队列
- if (pq->OSQEntries > 0u)
- {
- pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */
- pq->OSQEntries--; /* Update the number of entries in the queue */
- if (pq->OSQOut == pq->OSQEnd) /* Wrap OUT pointer if we are at the end of the queue*/
- {
- pq->OSQOut = pq->OSQStart;
- }
- }

为什么在中断中能使用OSQPost函数,但是不能使用OSQPend函数?
首先我们知道,当执行任务调度时,实际上是触发了PendSV中断,如果在任务中执行任务调度,那么ARM将直接跳转到PendSV中断去执行。但是如果在中断中触发了PendSV中断,由于PendSV中断的中断优先级设置的较低,所以系统会等所有的中断执行完了后,再去执行PendSV中断。
那么为什么不能再中断中调用Pend函数呢?我们先看下Pend函数的源码,源码如下所示,注意观察到如果在执行任务调度前,函数没有被返回的话,那么系统将执行任务调度。
如果是在中断中执行任务调度,那么系统不会立即跳转到最高优先级的任务,而是等待函数执行完了再去跳转,那么在该函数中,执行了任务调度后所执行的函数就具有具体意义了。
- void *OSQPend (OS_EVENT *pevent,
- INT32U timeout,
- INT8U *perr)
- {
- void *pmsg;
- OS_Q *pq;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
-
- #ifdef OS_SAFETY_CRITICAL
- if (perr == (INT8U *)0)
- {
- OS_SAFETY_CRITICAL_EXCEPTION();
- }
- #endif
-
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0)
- { /* Validate 'pevent' */
- *perr = OS_ERR_PEVENT_NULL;
- return ((void *)0);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_Q)
- { /* Validate event block type */
- *perr = OS_ERR_EVENT_TYPE;
- return ((void *)0);
- }
- if (OSIntNesting > 0u)
- { /* See if called from ISR ... */
- *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
- return ((void *)0);
- }
- if (OSLockNesting > 0u)
- { /* See if called with scheduler locked ... */
- *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
- return ((void *)0);
- }
- OS_ENTER_CRITICAL();
- pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
- if (pq->OSQEntries > 0u)
- { */
- pmsg = *pq->OSQOut++;
- pq->OSQEntries--;
- if (pq->OSQOut == pq->OSQEnd)
- {
- pq->OSQOut = pq->OSQStart;
- }
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- return (pmsg);
- }
- OSTCBCur->OSTCBStat |= OS_STAT_Q;
- OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
- OSTCBCur->OSTCBDly = timeout;
- OS_EventTaskWait(pevent);
- OS_EXIT_CRITICAL();
- OS_Sched();
- OS_ENTER_CRITICAL();
- switch (OSTCBCur->OSTCBStatPend)
- { /* See if we timed-out or aborted */
- case OS_STAT_PEND_OK:
- pmsg = OSTCBCur->OSTCBMsg;
- *perr = OS_ERR_NONE;
- break;
- case OS_STAT_PEND_ABORT:
- pmsg = (void *)0;
- *perr = OS_ERR_PEND_ABORT;
- break;
- case OS_STAT_PEND_TO:
- default:
- OS_EventTaskRemove(OSTCBCur, pevent);
- pmsg = (void *)0;
- *perr = OS_ERR_TIMEOUT;
- break;
- }
- OSTCBCur->OSTCBStat = OS_STAT_RDY;
- OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
- OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
- #if (OS_EVENT_MULTI_EN > 0u)
- OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
- #endif
- OSTCBCur->OSTCBMsg = (void *)0;
- OS_EXIT_CRITICAL();
- return (pmsg);
- }

附录:重要结构体的定义如下所示。
- //函数调用:
- can1_recv_unit.q_Can_Msg = OSQCreate(&(can1_recv_unit.MsgGrp[0]), CAN1_MSG_GRP_NUM);
- //其中结构体的定义如下:
- //CAN1_MSG_GRP_NUM == 30
- typedef struct
- {
- OS_EVENT *q_Can_Msg;
- void *MsgGrp[CAN1_MSG_GRP_NUM];
- can_message_t storage[CAN1_MSG_GRP_NUM];
- u8 mbox_windex;
- can_message_t *prmsg;
- }can1_recv_unit_t;
-
-
- typedef struct os_event
- {
- INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */
- void *OSEventPtr; /* Pointer to message or queue structure */
- INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */
- OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
- OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE];/* List of tasks waiting for event to occur */
- } OS_EVENT;
-
- typedef struct os_q
- {
- struct os_q *OSQPtr; // Link to next queue control block in listof free blocks
- void **OSQStart; // Pointer to start of queue data
- void **OSQEnd; // Pointer to end of queue data
- 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; //Size of queue (maximum number of entries)
- INT16U OSQEntries; /* Current number of entries in the queue */
- } OS_Q;

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。