1:消息队列
消息队列可以同时传递多个消息,当时间控制块中的变量OSEventType值为:OS_EVENT_TYPE_Q表示此事件控制块是用来表示消息队列的。消息队列数据结构如下:
在上面的事件控制块的OSEventPtr指针指向了消息队列结构体:OS_Q。改结构体OS_Q管理者一个消息数组,这个数组中存放是消息的指针。
2:队列控制块
OS_Q的定义如下:
typedef struct os_q { /* QUEUE CONTROL BLOCK */
struct os_q *OSQPtr; /* Link to next queue control block in list of 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;
其中OSQStart和OSQEnd 是常指针,分别指向队列消息数组的开始和结尾,OSQIn和OSQOut指针随着数据的插入和删除而改变。这些值的改变可以在队列的创建及消息的获取,post函数中看到。
消息队列的初始化函数与其他初始化函数:事件控制块,任务控制块类似的。有一个全局数组(定义了队列个数)及空闲链表(空闲的队列数)。如下全局变量:
#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
OS_EXT OS_Q *OSQFreeList; /* Pointer to list of free QUEUE control blocks */
OS_EXT OS_Q OSQTbl[OS_MAX_QS]; /* Table of QUEUE control blocks */
#endif
经过上面的初始化以后,OS_MAX_QS个消息队列连接成一个链表,OSQFreeList指向链表的开始。每当任务创建一个消息队列时,就会从空闲的队列链表OSQFreeList中取出一个来使用。空闲队列链表的如下:
3:消息队列创建
由于在消息队列中,存放消息的是指针数组,故在建立消息队列之前,必须先建立一个用来存放消息的指针数组。
OS_EVENT *OSQCreate (void **start, INT16U size)
{
OS_EVENT *pevent;
OS_Q *pq;
#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) { /* See if we have an event control block */
OS_ENTER_CRITICAL();
pq = OSQFreeList; /* Get a free queue control block */在空闲队列链表中取出一个空闲的队列
if (pq != (OS_Q *)0) { /* Were we able to get a queue control block ? */
OSQFreeList = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/
OS_EXIT_CRITICAL();
pq->OSQStart = start; /* Initialize the queue */
pq->OSQEnd = &start[size];分别指向了消息的数组起始和结尾
pq->OSQIn = start;
pq->OSQOut = start;
pq->OSQSize = size;//存放消息的数目
pq->OSQEntries = 0;
pevent->OSEventType = OS_EVENT_TYPE_Q;
pevent->OSEventCnt = 0;
pevent->OSEventPtr = pq;//指向了消息队列指针。
#if OS_EVENT_NAME_SIZE > 1
pevent->OSEventName[0] = '?'; /* Unknown name */
pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
OS_EventWaitListInit(pevent); /* Initalize the wait list */
} else {
pevent->OSEventPtr = (void *)OSEventFreeList; /* No, Return event control block on error */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
pevent = (OS_EVENT *)0;
}
}
return (pevent);
}
4:向消息队列发送消息
ucos中有俩种方式来向指针数组中存放消息。一种是先进先出FIFO,另一种是:后进先出LIFO。
这俩种方式分别使用函数OSQPost()和OSQPostFront()来实现。
FIFO时,消息队列将在OSQIn 指向的位置插入消息,OSQOut 指向输出消息的指针。
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0) { /* See if any task pending on queue */
/* Ready highest priority task waiting on event */
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
OS_EXIT_CRITICAL();
OS_Sched(); /* Find highest priority task ready to run */
return (OS_ERR_NONE);
}
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
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) { /* Wrap IN ptr if we are at end of queue */
pq->OSQIn = pq->OSQStart;
}
OS_EXIT_CRITICAL();
LIFO时,使用OSQOut 来完成消息的出入。
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0) { /* See if any task pending on queue */
/* Ready highest priority task waiting on event */
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
OS_EXIT_CRITICAL();
OS_Sched(); /* Find highest priority task ready to run */
return (OS_ERR_NONE);
}
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
OS_EXIT_CRITICAL();
return (OS_ERR_Q_FULL);
}
if (pq->OSQOut == pq->OSQStart) { /* Wrap OUT ptr if we are at the 1st queue entry */
pq->OSQOut = pq->OSQEnd;
}
pq->OSQOut--;
*pq->OSQOut = pmsg; /* Insert message into queue */
pq->OSQEntries++; /* Update the nbr of entries in the queue */
OS_EXIT_CRITICAL();
ucos 消息队列
最新推荐文章于 2024-01-16 12:21:41 发布