Старт ARM. RTOS часть 3-ая. Очереди.

Всем привет продолжаем мучать 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 целиком