一、消息隊列(queue)
隊列是一種用于實現任務與任務之間,任務與中斷之間消息交流的機制。
注意:1.數據的操作是FIFO模式。
2.隊列需要明確數據的大小和隊列的長度。
3.寫和讀都會出現堵塞。
實驗:創建一個消息隊列,兩個發送任務,一個接收任務。
其中任務一任務三的等待時間為0,任務二的等待時間為portMAX_DELAY(死等)。
實現:在前一個項目的基礎上進行更改【STM32】利用CubeMX對FreeRTOS用按鍵控制任務
void MX_FREERTOS_Init(void) {/* USER CODE BEGIN Init *//* USER CODE END Init *//* USER CODE BEGIN RTOS_MUTEX *//* add mutexes, ... *//* USER CODE END RTOS_MUTEX *//* Create the semaphores(s) *//* USER CODE BEGIN RTOS_SEMAPHORES *//* add semaphores, ... *//* USER CODE END RTOS_SEMAPHORES *//* USER CODE BEGIN RTOS_TIMERS *//* start timers, add new ones, ... *//* USER CODE END RTOS_TIMERS *//* Create the queue(s) *//* definition and creation of myQueue01 */osMessageQDef(myQueue01, 2, uint32_t);myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);/* USER CODE BEGIN RTOS_QUEUES *//* add queues, ... *//* USER CODE END RTOS_QUEUES *//* Create the thread(s) *//* definition and creation of Task1 */osThreadDef(Task1, StartDefaultTask, osPriorityNormal, 0, 128);Task1Handle = osThreadCreate(osThread(Task1), NULL);/* definition and creation of Task2 */osThreadDef(Task2, StartTask02, osPriorityIdle, 0, 128);Task2Handle = osThreadCreate(osThread(Task2), NULL);/* definition and creation of Task3 */osThreadDef(Task3, StartTask03, osPriorityIdle, 0, 128);Task3Handle = osThreadCreate(osThread(Task3), NULL);/* USER CODE BEGIN RTOS_THREADS *//* add threads, ... *//* USER CODE END RTOS_THREADS */}/* USER CODE BEGIN Header_StartDefaultTask */
/*** @brief Function implementing the Task1 thread.* @param argument: Not used* @retval None*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{/* USER CODE BEGIN StartDefaultTask *//* Infinite loop */BaseType_t xStatus;uint32_t Buf=10086;for(;;){if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0){osDelay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0){xStatus=xQueueSendToBack(myQueue01Handle,&Buf,0);if(xStatus!=pdTRUE){printf("NO1\r\n");osDelay(500);}else{printf("YES1%u\r\n",Buf);osDelay(500);}}}}/* USER CODE END StartDefaultTask */
}/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{/* USER CODE BEGIN StartTask02 *//* Infinite loop */BaseType_t xStatus;uint32_t Buf=66666;for(;;){ if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0){osDelay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0){xStatus=xQueueSendToBack(myQueue01Handle,&Buf,portMAX_DELAY);if(xStatus!=pdTRUE){printf("NO2\r\n");osDelay(500);}else{printf("YES2%u\r\n",Buf);osDelay(500);}}}}/* USER CODE END StartTask02 */
}/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the Task3 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{/* USER CODE BEGIN StartTask03 *//* Infinite loop *///BaseType_t xStatus;uint32_t Buf=0;for(;;){if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0){osDelay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0){printf("當前%u\r\n",Buf);//xStatus=xQueueReceive(myQueue01Handle,&Buf,portMAX_DELAY);if(xQueueReceive(myQueue01Handle,&Buf,portMAX_DELAY)!=pdTRUE){printf("NO3\r\n");}else{printf("YES3%u\r\n",Buf);}}}}/* USER CODE END StartTask03 */
}
現象:隊列滿了以后,任務一無法發送,任務二會死等,隊列空閑以后完成發送。
二、信號量
消息隊列用于傳輸多個數據,占用時間也相對較長,但有時只需要傳輸狀態,因此引入信號量。信號量也是隊列的一種。信號量有兩種,如果它的量只有0(被拿走的狀態)和1(被填入的狀態)兩種狀態,就稱為二進制的信號量;當量的狀態大于兩種,就稱為計數型信號量。
1.二值信號量
實驗:任務一:按鍵采集數據;任務二:拿走以后串口發送信息
實現:
void MX_FREERTOS_Init(void) {/* USER CODE BEGIN Init *//* USER CODE END Init *//* USER CODE BEGIN RTOS_MUTEX *//* add mutexes, ... *//* USER CODE END RTOS_MUTEX *//* Create the semaphores(s) *//* definition and creation of myBinarySem01 */osSemaphoreDef(myBinarySem01);myBinarySem01Handle = osSemaphoreCreate(osSemaphore(myBinarySem01), 1);/* USER CODE BEGIN RTOS_SEMAPHORES *//* add semaphores, ... *//* USER CODE END RTOS_SEMAPHORES *//* USER CODE BEGIN RTOS_TIMERS *//* start timers, add new ones, ... *//* USER CODE END RTOS_TIMERS *//* Create the queue(s) *//* definition and creation of myQueue01 */osMessageQDef(myQueue01, 2, uint32_t);myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);/* USER CODE BEGIN RTOS_QUEUES *//* add queues, ... *//* USER CODE END RTOS_QUEUES *//* Create the thread(s) *//* definition and creation of Task1 */osThreadDef(Task1, StartDefaultTask, osPriorityNormal, 0, 128);Task1Handle = osThreadCreate(osThread(Task1), NULL);/* definition and creation of Task2 */osThreadDef(Task2, StartTask02, osPriorityNormal, 0, 128);Task2Handle = osThreadCreate(osThread(Task2), NULL);/* definition and creation of Task3 */osThreadDef(Task3, StartTask03, osPriorityNormal, 0, 128);Task3Handle = osThreadCreate(osThread(Task3), NULL);/* USER CODE BEGIN RTOS_THREADS *//* add threads, ... *//* USER CODE END RTOS_THREADS */}/* USER CODE BEGIN Header_StartDefaultTask */
/*** @brief Function implementing the Task1 thread.* @param argument: Not used* @retval None*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{/* USER CODE BEGIN StartDefaultTask *//* Infinite loop */BaseType_t xStatus;uint32_t Buf=10086;for(;;){
// {if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0){osDelay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0){
// xStatus=xQueueSendToBack(myQueue01Handle,&Buf,0);if(xSemaphoreGive(myBinarySem01Handle)==pdTRUE){printf("NO1\r\n");}else{printf("YES1%u\r\n",Buf);}}}}/* USER CODE END StartDefaultTask */
}/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the Task3 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{/* USER CODE BEGIN StartTask03 *//* Infinite loop */ uint32_t Buf=0;for(;;){if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0){osDelay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0){ if(xSemaphoreTake(myBinarySem01Handle,0)==pdTRUE){printf("YES3\r\n");}else{printf("NO3%u\r\n",Buf);}}}}/* USER CODE END StartTask03 */
}
?現象:當按鍵釋放了信號量,串口才能成功發送信息。
2.記數型信號量
實驗:任務一 :按鍵一記錄人進來;按鍵二記錄人出去;(最多有10個人)
任務二:串口每隔3S打印人數。
實現:
void MX_FREERTOS_Init(void) {/* USER CODE BEGIN Init *//* USER CODE END Init *//* USER CODE BEGIN RTOS_MUTEX *//* add mutexes, ... *//* USER CODE END RTOS_MUTEX *//* Create the semaphores(s) *//* definition and creation of myBinarySem01 */osSemaphoreDef(myBinarySem01);myBinarySem01Handle = osSemaphoreCreate(osSemaphore(myBinarySem01), 1);/* definition and creation of myCountingSem01 */osSemaphoreDef(myCountingSem01);myCountingSem01Handle = osSemaphoreCreate(osSemaphore(myCountingSem01), 10);/* USER CODE BEGIN RTOS_SEMAPHORES *//* add semaphores, ... *//* USER CODE END RTOS_SEMAPHORES *//* USER CODE BEGIN RTOS_TIMERS *//* start timers, add new ones, ... *//* USER CODE END RTOS_TIMERS *//* Create the queue(s) *//* definition and creation of myQueue01 */osMessageQDef(myQueue01, 2, uint32_t);myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);/* USER CODE BEGIN RTOS_QUEUES *//* add queues, ... *//* USER CODE END RTOS_QUEUES *//* Create the thread(s) *//* definition and creation of Task1 */osThreadDef(Task1, StartDefaultTask, osPriorityNormal, 0, 128);Task1Handle = osThreadCreate(osThread(Task1), NULL);/* definition and creation of Task2 */osThreadDef(Task2, StartTask02, osPriorityNormal, 0, 128);Task2Handle = osThreadCreate(osThread(Task2), NULL);/* definition and creation of Task3 */osThreadDef(Task3, StartTask03, osPriorityNormal, 0, 128);Task3Handle = osThreadCreate(osThread(Task3), NULL);/* USER CODE BEGIN RTOS_THREADS *//* add threads, ... *//* USER CODE END RTOS_THREADS */}/* USER CODE BEGIN Header_StartDefaultTask */
/*** @brief Function implementing the Task1 thread.* @param argument: Not used* @retval None*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{/* USER CODE BEGIN StartDefaultTask *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0){osDelay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0){if(xSemaphoreGive(myCountingSem01Handle)!=pdTRUE){printf("NO1\r\n");}else{printf("YES1\r\n");}}}if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0){osDelay(20);if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0){if(xSemaphoreTake(myCountingSem01Handle,0)!=pdTRUE){printf("NO2\r\n");}else{printf("YES2\r\n");}}}}/* USER CODE END StartDefaultTask */
}/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{/* USER CODE BEGIN StartTask02 *//* Infinite loop */for(;;){}/* USER CODE END StartTask02 */
}/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the Task3 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{/* USER CODE BEGIN StartTask03 *//* Infinite loop */for(;;){printf("possess %d people\r\n",(uint16_t)uxSemaphoreGetCount(myCountingSem01Handle));osDelay(3000);}/* USER CODE END StartTask03 */
}
?因為用了函數
myCountingSem01Handle = osSemaphoreCreate(osSemaphore(myCountingSem01), 10);
默認當前計數值為滿值。如果設置為0,使用下面的函數:
myCountingSem01Handle=xSemaphoreCreateCounting(10,0);
現象:通過按鍵一和二實現記錄人數,并串口打印了當前人數。