UCOSII 使用叫作事件控制塊(ECB)的數據結構來描述諸如信號量、郵箱(消息郵箱)和消息隊列這些事件
數組
#define OS_EVENT_EN (((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u) || (OS_SEM_EN > 0u) || (OS_MUTEX_EN > 0u))
事件控制塊類型定義:數據結構
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 */ #if OS_EVENT_NAME_EN > 0u INT8U *OSEventName; #endif } OS_EVENT;
消息郵箱:函數
向郵箱發送消息函數:INT8U OSMboxPost (OS_EVENT *pevent, void *pmsg)其中 pevent 爲消息郵箱的指針, msg 爲消息指針 spa
該函數先檢查消息郵箱結構體成員指針變量OSEventPtr是否爲0,若爲0,則說明消息郵箱爲空,爲其賦值pevent->OSEventPtr = pmsg;不然返回對應錯誤代碼。指針
請求郵箱函數:void *OSMboxPend (OS_EVENT *pevent, INT16U timeout,INT8U *err) 其中 pevent 爲請求郵箱指針, timeout 爲等待時限, err 爲錯誤信息。code
這個函數的主要做用就是查看郵箱指針 OSEventPtr 是否爲 NULL,若是不是 NULL 就把郵箱中的消息指針返回給調用函數的任務,而後清空郵箱pevent->OSEventPtr = (void *)0;同時用 OS_NO_ERR 經過函數的參數 err 通知任務獲取消息成功。blog
如果郵箱指針OSEventPtr 是 NULL,則使任務進入等待狀態,並引起一次任務調度
建立消息郵箱:OS_EVENT *OSMboxCreate (void *pmsg),
例如:隊列
msg_key=OSMboxCreate((void*)0); //建立郵箱並初始化爲空
若是指針不爲空,創建的消息郵箱將含有消息進程
消息隊列:事件
與郵箱相比,消息隊列在OS_EVENT結構基礎之上添加了一循環隊列,能夠同時容納多個消息,而郵箱只能容納一個。所以,能夠將消息隊列看做同時接收多條消息的郵箱。
隊列控制塊類型定義:
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;
OSQSize:消息指針數組的大小
OSQEntries:消息指針數組中當前存放的消息指針數量(對應消息數量)
1) 建立消息隊列函數
建立一個消息隊列首先須要定義一指針數組,而後把各個消息數據緩衝區的首地址存
入這個數組中,而後再調用函數 OSQCreate 來建立消息隊列。建立消息隊列函數 OSQCreate
的原型爲: OS_EVENT *OSQCreate(void**start,INT16U size)。其中, start 爲存放消息緩衝
區指針數組的地址, size 爲該數組大小。該函數的返回值爲消息隊列指針。
2) 請求消息隊列函數
請求消息隊列的目的是爲了從消息隊列中獲取消息。任務請求消息隊列須要調用函數
OSQPend,該函數原型爲: void*OSQPend(OS_EVENT*pevent,INT16U timeout,INT8U *err)。
其中, pevent 爲所請求的消息隊列的指針, timeout 爲任務等待時限, err 爲錯誤信息。
下面是函數的部分關鍵代碼:
pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */ if (pq->OSQEntries > 0u) { /* See if any messages in the queue */ 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; } OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return (pmsg); /* Return message received */ }
3) 向消息隊列發送消息函數
任務能夠經過調用函數 OSQPost 或 OSQPostFront 兩個函數來向消息隊列發送消息。函數 OSQPost 以 FIFO( 先進先出)的方式組織消息隊列,函數 OSQPostFront 以 LIFO(後
進先出)的方式組織消息隊列。這兩個函數的原型分別爲: INT8U OSQPost(OS_EVENT*pevent,void *msg)和 INT8U OSQPost(OS_EVENT*pevent,void*msg)。
其中, pevent 爲消息隊列的指針, msg 爲待發消息的指針。
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; }
注:消息隊列用做消息緩衝區是明智的(適合於進程通訊),可要是用它來做爲接收批量數據的數據緩衝區就不行了,由於ucos中的消息隊列每次只能取出一條消息和每次只能放入一條消息。