portMAX_DELAY), то возврат значения
errQUEUE_FULL говорит о том, что
тайм-аут завершен и никакая другая за-
дача или прерывание не записали эле-
мент в очередь.
Как и в случае с записью элемента
в очередь, API-функции xQueueReceive()
и xQueuePeek() нельзя вызывать из тела об-
работчика прерывания. Для этих целей слу-
жит API-функция xQueueReceiveFromISR(),
которая будет описана в следующих публи-
кациях.
Состояние очереди
Получить текущее количество записанных
элементов в очереди можно с помощью API-
функции uxQueueMessagesWaiting():
unsigned portBASE_TYPE uxQueueMessagesWaiting(xQueueHan
dle xQueue);
Назначение параметров и возвращаемое
значение:
xQueue
•
— дескриптор очереди, состояние
которой необходимо получить. Дескриптор
очереди может быть получен при ее созда-
нии API-функцией xQueueCreate().
Возвращаемое значение — количество эле-
•
ментов, которые хранит очередь в момент
вызова uxQueueMessagesWaiting(). Если
очередь пуста, то возвращаемым значени-
ем будет «0».
Как и в случаях с чтением и запи-
сью элемента в очередь, API-функцию
uxQueueMessagesWaiting() нельзя вызывать
из тела обработчика прерывания. Для этих
целей служит API-функция uxQueueMessage
sWaitingFromISR().
Удаление очереди
Если в программе использована схема рас-
пределения памяти, допускающая удаление
задач [1, КиТ № 5], то полезной окажется
возможность удалить и очередь, которая ис-
пользовалась для взаимодействия с удален-
ной задачей. Для удаления очереди служит
API-функция vQueueDelete(). Ее прототип:
void vQueueDelete(xQueueHandle xQueue);
Единственный аргумент — это дескриптор
удаляемой очереди. При успешном заверше-
нии API-функция vQueueDelete() освободит
всю память, выделенную как для размеще-
ния служебной структуры управления очере-
дью, так и для размещения самих элементов
очереди.
Рассмотреть процесс обмена сообщениями
между несколькими задачами можно на при-
мере учебной программы № 2, в которой реа-
лизована очередь для хранения элементов
типа long. Данные в очередь записывают две
задачи-передатчика, а считывает данные одна
задача-приемник.
#include
#include
#include
#include “FreeRTOS.h”
#include “task.h”
#include “queue.h”
/* Объявить переменную-дескриптор очереди.
* Эта переменная будет использоваться
* для работы с очередью из тела всех трех задач. */
xQueueHandle xQueue;
/*------------------------------------------------------------------------*/
/* Функция, реализующая задачи-передатчики */
void vSenderTask(void *pvParameters) {
/* Переменная, которая будет хранить значение, передаваемое
* в очередь */
long
lValueToSend;
/* Переменная, которая будет хранить результат выполнения
* xQueueSendToBack() */
portBASE_TYPE
xStatus;
/* Будет создано несколько экземпляров задачи. В качестве
* параметра задачи выступает число, которое задача будет
* записывать в очередь */
lValueToSend = (long) pvParameters;
/* Бесконечный цикл */
for (;;) {
/* Записать число в конец очереди.
* 1-й параметр — дескриптор очереди, в которую будет
* производиться запись, очередь создана до запуска
* планировщика, и ее дескриптор сохранен в глобальной \
* переменной xQueue.
* 2-й параметр — указатель на переменную, которая будет
* записана в очередь, в данном случае — lValueToSend.
* 3-й параметр — продолжительность тайм-аута.
* В данном случае задана равной 0, что соответствует
* отсутствию времени ожидания, если очередь полна.
* Однако из-за того, что задача-приемник сообщений имеет
* более высокий приоритет, чем задачи-передатчики,
* в очереди не может находиться более одного элемента.
* Таким образом, запись нового элемента будет всегда
* возможна. */
xStatus = xQueueSendToBack(xQueue, &lValueToSend, 0);
if (xStatus != pdPASS) {
/* Если попытка записи не была успешной —
* индицировать ошибку. */
puts(“Could not send to the queue.\r\n”);
}
/* Сделать принудительный вызов планировщика, позволив,
* таким образом, выполняться другой задаче-передатчику.
* Переключение на другую задачу произойдет быстрее,
* чем окончится текущий квант времени. */
taskYIELD();
}
}
/*------------------------------------------------------------------------*/
/* Функция, реализующая задачу-приемник */
void vReceiverTask(void *pvParameters) {
/* Переменная, которая будет хранить значение, полученное
* из очереди */
long
lReceivedValue;
/* Переменная, которая будет хранить результат выполнения
* xQueueReceive() */
portBASE_TYPE
xStatus;
/* Бесконечный цикл */
for (;;) {
/* Индицировать состояние, когда очередь пуста */
if (uxQueueMessagesWaiting(xQueue) != 0) {
puts(“Queue should have been empty!\r\n”);
}
/* Прочитать число из начала очереди.
* 1-й параметр — дескриптор очереди, из которой будет
* происходить чтение, очередь создана до запуска
* планировщика, и ее дескриптор сохранен в глобальной
*
переменной
xQueue.
* 2-й параметр — указатель на буфер, в который будет
* помещено число из очереди.
* В данном случае — указатель на переменную lReceivedValue.
* 3-й параметр — продолжительность тайм-аута, в течение
*
которого
задача
будет находиться в блокированном
* состоянии, пока очередь пуста. В данном случае
* макроопределение portTICK_RATE_MS используется
* для преобразования времени 100 мс в количество
*
системных
квантов.
*/
xStatus = xQueueReceive(xQueue, &lReceivedValue, 100 /
portTICK_RATE_MS);
if (xStatus == pdPASS) {
/* Число успешно принято, вывести его на экран */
printf(“Received
=
%ld\r\n”,
lReceivedValue);
|