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