- Предимства на многоядрения процесор
- 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 вече е програмиран за RF комуникация. Но ето този урок ще покажем как да използваме двете ядра на ESP32, за да извършим две операции едновременно. Тук първата задача ще бъде да мига вградения светодиод, а втората задача ще бъде да извлече температурните данни от сензора DHT11.
Нека първо видим предимствата на многоядрения процесор пред едноядрения.
Предимства на многоядрения процесор
- Многоядрените процесори са полезни, когато има повече от 2 процеса, които да работят едновременно.
- Тъй като работата е разпределена между различни ядра, нейната скорост се увеличава и множество процеси могат да бъдат завършени едновременно.
- Консумацията на енергия може да бъде намалена, защото когато всяко ядро е в режим на празен ход, то може да се използва за изключване на периферните устройства, които не се използват по това време.
- Двуядрените процесори трябва да превключват между различни нишки по-рядко от едноядрените, тъй като те могат да обработват две наведнъж, вместо една по една.
ESP32 и FreeRTOS
Платката ESP32 вече има инсталиран фърмуер FreeRTOS. FreeRTOS е операционна система в реално време с отворен код, която е много полезна при многозадачност. RTOS помага при управлението на ресурсите и максимизиране на производителността на системата. FreeRTOS има много API функции за различни цели и като използваме тези API, можем да създаваме задачи и да ги караме да работят на различни ядра.
Пълна документация за API на FreeRTOS можете да намерите тук. Ще се опитаме да използваме някои API в нашия код, за да изградим многозадачно приложение, което ще работи и на двете ядра.
Намиране на основния идентификатор на ESP32
Тук ще използваме Arduino IDE, за да качим кода в ESP32. За да знаете Core ID, на който се изпълнява кодът, има функция API
xPortGetCoreID ()
Тази функция може да бъде извикана от void setup () и void loop (), за да се знае основният ID, на който се изпълняват тези функции.
Можете да тествате този API, като качите скицата по-долу:
void setup () { Serial.begin (115200); Serial.print ("функция за настройка (), работеща на ядрото:"); Serial.println (xPortGetCoreID ()); } void loop () { Serial.print ("loop () функция, работеща в ядрото:"); Serial.println (xPortGetCoreID ()); }
След като качите горната скица, отворете серийния монитор и ще откриете, че и двете функции работят на core1, както е показано по-долу.
От горните наблюдения може да се заключи, че скицата на Arduino по подразбиране винаги работи на core1.
ESP32 двуядрено програмиране
Arduino IDE поддържа FreeRTOS за ESP32, а API на FreeRTOS ни позволяват да създаваме задачи, които могат да се изпълняват независимо на двете ядра. Задачата е парче код, което извършва някаква операция на платката като мигащ led, температура на изпращане и т.н.
Функцията по-долу се използва за създаване на задачи, които могат да се изпълняват и на двете ядра. В тази функция трябва да дадем някои аргументи като приоритет, идентификатор на ядрото и т.н.
Сега следвайте стъпките по-долу, за да създадете задача и функция.
1. Първо, създайте задачи във функцията за настройка на void . Тук ще създадем две задачи, едната за мигане на светодиода след всеки 0,5 секунди и друга задача е да се получи отчитане на температурата след всеки 2 секунди.
Функцията xTaskCreatePinnedToCore () отнема 7 аргумента:
- Име на функция за изпълнение на задачата (task1)
- Всяко име, дадено на задачата („task1“ и т.н.)
- Размер на стека, разпределен на задачата с думи (1 дума = 2 байта)
- Параметър за въвеждане на задача (може да бъде NULL)
- Приоритет на задачата (0 е най-ниският приоритет)
- Манипулатор на задачата (може да бъде NULL)
- Основен идентификатор, където ще се изпълнява задачата (0 или 1)
Сега създайте Task1 за мигане на led, като дадете всички аргументи във функцията xTaskCreatePinnedToCore ().
xTaskCreatePinnedToCore (Task1code, "Task1", 10000, NULL, 1, NULL, 0);
По същия начин създайте Task2 за Task2 и направете идентификатор на ядро 1 в 7 -ия аргумент.
xTaskCreatePinnedToCore (Task2code, "Task2", 10000, NULL, 1, NULL, 1);
Можете да промените приоритета и размера на стека в зависимост от сложността на задачата.
2. Сега ще приложим функцията Task1code и Task2code . Тези функции съдържат кода за необходимата задача. В нашия случай първата задача ще премигва светодиода, а друга задача ще достигне температурата. Затова направете две отделни функции за всяка задача извън функцията за настройка на void.
Task1code функция за мига на борда доведе след 0,5 секунди се осъществява, както е показано по-долу.
Void Task1code (void * параметър) { Serial.print ("Task1 работи на ядрото"); Serial.println (xPortGetCoreID ()); за (;;) {// безкраен цикъл digitalWrite (led, HIGH); забавяне (500); digitalWrite (LED, LOW); забавяне (500); } }
По същия начин внедрете функцията Task2code за извличане на температурата.
void Task2code (void * pvParameters) { Serial.print ("Task2 работи на ядрото"); Serial.println (xPortGetCoreID ()); за (;;) { 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.
Пълният код заедно с демонстрационния видеоклип е даден по-долу.