Kolejka jest wykorzystywana do wymiany informacji pomiędzy zadaniami. Można ją wykorzystać do przysyłania wiadomości pomiędzy zadaniami czy przerwaniami a zadaniami. Najczęściej są one wykorzystywane jako bufory FIFO.
Na zdefiniowaną kolejkę składa się jej długość oraz rozmiar pojedynczego elementu jaki może zostać wpisany. Każdy element jaki jest umieszczany w kolejce jest kopią danych źródłowych. Oznacza to, że zadania nie mogą bezpośrednio uzyskać dostępu do pamięci. Mechanizm kolejek posiada obsługę zagadnień związanych z wzajemnymi wykluczeniami.
Stworzenie kolejki pozwalającej na wymianę informacji pomiędzy poszczególnymi zadaniami można wykonać następującą funkcją:
- osMessageQDef(name, queue_sz, type);
Tworzy atrybuty wiadomości, do parametrów wprowadza się nazwę kolejki, jej wielkość, oraz typ danych pojedynczego elementu.
- osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id);
Funkcja pozwala na uruchomienie kolejki. W argumentach podawana jest nazwa kolejki oraz wątek odpowiedzialny za obsługę danych. Jeśli nie ma żadnego wątku zdefiniowanego to w argumencie podawana jest wartość NULL.
Teraz tworzę dwa zadania które będą wymiały dane między sobą oraz jedno wykonujące inne zadanie:
- osThreadDef(defaultTask, reciveDataQue, osPriorityNormal, 0, 128);
- defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
- osThreadDef(myTask02, sendDataToQue, osPriorityIdle, 0, 128);
- myTask02Handle = osThreadCreate(osThread(myTask02), NULL);
- osThreadDef(myTask03, StartTask03, osPriorityIdle, 0, 128);
- Task03Handle = osThreadCreate(osThread(myTask03), NULL);
- osMessageQDef(myQueue01, 32, uint32_t);
- queueHandle = osMessageCreate(osMessageQ(myQueue01), NULL);
Funkcja wyświetlająca informacje na ekranie:
- void StartTask03(void const * argument)
- {
- for(;;)
- {
- ROCKTECH_DisplayString(120, 230, (uint8_t *)" ", LEFT_MODE);
- ROCKTECH_DisplayString(120, 200, (uint8_t *)"Task3", LEFT_MODE);
- HAL_Delay(2000);
- ROCKTECH_DisplayString(120, 200, (uint8_t *)" ", LEFT_MODE);
- ROCKTECH_DisplayString(120, 230, (uint8_t *)"Task2", LEFT_MODE);
- HAL_Delay(2000);
- }
- }
Teraz funkcje wymieniające się danymi. Najpierw wprowadzanie danych do kolejki:
- void sendDataToQue(void const * argument)
- {
- char displayBuffer[15];
- for(;;)
- {
- newData.exchangeData++;
- sprintf(displayBuffer, "Que write = %lu", newData.exchangeData);
- ROCKTECH_DisplayString(120, 100, (uint8_t *)displayBuffer, LEFT_MODE);
- osMessagePut(queueHandle, newData.exchangeData, 500);
- osDelay(100);
- }
- }
Odczytywanie danych z kolejki:
- void reciveDataQue(void const * argument)
- {
- osEvent evt;
- for(;;)
- {
- char displayBuffer[15];
- evt = osMessageGet(queueHandle, 1000);
- if(evt.status == osEventMessage)
- {
- sprintf(displayBuffer, "Data rec: = %lu", evt.value.p);
- TFT_DisplayString(120, 50, (uint8_t *)buffer, LEFT_MODE);
- }
- else
- {
- TFT_DisplayString(120, 50, (uint8_t *)"Failed", LEFT_MODE);
- }
- osDelay(1);
- }
- }
Kolejka jest tworzona przez wywołanie funkcji:
- osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id)
Tutaj podobnie jak poprzednio możliwa jest wymiana informacji pomiędzy wątkami. Różnica polega na tym, że wcześniejszy przykład może jedynie przesłać wskaźnik lub 32 bitową wartość. W tym przypadku wykorzystywane są przygotowane bloki danych do których przekazywany jest wskaźnik. Dane przechowywane są w jednym bloku, natomiast wskaźnik jest przesyłany pomiędzy wątkami.
Tworzenie kolejki wygląda następująco:
- osMailQDef(mailQueue, QUEUE_SIZE, dataStructure_t);
- mailQueue = osMailCreate(osMailQ(mailQueue), NULL);
Dane do poszczególnych zadań przechowuję w strukturze opisanej w poprzedniej poście (FreeRtos - Zadania):
- typedef struct taskStruct{
- char taskName[10];
- taskFuncPointer taskFunct;
- osPriority priority;
- uint8_t instances;
- uint16_t stackSize;
- uint16_t screenPosi_y;
- uint16_t delayTime;
- }taskStruct_t;
Wobec tego stworzone zadania będą wyglądały następująco:
- osThreadDef(taskNorm1, task1_Definition.taskFunct, task1_Definition.priority, task1_Definition.instances, task1_Definition.stackSize);
- Task01Handle = osThreadCreate(osThread(taskNorm1), (void*)&task1_Definition);
- osThreadDef(taskNorm2, task2_Definition.taskFunct, task2_Definition.priority, task2_Definition.instances, task2_Definition.stackSize);
- Task02Handle = osThreadCreate(osThread(taskNorm2), (void*)&task2_Definition);
- osThreadDef(taskNorm3, task3_Definition.taskFunct, task3_Definition.priority, task3_Definition.instances, task3_Definition.stackSize);
- Task03Handle = osThreadCreate(osThread(taskNorm3), (void*)&task3_Definition);
- osThreadDef(taskNorm4, task4_Definition.taskFunct, task4_Definition.priority, task4_Definition.instances, task4_Definition.stackSize);
- Task04Handle = osThreadCreate(osThread(taskNorm4), (void*)&task4_Definition);
- osThreadDef(taskNorm5, task5_Definition.taskFunct, task5_Definition.priority, task5_Definition.instances, task5_Definition.stackSize);
- Task05Handle = osThreadCreate(osThread(taskNorm5), (void*)&task5_Definition);
Do obsługi zdarzeń wykorzystuje dwie funkcje:
- void TaskPut(void const * argument)
- {
- volatile taskStruct_t *taskStructPtr;
- taskStructPtr = (taskStruct_t*) argument;
- uint8_t i = 0;
- dataStructure_t *dataStructPointer;
- for(;;)
- {
- dataStructPointer = osMailAlloc(mailQueue, 1000);
- if(i==0)
- {
- dataStructPointer->screenPosition = 0;
- dataStructPointer->countSystemTick = 0;
- dataStructPointer->someCounter = 0;
- i++;
- }
- dataStructPointer->someCounter += 1;
- dataStructPointer->countSystemTick = osKernelSysTick();
- dataStructPointer->screenPosition = taskStructPtr->screenPosi_y;
- sprintf(dataStructPointer->displayDataBuffer, "%s %d", taskStructPtr->taskName, osThreadGetPriority(NULL));
- osMailPut(mailQueue, dataStructPointer);
- }
- }
Funkcja TaskPut wprowadza dane do kolejki na początku alokowane jest blok danych przechowujący strukturę. Drugi parametr jest to czas oczekiwania w milisekundach. W przypadku jego pominięcia timeout nie jest wykorzystywany. Dalej wprowadzane są dane do elementów struktury. Na końcu wprowadzane są dane do kolejki.
- void TaskStringOut(void const * argument)
- {
- osEvent event;
- dataStructure_t *dataStructPointer;
- ROCKTECH_SetTextColor(LCD_COLOR_BLUE);
- for(;;)
- {
- char displayData[40];
- event = osMailGet(mailQueue, osWaitForever);
- if (event.status == osEventMail)
- {
- dataStructPointer = event.value.p;
- sprintf(displayData,"%s %lu %lu",
- dataStructPointer->displayDataBuffer,
- dataStructPointer->countSystemTick,
- dataStructPointer->someCounter);
- ROCKTECH_DisplayString(20, dataStructPointer->screenPosition, (uint8_t *)displayData, LEFT_MODE);
- }
- }
- }
Bibliografia:
[1] STM32 - Free RTOS dla dociekliwych
[2] Wbudowane systemy czasy rzeczywistego