- Как работает RTOS?
- Часто используемые термины в RTOS
- Установка библиотеки Arduino FreeRTOS
- Принципиальная электрическая схема
- Пример Arduino FreeRTOS - создание задач FreeRTOS в Arduino IDE
- Реализация задачи FreeRTOS в среде Arduino IDE
ОС, присутствующая во встроенных устройствах, называется RTOS (операционная система реального времени). Во встроенных устройствах критически важны задачи в реальном времени, где очень важную роль играет время. Задачи в реальном времени детерминированы по времени, что означает, что время отклика на любое событие всегда постоянно, поэтому можно гарантировать, что любое конкретное событие произойдет в фиксированное время. ОСРВ предназначена для запуска приложений с очень точной синхронизацией и высокой степенью надежности. RTOS также помогает в многозадачной работе с одним ядром.
Мы уже рассмотрели руководство по использованию ОСРВ во встроенных системах, где вы можете узнать больше об ОСРВ, различиях между ОС общего назначения и ОСРВ, различных типах ОСРВ и т. Д.
В этом руководстве мы начнем с FreeRTOS. FreeRTOS - это класс ОСРВ для встроенных устройств, который достаточно мал, чтобы работать на 8/16-битных микроконтроллерах, хотя его использование не ограничивается этими микроконтроллерами. Это полностью открытый исходный код, и его код доступен на github. Если мы знаем некоторые базовые концепции RTOS, то FreeRTOS очень легко использовать, потому что он имеет хорошо документированные API, которые можно напрямую использовать в коде, не зная внутренней части кода. Полную документацию FreeRTOS можно найти здесь.
Поскольку FreeRTOS может работать на 8-битном MCU, он также может работать на плате Arduino Uno. Нам нужно просто загрузить библиотеку FreeRTOS, а затем начать реализацию кода с помощью API. Это руководство предназначено для начинающих, ниже приведены темы, которые мы рассмотрим в этом руководстве Arduino FreeRTOS:
- Как работает RTOS
- Некоторые часто используемые термины в RTOS
- Установка FreeRTOS в Arduino IDE
- Как создать задачи FreeRTOS на примере
Как работает RTOS?
Прежде чем приступить к работе с RTOS, давайте посмотрим, что такое Task. Задача - это фрагмент кода, выполнение которого ЦП может запланировать. Итак, если вы хотите выполнить какую-то задачу, ее следует запланировать с использованием задержки ядра или прерываний. Эта работа выполняется планировщиком, присутствующим в ядре. В одноядерном процессоре планировщик помогает задачам выполняться в определенном временном интервале, но кажется, что разные задачи выполняются одновременно. Каждая задача выполняется в соответствии с присвоенным ей приоритетом.
Теперь давайте посмотрим, что произойдет в ядре RTOS, если мы хотим создать задачу для мигания светодиода с интервалом в одну секунду и поставить эту задачу на самый высокий приоритет.
Помимо светодиодной задачи, будет еще одна задача, которая создается ядром, она известна как незанятая задача.. Неактивная задача создается, когда нет задач, доступных для выполнения. Эта задача всегда выполняется с самым низким приоритетом, то есть с нулевым приоритетом. Если мы проанализируем график времени, приведенный выше, можно увидеть, что выполнение начинается с задачи светодиода, и она выполняется в течение определенного времени, а затем в течение оставшегося времени задача бездействия выполняется до тех пор, пока не произойдет прерывание по тикам. Затем ядро решает, какая задача должна быть выполнена, в соответствии с приоритетом задачи и общим истекшим временем светодиодной задачи. Когда истекает 1 секунда, ядро снова выбирает задачу для выполнения, потому что она имеет более высокий приоритет, чем задача ожидания, мы также можем сказать, что задача LED вытесняет неактивную задачу. Если имеется более двух задач с одинаковым приоритетом, они будут выполняться циклически в течение определенного времени.
Под диаграммой состояний показано переключение неработающей задачи в рабочее состояние.
Каждая вновь созданная задача переходит в состояние готовности (часть неработающего состояния). Если созданная задача (Task1) имеет наивысший приоритет по сравнению с другими задачами, она перейдет в состояние выполнения. Если эта запущенная задача вытесняется другой задачей, она снова возвращается в состояние готовности. В противном случае, если задача 1 заблокирована с помощью API блокировки, ЦП не будет взаимодействовать с этой задачей до истечения времени ожидания, определенного пользователем.
Если Task1 приостанавливается в рабочем состоянии с помощью Suspend API, тогда Task1 переходит в состояние Suspended и снова становится недоступным для планировщика. Если вы возобновите Task1 в приостановленном состоянии, он вернется в состояние готовности, как вы можете видеть на блок-схеме.
Это основная идея того, как задачи запускаются и меняют свое состояние. В этом руководстве мы реализуем две задачи в Arduino Uno с помощью FreeRTOS API.
Часто используемые термины в RTOS
1. Задача: это часть кода, выполнение которой может быть запланировано на ЦП.
2. Планировщик: он отвечает за выбор задачи из списка состояния готовности в состояние выполнения. Планировщики часто реализуются таким образом, что они загружают все ресурсы компьютера (как при балансировке нагрузки).
3. Вытеснение: это действие по временному прерыванию уже выполняющейся задачи с намерением вывести ее из рабочего состояния без ее участия.
4. Переключение контекста: при приоритетном приоритетном прерывании планировщик сравнивает приоритет выполняемых задач с приоритетом готового списка задач при каждом прерывании от Systick . Если в списке есть задача, приоритет которой выше, чем у выполняющейся задачи, происходит переключение контекста. По сути, в этом процессе содержимое различных задач сохраняется в соответствующей памяти стека.
5. Типы политик планирования:
- Упреждающее планирование: при этом типе планирования задачи выполняются с равным временным интервалом без учета приоритетов.
- Вытеснение на основе приоритета : сначала будет запущена задача с высоким приоритетом.
- Кооперативное планирование: переключение контекста будет происходить только при взаимодействии запущенных задач. Задача будет выполняться непрерывно, пока не будет вызван выход задачи.
6. Объекты ядра: для сигнализации задачи о выполнении некоторой работы используется процесс синхронизации. Для выполнения этого процесса используются объекты ядра. Некоторые объекты ядра - это события, семафоры, очереди, мьютексы, почтовые ящики и т. Д. Мы увидим, как использовать эти объекты в следующих руководствах.
Из приведенного выше обсуждения у нас есть некоторые основные идеи о концепции RTOS, и теперь мы можем реализовать проект FreeRTOS в Arduino. Итак, приступим к установке библиотек FreeRTOS в Arduino IDE.
Установка библиотеки Arduino FreeRTOS
1. Откройте Arduino IDE и перейдите в Sketch -> Include Library -> Manage Libraries . Найдите FreeRTOS и установите библиотеку, как показано ниже.
Вы можете скачать библиотеку с github и добавить файл.zip в Sketch-> Включить библиотеку -> Добавить файл .zip .
Теперь перезапустите IDE Arduino. Эта библиотека предоставляет некоторый пример кода, который также можно найти в Файл -> Примеры -> FreeRTOS, как показано ниже.
Здесь мы напишем код с нуля, чтобы понять, как работает, позже вы можете проверить примеры кода и использовать их.
Принципиальная электрическая схема
Ниже приведена принципиальная схема для создания задачи «Мигающий светодиод» с использованием FreeRTOS на Arduino:
Пример Arduino FreeRTOS - создание задач FreeRTOS в Arduino IDE
Давайте посмотрим на базовую структуру для написания проекта FreeRTOS.
1. Сначала включите заголовочный файл Arduino FreeRTOS как
#включают
2. Предоставьте для исполнения прототип всех функций, которые вы пишете, в виде
void Task1 (void * pvParameters); void Task2 (void * pvParameters); .. ….
3. Теперь в функции void setup () создайте задачи и запустите планировщик задач.
Для создания задачи API xTaskCreate () вызывается в функции настройки с определенными параметрами / аргументами.
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
Есть 6 аргументов, которые нужно передать при создании любой задачи. Посмотрим, что это за аргументы
- pvTaskCode: это просто указатель на функцию, которая реализует задачу (фактически, просто имя функции).
- pcName: описательное имя задачи. Это не используется FreeRTOS. Он включен исключительно в целях отладки.
- usStackDepth: Каждая задача имеет свой уникальный стек, который выделяется ядром для задачи при ее создании. Значение указывает количество слов, которые может содержать стек, а не количество байтов. Например, если стек имеет ширину 32 бита и usStackDepth передается как 100, то в ОЗУ будет выделено 400 байт пространства стека (100 * 4 байта). Используйте это с умом, потому что Arduino Uno имеет всего 2 КБ ОЗУ.
- pvParameters: входной параметр задачи (может быть NULL).
- uxPriority: приоритет задачи (0 - самый низкий приоритет).
- pxCreatedTask: его можно использовать для передачи дескриптора создаваемой задачи. Затем этот дескриптор можно использовать для ссылки на задачу в вызовах API, которые, например, изменяют приоритет задачи или удаляют задачу (может иметь значение NULL).
Пример создания задачи
xTaskCreate (задача1, «задача1», 128, NULL, 1, NULL); xTaskCreate (задача2, «задача2», 128, NULL, 2, NULL);
Здесь Task2 имеет более высокий приоритет и, следовательно, выполняется первым.
4. После создания задачи запустите планировщик в пустой настройке с помощью vTaskStartScheduler (); API.
5. Функция Void loop () останется пустой, поскольку мы не хотим запускать какую-либо задачу вручную и бесконечно. Потому что выполнение задачи теперь обрабатывается планировщиком.
6. Теперь мы должны реализовать функции задач и написать логику, которую вы хотите выполнять внутри этих функций. Имя функции должно совпадать с первым аргументом API xTaskCreate () .
недействительными task1 (недействительными * pvParameters) { в то время как (1) { .. ..//your логика } }
7. Большей части кода требуется функция задержки для остановки выполняющейся задачи, но в RTOS не рекомендуется использовать функцию Delay (), поскольку она останавливает ЦП и, следовательно, RTOS также перестает работать. Итак, FreeRTOS имеет API ядра для блокировки задачи на определенное время.
vTaskDelay (const TickType_t xTicksToDelay);
Этот API можно использовать для задержки. Этот API задерживает задачу на заданное количество тиков. Фактическое время, в течение которого задача остается заблокированной, зависит от тика. Константу portTICK_PERIOD_MS можно использовать для расчета в реальном времени на основе тикового курса.
Это означает, что если вам нужна задержка в 200 мс, просто напишите эту строку
vTaskDelay (200 / портTICK_PERIOD_MS);
Итак, в этом руководстве мы будем использовать эти API FreeRTOS для реализации трех задач.
Используемые API:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
Задача, которую необходимо создать для этого руководства:
- Светодиод мигает на цифровом выводе 8 с частотой 200 мс
- Светодиод мигает на цифровом выводе 7 с частотой 300 мс
- Печатайте номера на серийном мониторе с частотой 500 мс.
Реализация задачи FreeRTOS в среде Arduino IDE
1. Из приведенного выше объяснения базовой структуры включите заголовочный файл Arduino FreeRTOS. Затем сделайте прототипы функций. Поскольку у нас есть три задачи, сделайте три функции и их прототипы.
#include void TaskBlink1 (void * pvParameters); void TaskBlink2 (void * pvParameters); void Taskprint (void * pvParameters);
2. В функции void setup () инициализируйте последовательную связь со скоростью 9600 бит в секунду и создайте все три задачи с помощью xTaskCreate () API. Изначально установите приоритеты всех задач как «1» и запустите планировщик.
void setup () { Serial.begin (9600); xTaskCreate (TaskBlink1, «Task1», 128, NULL, 1, NULL); xTaskCreate (TaskBlink2, «Задача2», 128, NULL, 1, NULL); xTaskCreate (Taskprint, «Task3», 128, NULL, 1, NULL); vTaskStartScheduler (); }
3. Теперь выполните все три функции, как показано ниже, чтобы индикатор задачи 1 мигал.
void TaskBlink1 (void * pvParameters) { pinMode (8, ВЫХОД); в то время как (1) { digitalWrite (8, HIGH); vTaskDelay (200 / портTICK_PERIOD_MS); digitalWrite (8, LOW); vTaskDelay (200 / портTICK_PERIOD_MS); } }
Аналогичным образом реализуем функцию TaskBlink2. Функция Task3 запишется как
void Taskprint (void * pvParameters) { int counter = 0; в то время как (1) { counter ++; Serial.println (счетчик); vTaskDelay (500 / портTICK_PERIOD_MS); } }
Вот и все. Мы успешно завершили проект FreeRTOS Arduino для Arduino Uno. Вы можете найти полный код вместе с видео в конце этого руководства.
Наконец, подключите два светодиода к цифровым контактам 7 и 8, загрузите код на плату Arduino и откройте последовательный монитор. Вы увидите, что счетчик запускается один раз в 500 мс с названием задачи, как показано ниже.
Также обратите внимание на светодиоды, они мигают с разным интервалом времени. Попробуйте поиграть с аргументом приоритета в функции xTaskCreate . Измените номер и наблюдайте за поведением на последовательном мониторе и светодиодах.
Теперь вы можете понять первые два примера кодов, в которых создаются задачи аналогового и цифрового чтения. Таким образом, вы можете создавать более продвинутые проекты, используя только API Arduino Uno и FreeRTOS.