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 為消息指針
該函數先檢查消息郵箱結構體成員指針變量OSEventPtr是否為0,若為0,則說明消息郵箱為空,為其賦值pevent->OSEventPtr = pmsg;否則返回對應錯誤代碼。
請求郵箱函數:void *OSMboxPend (OS_EVENT *pevent, INT16U timeout,INT8U *err) 其中 pevent 為請求郵箱指針, timeout 為等待時限, err 為錯誤信息。
這個函數的主要作用就是查看郵箱指針 OSEventPtr 是否為 NULL,如果不是 NULL 就把郵箱中的消息指針返回給調用函數的任務,然后清空郵箱pevent->OSEventPtr = (void *)0;同時用 OS_NO_ERR 通過函數的參數 err 通知任務獲取消息成功。
如果郵箱指針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中的消息隊列每次只能取出一條消息和每次只能放入一條消息。