- Преимущества многоядерного процессора
- ESP32 и FreeRTOS
- Определение идентификатора ядра ESP32
- Двухъядерное программирование ESP32
Модули ESP популярны благодаря своим функциям Wi-Fi, таким как ESP8266, ESP-12E и т. Д. Все они представляют собой мощные модули микроконтроллеров с функциями Wi-Fi. Есть еще один модуль ESP, который более мощный и универсальный, чем предыдущие модули ESP, его имя ESP32. Он поддерживает Bluetooth и Wi-Fi, и мы уже объясняли возможности BLE ESP32 и использовали ESP32 во многих проектах IoT. Но мало кто знает, что ESP32 - это двухъядерный микроконтроллер.
ESP32 имеет два 32-разрядных микропроцессора Tensilica Xtensa LX6, что делает его мощным двухъядерным (core0 и core1) микроконтроллером. Он доступен в двух вариантах: одноядерный и двухъядерный. Но двухъядерный вариант более популярен, потому что здесь нет значительной разницы в цене.
ESP32 может быть запрограммирован с использованием Arduino IDE, Espressif IDF, Lua RTOS и т. Д. При программировании с Arduino IDE код работает только на Core1, поскольку Core0 уже запрограммирован для радиочастотной связи. Но вот в этом руководстве мы покажем, как использовать оба ядра ESP32 для одновременного выполнения двух операций. Здесь первой задачей будет мигание встроенного светодиода, а второй задачей будет получение данных о температуре с датчика DHT11.
Давайте сначала посмотрим на преимущества многоядерного процессора перед одноядерным.
Преимущества многоядерного процессора
- Многоядерные процессоры полезны, когда одновременно работают более двух процессов.
- Поскольку работа распределяется между разными ядрами, ее скорость увеличивается, и несколько процессов могут выполняться одновременно.
- Потребляемая мощность может быть уменьшена, потому что, когда какое-либо ядро находится в режиме ожидания, его можно использовать для отключения периферийных устройств, которые в это время не используются.
- Двухъядерные процессоры должны переключаться между разными потоками реже, чем одноядерные процессоры, потому что они могут обрабатывать два одновременно, а не по одному за раз.
ESP32 и FreeRTOS
На плате ESP32 уже установлена прошивка FreeRTOS. FreeRTOS - это операционная система реального времени с открытым исходным кодом, которая очень полезна при многозадачности. RTOS помогает управлять ресурсами и максимизировать производительность системы. FreeRTOS имеет множество функций API для разных целей, и с помощью этих API мы можем создавать задачи и запускать их на разных ядрах.
Полную документацию по API FreeRTOS можно найти здесь. Мы попытаемся использовать некоторые API-интерфейсы в нашем коде для создания многозадачного приложения, которое будет работать на обоих ядрах.
Определение идентификатора ядра ESP32
Здесь мы будем использовать Arduino IDE для загрузки кода в ESP32. Чтобы узнать Core ID, на котором выполняется код, существует функция API
xPortGetCoreID ()
Эту функцию можно вызвать из функций void setup () и void loop (), чтобы узнать идентификатор ядра, на котором выполняются эти функции.
Вы можете протестировать этот API, загрузив скетч ниже:
void setup () { Serial.begin (115200); Serial.print ("функция setup (), работающая на ядре:"); Serial.println (xPortGetCoreID ()); } void loop () { Serial.print ("функция loop (), работающая на ядре:"); Serial.println (xPortGetCoreID ()); }
После загрузки приведенного выше эскиза откройте монитор последовательного порта, и вы обнаружите, что обе функции работают на ядре core1, как показано ниже.
Из приведенных выше наблюдений можно сделать вывод, что эскиз Arduino по умолчанию всегда работает на core1.
Двухъядерное программирование ESP32
Arduino IDE поддерживает FreeRTOS для ESP32, а API FreeRTOS позволяют нам создавать задачи, которые могут выполняться независимо на обоих ядрах. Задача - это фрагмент кода, который выполняет некоторые операции на плате, такие как мигание светодиода, отправка температуры и т. Д.
Следующая функция используется для создания задач, которые могут выполняться на обоих ядрах. В этой функции мы должны указать некоторые аргументы, такие как приоритет, идентификатор ядра и т. Д.
Теперь выполните следующие шаги, чтобы создать задачу и функцию задачи.
1. Сначала создайте задачи в функции настройки void . Здесь мы создадим две задачи: одна для мигания светодиода через каждые 0,5 секунды, а другая задача - получение показаний температуры через каждые 2 секунды.
Функция xTaskCreatePinnedToCore () принимает 7 аргументов:
- Имя функции для реализации задачи (task1)
- Любое имя, присвоенное задаче («задача1» и т. Д.)
- Размер стека, выделенного задаче в словах (1 слово = 2 байта)
- Входной параметр задачи (может быть NULL)
- Приоритет задачи (0 - самый низкий приоритет)
- Дескриптор задачи (может быть NULL)
- Идентификатор ядра, по которому будет выполняться задача (0 или 1)
Теперь создайте Task1 для мигания светодиода, указав все аргументы в функции xTaskCreatePinnedToCore ().
xTaskCreatePinnedToCore (Task1code, «Task1», 10000, NULL, 1, NULL, 0);
Точно так же создайте Task2 для Task2 и сделайте основной идентификатор 1 в 7- м аргументе.
xTaskCreatePinnedToCore (Task2code, «Задача2», 10000, NULL, 1, NULL, 1);
Вы можете изменить приоритет и размер стека в зависимости от сложности задачи.
2. Теперь мы реализуем функцию Task1code и Task2code . Эти функции содержат код требуемой задачи. В нашем случае первая задача будет мигать светодиодом, а другая задача будет получать температуру. Так что сделайте две отдельные функции для каждой задачи вне функции настройки void.
Функция Task1code для мигания бортового светодиода через 0,5 секунды реализована, как показано ниже.
Void Task1code (параметр void *) { Serial.print ("Task1 выполняется на ядре"); Serial.println (xPortGetCoreID ()); for (;;) {// бесконечный цикл digitalWrite (led, HIGH); задержка (500); digitalWrite (во главе, LOW); задержки (500); } }
Точно так же реализуйте функцию Task2code для получения температуры.
void Task2code (void * pvParameters) { Serial.print ("Task2 выполняется на ядре"); Serial.println (xPortGetCoreID ()); for (;;) { float t = dht.readTemperature (); Serial.print ("Температура:"); Serial.print (t); задержка (2000); } }
3. Здесь функция void loop останется пустой. Как мы уже знаем, функция цикла и настройки работает на core1, поэтому вы также можете реализовать задачу core1 в функции void loop .
Теперь часть кодирования окончена, поэтому просто загрузите код с помощью Arduino IDE, выбрав плату ESP32 в меню Инструменты. Убедитесь, что вы подключили датчик DHT11 к контакту D13 ESP32.
Теперь результаты можно отслеживать с помощью Serial Monitor или Arduino IDE, как показано ниже:
Сложные приложения, такие как система реального времени, могут быть созданы путем одновременного выполнения нескольких задач с использованием двухъядерных процессоров ESP32.
Полный код и демонстрационное видео приведены ниже.