Всем привет продолжаем мучать stm32f4(stm32f429i-disco) и FreeRTOS, сегодня речь пойдет об очередях и зачем они нужны во FreeRTOS. И так преступим. Во первых, очередь – структура данных с организацией доступа к элементам «первый пришёл — первый вышел» (FIFO, First In — First Out). Добавление элемента (принято обозначать словом enqueue — добавить в очередь) возможно лишь в конец очереди, взятие — только из начала очереди (что принято называть словом dequeue — убрать из очереди), при этом выбранный элемент из очереди удаляется. Во вторых, рассмотрим такую ситуацию, у нас есть переменная которая хранит массив объектов, и вдруг мы начали обращаться, с кажем из разных задач которые получают процессорное время, задача первая (будем абстрагироваться: D) ) отдает в эту переменную яблоки, а вторая задача отдает груши, если тех и тех много, происходит формирование гибридов грушо-яблоки. Или иной пример передавали «Неllo world!» одной задачей, а второй задачей передавали «Hi Mars!», тогда в итоги у нас может получиться «HellHi Mars», или что-нибудь похожее на данную строку. Да кончено в случае если вы используете вытесняющую(гибридную) многозадачность, а не кооперативную, в кооперативной можно обойтись и без очередей, так как там вы сами завершаете выполнение задачи и отдает управление планировщику. Использование очередей позволяет избежать некорректного обмена данных между задачами.
Что ж перейдем к примеру.
... UART_HandleTypeDef huart5; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_UART5_Init(void); volatile xQueueHandle xQueue; void vSenderTask(void *pvParameters){ char luValue[20] = {0x00}; portBASE_TYPE xStatus; strcpy(luValue, (char *)pvParameters); HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_RESET); for(;;){ xStatus = xQueueSendToBack(xQueue, luValue, 0); if(xStatus != pdPASS){ HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_SET); } taskYIELD(); } } void vRecieverTask(void *pvParameters){ char luValue[20] = {0x00}; portBASE_TYPE xStatus; HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_RESET); for(;;){ if(uxQueueMessagesWaiting(xQueue) != 0){ HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_RESET); } else{ HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET); } xStatus = xQueueReceive(xQueue, luValue, 100/portTICK_RATE_MS); if(xStatus == pdPASS){ HAL_UART_Transmit(&huart5, (uint8_t *)luValue, 20, 20); } } vTaskDelete(NULL); } void ApplicationIdleHook(void){ } int main(void) { xQueue = xQueueCreate(5, 20 * sizeof(char)); HAL_Init(); SystemClock_Config(); HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); MX_GPIO_Init(); MX_UART5_Init(); if(xQueue != NULL){ xTaskCreate(vSenderTask, (signed char *)"Sender1", configMINIMAL_STACK_SIZE + 256, (void*) "mcu1.by\n\r", 1, NULL); xTaskCreate(vSenderTask, (signed char *)"Sender2", configMINIMAL_STACK_SIZE + 256, (void*) "mcu2.by\n\r", 1, NULL); xTaskCreate(vSenderTask, (signed char *)"Sender3", configMINIMAL_STACK_SIZE + 256, (void*) "mcu3.by\n\r", 1, NULL); xTaskCreate(vRecieverTask, (signed char *)"Receiver", configMINIMAL_STACK_SIZE + 256, NULL, 2, NULL); } vTaskStartScheduler(); for(;;); } ...
Вот таким нехитрым способом можно использовать очереди во FreeRTOS-е и красиво организовать обмен сообщениями между задачами. Полный example прилагаю. Всем пока! В следующий раз будет разбирать семафоры. 🙂
Firmware целиком