Как и при чтении из очереди, задача может находиться в блокированном состоянии, ожидая возможность записи в очередь. Это происходит, когда очередь полностью заполнена и в ней нет свободного места для записи нового элемента данных.
До тех пор, пока какая-либо другая задача не прочитает данные из очереди, задача, которая пишет в очередь, будет «ожидать», находясь в блокированном состоянии.
В одну очередь могут писать сразу несколько задач, поэтому возможна ситуация, когда несколько задач находятся в блокированном состоянии, ожидая завершения операции записи в одну очередь. Когда в очереди появится свободное место, получит управление задача с наивысшим приоритетом. В случае если запись в очередь ожидали равноприоритетные задачи, управление получит та, которая находилась в блокированном состоянии дольше остальных.
Работа с очередями
Теперь целесообразно рассмотреть конкретные API-функции FreeRTOS для работы с очередями. Все API-функции для работы с очередями используют переменную типа xQueueHandle (QueueHandle_t в FreeRTOS 10.1.1), которая служит в качестве дескриптора (идентификатора) конкретной очереди из множества всех очередей в программе.
Создание очереди
Очередь должна быть явно создана перед первым ее использованием. API-функция
xQueueCreate() служит для создания очереди, она возвращает переменную типа
xQueueHandle в случае успешного создания очереди:
1. xQueueHandle xQueueCreate(unsigned portBASE_TYPE uxQueueLength,
2. unsigned portBASE_TYPE uxItemSize);
Ее параметры и возвращаемое значение:
· uxQueueLength — определяет размер очереди, то есть максимальное количество элементов, которые может хранить очередь.
· uxItemSize — задает размер одного элемента очереди в байтах, его легко получить с помощью оператора sizeof().
· Возвращаемое значение — дескриптор очереди. Равен NULL, если очередь не создана по причине отсутствия достаточного объема памяти в куче FreeRTOS. Ненулевое значение свидетельствует об успешном создании очереди, в этом случае оно должно быть сохранено в переменной типа xQueueHandle для дальнейшего обращения к очереди.
Запись элемента в очередь
Для записи элемента в конец очереди используется API - функция xQueueSendToBack(), для записи элемента в начало очереди — xQueueSendToFront().
Так как запись в конец очереди применяется гораздо чаще, чем в начало, то вызов API-функции xQueueSend() эквивалентен вызову xQueueSendToBack(). Прототипы у всех трех API-функций одинаковы:
1. portBASE_TYPE xQueueSendXXXX (xQueueHandle xQueue,
2. const void * pvItemToQueue,
3. portTickType xTicksToWait);
Назначение параметров и возвращаемое значение:
· xQueue — дескриптор очереди, в которую будет записан элемент. Дескриптор очереди может быть получен при ее создании API-функцией xQueueCreate().
· pvItemToQueue — указатель на элемент, который будет записан в очередь. Размер элемента зафиксирован при создании очереди, так что для побайтового копирования элемента достаточно иметь указатель на него.
· xTicksToWait — максимальное количество квантов времени, в течение которого задача может пребывать в блокированном состоянии, если очередь полна и записать новый элемент невозможно. Установка xTicksToWait равным константе portMAX_DELAY приведет к тому, что выхода из блокированного состояния по истечении тайм-аута не будет. Задача будет сколь угодно долго «ожидать» возможности записать элемент в очередь, пока такая возможность не появится. При этом макроопределение INCLUDE_vTaskSuspend в файле FreeRTOSConfig.h должно быть равно «1».
· Возвращаемое значение — может возвращать 2 значения:
o pdPASS — означает, что данные успешно записаны в очередь. Если определена продолжительность тайм-аута (параметр xTicksToWait не равен «0»), то возврат значения pdPASS говорит о том, что свободное место в очереди появилось до истечения тайм-аута и элемент был помещен в очередь.
o errQUEUE_FULL — означает, что данные не записаны в очередь, так как очередь заполнена. Если определена продолжительность тайм-аута (параметр xTicksToWait не равен «0» или portMAX_DELAY), то возврат значения errQUEUE_FULL говорит о том, что тайм-аут завершен и свободное место в очереди так и не появилось.
Следует отметить, что API-функции xQueueSendToBack() и xQueueSendToFront() нельзя вызывать из тела обработчика прерывания. Для этой цели служат специальные версии этих функций: xQueueSendToBackFromISR() и xQueueSendToFrontFromISR() соответственно.