Работа с очередями FreeRTOS в ESP32 с помощью ESP-IDF


В данной статье мы рассмотрим создание очередей FreeRTOS на ESP32 с помощью ESP-IDF. Ранее мы изучили создание задач FreeRTOS на ESP32 с помощью ESP-IDF. Однако создание отдельных задач недостаточно для полноценного приложения на основе RTOS, поскольку эти независимые задачи представляют собой небольшие программы, имеющие собственный стек, память и задачи выполнения. Следовательно, нам необходим механизм для взаимодействия этих независимых задач друг с другом, чтобы они могли обмениваться данными.

Ядро FreeRTOS, как и другие современные ядра RTOS, предлагает механизм для передачи данных между задачами. Для этой цели используются так называемые очереди сообщений. Они служат фундаментальным элементом для синхронизации задач FreeRTOS и методов связи. Они используются для отправки и получения сообщений между задачами.

Работа с очередями FreeRTOS в ESP32 с помощью ESP-IDF

Также на нашем сайте вы можете прочитать статью про работу с FreeRTOS и памятью в ESP32-S3 с помощью ESP-IDF - возможно, некоторые аспекты в ней рассмотрены более понятным для вас языком.

Прежде чем продолжить, убедитесь, что у вас установлена ​​последняя версия VS Code и настроено расширение ESP-IDF:

Также на нашем сайте вы можете прочитать статью про начало работы с ESP32 с использованием ESP-IDF.

Введение в очереди FreeRTOS

Очередь сообщений — это тип буфера FIFO, в котором хранятся элементы данных фиксированного размера. Кроме того, после инициализации очереди количество элементов, которые она может содержать, фиксировано. Как правило, задачи считывают данные из начала буфера и записывают их в конец буфера. Но возможна и запись с начала. Буфер может использоваться несколькими записывающими и читающими процессами одновременно.

Однако буфер может использоваться только одной задачей записи или чтения одновременно, а другие процессы блокируются. В результате блокировка возможна как для записи, так и для чтения из буфера.

Например, задача 1 отправляет данные в буфер. Задача 2 считывает эти данные из буфера и удаляет их значение из буфера. Каждый блок данных в очереди FreeRTOS может иметь любой тип данных или размер.

Блокировка задач при чтении из очереди

Блокировка при чтении в задаче FreeRTOS вероятна в следующих ситуациях:

  1. Если  несколько задач  хотят прочитать данные из очереди сообщений, то задача с наивысшим приоритетом читает данные первой, а задача с наименьшим приоритетом — в конце. При этом остальные задачи остаются заблокированными. Мы также можем установить максимальное время блокировки задачи при отправке запроса на чтение. Однако различные задачи FreeRTOS могут иметь различное время блокировки.
  2. Другой возможный случай — когда очередь пуста. В этом случае все запросы на чтение переходят в блокирующее состояние. Как только данные становятся доступны из очереди сообщений  (когда другая задача помещает данные в очередь готовности), все читатели переводятся в состояние готовности, и задача с наивысшим приоритетом получает возможность читать из очереди первой.

Блокировка задач при записи в очередь

Подобно чтению из очереди, задача записи также может дополнительно задать время блокировки при записи в очередь. Например, задача записи хочет записать данные в уже заполненную очередь. В этом случае время блокировки — это максимальное время, в течение которого задача должна находиться в заблокированном состоянии, ожидая освобождения места в очереди.

В одной очереди может находиться несколько задач записи. Поэтому существует вероятность того, что в уже заполненной очереди будет заблокировано более одной задачи, ожидающей завершения операции записи. В этом случае, когда освободится место в очереди, будет разблокирована только одна задача.

Разблокированной всегда будет задача с наивысшим приоритетом, ожидавшая освобождения места. Если заблокированные задачи имеют одинаковый приоритет, то разблокированной будет задача, которая дольше всего ожидала освобождения места.

Данная симуляция демонстрирует последовательность операций чтения/записи:

Последовательность операций чтения/записи в FreeRTOS

Пример кода для работы с очередью FreeRTOS в ESP32 с помощью ESP-IDF 

Давайте поработаем над кодом, который мы использовали ранее при создании двух задач, и интегрируем в него Queue (очередь). Прежде чем продолжить, обратитесь к статье «Задачи FreeRTOS в ESP32 с ESP-IDF». Создание задач уже обсуждалось в данной статье. Здесь мы покажем, как использовать очереди FreeRTOS.

Чтобы использовать функциональные возможности библиотеки Queue, предоставляемой FreeRTOS, сначала подключим её заголовочный файл:

Далее создайте обработчик очереди, как показано ниже:

Первая задача (функция)

Затем мы определим функцию Demo_Task. Это позволит нам отправлять данные в буфер.

Во-первых, мы создадим массив символов для хранения данных. Он называется 'txBuffer'.

Создание очереди

Далее мы создадим очередь с помощью функции xQueueCreate(). Первый аргумент — это количество символов в буфере очереди, а второй параметр — размер каждого символа в буфере. В нашем случае это выглядит следующим образом:

Поскольку размер txBuffer установлен на 50, каждый блок будет иметь ограничение в 50 символов.

Кроме того, мы добавим условное выражение для проверки того, успешно ли создана очередь.

Далее мы определяем строку 'Hello from Demo_Task 1', которую хотим отправить в очередь, используя функцию sprintf().

Запись данных в очередь

Для отправки этого буфера в очередь мы будем использовать функцию xQueueSend(). Первый аргумент этой функции — это используемая очередь. В нашем случае это 'queue'. Второй аргумент — это указатель на отправляемые данные. В нашем случае это '(void*)txBuffer'. Третий аргумент — это время блокировки. Поскольку мы не хотим добавлять блоки, мы установим его равным нулю.

Добавим ещё несколько строк в txBuffer и отправим их в очередь следующим образом:

Вторая функция задачи

Во второй функции задачи, Demo_Task2(), мы получим данные из буфера очереди.

Во-первых, мы создадим массив символов для хранения данных, которые будут получены из буфера очереди. Он называется 'rxBuffer'.

Чтение данных из очереди

Внутри непрерывного цикла while мы будем использовать функцию xQueueReceive() для постоянного чтения буфера. Ее первый аргумент — это очередь, которую мы будем проверять в функции xQueueSend(). В нашем случае это очередь. Второй аргумент — это указатель на данные, которые мы получаем. В нашем случае это '&(rxBuffer)'. Третий аргумент — это время блокировки. Мы будем добавлять время блокировки при получении данных из буфера очереди, чтобы не потерять данные.

Кроме того, мы добавим оператор print для проверки данных, полученных через последовательный монитор.

Полный код

Это полный код, который мы используем, и в котором мы объяснили части, относящиеся к очереди FreeRTOS.

Демонстрация

Для прошивки микросхемы введите следующую команду в последовательном терминале. Не забудьте заменить COM-порт на тот, через который подключена ваша плата.

После успешной прошивки кода этот вывод отображается в последовательном терминале. Как видно из вывода монитора последовательного порта, первая задача записывает три строки в очередь, а вторая задача считывает их, как только появляется доступная запись в очереди.

Демонстрация в VS Code работы с очередями FreeRTOS в ESP32 с помощью ESP-IDF

Таким образом, мы можем читать и записывать данные в очереди, используя FreeRTOS, и осуществлять межзадачное взаимодействие для обмена данными между независимыми задачами. Очереди обеспечивают безопасный и эффективный способ обмена данными между задачами.

Вам также может быть интересно прочитать:

(Проголосуй первым!)
Загрузка...
2 просмотров

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *