μC/OS-II系統中訊息佇列的使用
以下內容主要注重應用,對原始碼不做分析,對原始碼有興趣的可參考官方具體文件,相關連結:https://doc.micrium.com/display/ucos/
開發環境:TrueSTUDIO
微控制器:STM32F103VET6(HAL庫)
一、建立一個訊息佇列,OSQCreate()
在使用訊息佇列之前,需要先建立訊息佇列(或簡單地說一個佇列)。建立佇列是通過呼叫OSQCreate()並向它傳遞兩個引數來完成的:一個指向一個數組的指標,這個陣列將儲存訊息和這個陣列的大小。這個陣列必須宣告為一個指向void的指標陣列,如下所示:
void * MyArrayOfMsg(大小);
你需要將MyArrayOfMsg[]的地址以及這個陣列的大小傳遞給OSQCreate()。如果訊息佇列最初為空則它不包含任何訊息
1、OS_EVENT *OSQCreate (
void
**start, INT16U size)。
- start是指向一個數組的指標,這個陣列將儲存訊息;
- size是指向陣列的大小;
- 返回與佇列相關聯的指向事件控制塊的指標。
二、傳送一個訊息到訊息佇列(FIFO 先進先出原則),OSQPost()
將一個訊息存到訊息佇列,函式原型為:
1、INT8U OSQPost (OS_EVENT *pevent,
void
*msg)。
- pevent是訊息佇列相關聯的指向事件控制塊的指標;
- msg是指向您希望存入訊息佇列的訊息的指標(傳送的不能是空指標,由於佇列傳送的訊息是地址,被髮送的訊息最好是全域性變數
- 返回值是錯誤型別。
三、傳送一個訊息到訊息佇列(LIFO 後進先出原則),OSQPostFront()
將一個訊息存到訊息佇列,函式原型為:
1、INT8U OSQPostFront (OS_EVENT *pevent,
void
*msg)
- pevent是訊息佇列相關聯的指向事件控制塊的指標;
- msg是指向您希望存入訊息佇列的訊息的指標(傳送的不能是空指標,由於佇列傳送的訊息是地址,被髮送的訊息最好是全域性變數);
- 返回值是錯誤型別。
四、從一個訊息佇列中等待一個訊息,OSQPend()
等待一個訊息到達訊息佇列,函式原型為:
1、void
*OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
- pevent是訊息佇列相關聯的指向事件控制塊的指標;
- timeout等待時長(如果是0將一直等下去,直到訊息佇列中有訊息);
- err錯誤型別;
- 返回值是訊息佇列中收到的訊息指標。
五、示例程式碼(非中斷方式)
1、定義一個訊息佇列事件指標和訊息佇列的儲存單元(儲存單元儲存的是資料的指標):
/* 定義一個訊息佇列事件指標 */ OS_EVENT *MessageQ; /* 定義訊息佇列的空間大小 */ void *MessageStorage[10];
2、建立訊息佇列:
/* 建立訊息佇列, 含10個儲存單元(儲存的內容是指標不是資料) */ MessageQ = OSQCreate(&MessageStorage[0], 10);
3、在一個任務中傳送兩種不同的值的地址到訊息郵箱:
static void AppTask1(void *p_arg) { INT16U value1 = 1, value2 = 2; (void)p_arg; while(1) { if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) { /* 傳送訊息到訊息佇列 */ OSQPost(MessageQ, (void *)&value1); } if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET) { /* 傳送訊息到訊息佇列 */ OSQPost(MessageQ, (void *)&value2); } OSTimeDlyHMSM(0, 0, 0, 100); } }
4、在一個任務中接收訊息佇列中的訊息:
static void AppTask2(void *p_arg) { INT8U err; INT16U r_value; (void)p_arg; while(1) { /* 等待訊息佇列獲取到訊息 */ r_value = *(INT16U *)OSQPend(MessageQ, 0, &err); if(err == OS_ERR_NONE) { if(r_value == 1) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); } else if(r_value ==2) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5); } } } }
六、示例程式碼(中斷方式)
1、定義訊息佇列事件指標和訊息佇列的儲存單元(儲存單元儲存的是資料的指標):
/* 定義兩個訊息佇列事件溼疹 */ OS_EVENT *MessageQ1; OS_EVENT *MessageQ2; /* 定義訊息佇列的儲存單元 */ void *MessageStorage1[10]; void *MessageStorage2[10];
2、建立訊息佇列:
/* 建立訊息佇列,含10個儲存單元 */ MessageQ1 = OSQCreate(&MessageStorage1[0], 10); MessageQ2 = OSQCreate(&MessageStorage2[0], 10);
3、中斷函式中進行鍼對μC/OS系統的處理:
/** * @brief This function handles EXTI line0 interrupt. */ void EXTI0_IRQHandler(void) { #if uCOS_EN == 1 #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif OS_ENTER_CRITICAL(); OSIntEnter(); OS_EXIT_CRITICAL(); #endif HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); #if uCOS_EN == 1 OSIntExit(); #endif } /** * @brief This function handles EXTI line[15:10] interrupts. */ void EXTI15_10_IRQHandler(void) { #if uCOS_EN == 1 #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif OS_ENTER_CRITICAL(); OSIntEnter(); OS_EXIT_CRITICAL(); #endif HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); #if uCOS_EN == 1 OSIntExit(); #endif }
4、在中斷的回撥函式中傳送訊息,針對不同埠引腳被觸發傳送不同的訊息:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_0) { OSQPost(MessageQ1, (void *)&value_u8); } if(GPIO_Pin == GPIO_PIN_13) { OSQPost(MessageQ2, (void *)&value_u16); } }
5、建立兩個任務分別去接收中斷髮出的郵箱訊息:
static void AppTaskLed1(void *p_arg) { INT8U err; INT8U r_value; (void)p_arg; while(1) { /* 從訊息佇列中獲取訊息 */ r_value = *(INT8U *)OSQPend(MessageQ1, 0, &err); if(err == OS_ERR_NONE) { if(r_value == 1) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5); } } } } static void AppTaskLed2(void *p_arg) { INT8U err; INT16U r_value; (void)p_arg; while(1) { /* 從訊息佇列中獲取訊息 */ r_value = *(INT16U *)OSQPend(MessageQ2, 0, &err); if(err == OS_ERR_NONE) { if(r_value == 2) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); } } } }
#endif