- Avantajele procesorului multi-core
- ESP32 și FreeRTOS
- Găsirea ID-ului de bază ESP32
- Programare ESP32 Dual Core
Modulele ESP sunt populare pentru funcționalitățile lor Wi-Fi, cum ar fi ESP8266, ESP-12E, etc. Toate acestea sunt module puternice de microcontroler cu funcționalități Wi-Fi. Există încă un modul ESP care este mai puternic și mai versatil decât modulele ESP anterioare - numele său este ESP32. Are conectivitate Bluetooth și Wi-Fi și am explicat deja capabilitățile BLE ale ESP32 și am folosit ESP32 în multe proiecte IoT. Dar foarte puțini oameni știu că ESP32 este un microcontroler dual-core.
ESP32 are două microprocesoare Tensilica Xtensa LX6 pe 32 de biți, ceea ce îl face un microcontroler puternic dual-core (core0 și core1). Este disponibil în două variante single-core și dual-core. Dar varianta dual-core este mai populară, deoarece nu există o diferență semnificativă de preț.
ESP32 poate fi programat folosind Arduino IDE, Espressif IDF, Lua RTOS etc. În timp ce programați cu Arduino IDE, codul rulează doar pe Core1 deoarece Core0 este deja programat pentru comunicații RF. Dar iată acest tutorial, vă vom arăta cum să utilizați ambele nuclee ale ESP32 pentru a efectua două operații simultan. Aici prima sarcină va fi să clipească LED-ul de la bord și a doua sarcină va fi să preia datele de temperatură de la senzorul DHT11.
Să vedem mai întâi avantajele unui procesor multi-core față de un singur nucleu.
Avantajele procesorului multi-core
- Procesoarele multi-core sunt utile atunci când există mai mult de 2 procese care pot funcționa simultan.
- Pe măsură ce munca este distribuită între diferite nuclee, viteza sa crește și mai multe procese pot fi finalizate în același timp.
- Consumul de energie poate fi redus, deoarece atunci când orice nucleu este în modul inactiv, poate fi folosit pentru a opri perifericele care nu sunt utilizate în acel moment.
- Procesoarele dual-core trebuie să comute între fire diferite mai rar decât procesoarele single-core, deoarece pot gestiona două simultan în loc de unul câte unul.
ESP32 și FreeRTOS
Placa ESP32 are deja instalat firmware-ul FreeRTOS. FreeRTOS este un sistem de operare open-source în timp real, care este foarte util în multitasking. RTOS ajută la gestionarea resurselor și la maximizarea performanței sistemului. FreeRTOS are multe funcții API în scopuri diferite și folosind aceste API-uri, putem crea sarcini și le putem face să ruleze pe diferite nuclee.
Documentația completă a API-urilor FreeRTOS poate fi găsită aici. Vom încerca să folosim câteva API-uri în codul nostru pentru a crea o aplicație multitasking care va rula pe ambele nuclee.
Găsirea ID-ului de bază ESP32
Aici vom folosi Arduino IDE pentru a încărca codul în ESP32. Pentru a cunoaște ID-ul de bază pe care rulează codul, există o funcție API
xPortGetCoreID ()
Această funcție poate fi apelată din funcția void setup () și void loop () pentru a cunoaște ID-ul de bază pe care rulează aceste funcții.
Puteți testa acest API încărcând schița de mai jos:
void setup () { Serial.begin (115200); Serial.print (funcția "setup () care rulează pe nucleu:"); Serial.println (xPortGetCoreID ()); } void loop () { Serial.print (funcția "loop () care rulează pe nucleu:"); Serial.println (xPortGetCoreID ()); }
După încărcarea schiței de mai sus, deschideți monitorul Serial și veți găsi că ambele funcții rulează pe core1 așa cum se arată mai jos.
Din observațiile de mai sus, se poate concluziona că schița implicită Arduino rulează întotdeauna pe core1.
Programare ESP32 Dual Core
Arduino IDE acceptă FreeRTOS pentru ESP32 și API-urile FreeRTOS ne permit să creăm sarcini care pot rula independent pe ambele nuclee. Sarcina este piesa de cod care efectuează o anumită operație pe placă, cum ar fi ledul intermitent, temperatura de trimitere etc.
Funcția de mai jos este utilizată pentru a crea sarcini care pot rula pe ambele nuclee. În această funcție, trebuie să oferim câteva argumente, cum ar fi o prioritate, ID-ul de bază etc.
Acum, urmați pașii de mai jos pentru a crea sarcina și funcția sarcinii.
1. Mai întâi, creați activități în funcția de configurare nulă . Aici vom crea două sarcini, una pentru LED-ul intermitent la fiecare 0,5 secunde și o altă sarcină este de a obține citirea temperaturii după fiecare 2 secunde.
Funcția xTaskCreatePinnedToCore () ia 7 argumente:
- Numele funcției pentru implementarea sarcinii (task1)
- Orice nume dat sarcinii („task1” etc.)
- Dimensiunea stivei alocată sarcinii în cuvinte (1 cuvânt = 2 biți)
- Parametrul de introducere a activității (poate fi NUL)
- Prioritatea sarcinii (0 este cea mai mică prioritate)
- Task handle (poate fi NULL)
- ID de bază în care va rula sarcina (0 sau 1)
Acum, creați Task1 pentru a clipi ledul oferind toate argumentele din funcția xTaskCreatePinnedToCore ().
xTaskCreatePinnedToCore (Task1code, "Task1", 10000, NULL, 1, NULL, 0);
În mod similar, creați Task2 pentru Task2 și să facă miez id 1 în 7 - lea argument.
xTaskCreatePinnedToCore (Task2code, "Task2", 10000, NULL, 1, NULL, 1);
Puteți modifica prioritatea și dimensiunea stivei în funcție de complexitatea sarcinii.
2. Acum, vom implementa funcția Task1code și Task2code . Aceste funcții conțin codul pentru sarcina necesară. În cazul nostru, prima sarcină va clipi cu ledul și o altă sarcină va prelua temperatura. Deci, faceți două funcții separate pentru fiecare activitate în afara funcției de configurare nulă.
Funcția Task1code pentru clipirea led-ului de la bord după 0,5 secunde este implementată așa cum se arată mai jos.
Void Task1code (parametru void *) { Serial.print ("Task1 rulează pe bază"); Serial.println (xPortGetCoreID ()); pentru (;;) {// buclă infinită digitalWrite (led, HIGH); întârziere (500); digitalWrite (led, LOW) întârziere (500); } }
În mod similar, implementați funcția Task2code pentru preluarea temperaturii.
void Task2code (void * pvParameters) { Serial.print ("Task2 rulează pe bază"); Serial.println (xPortGetCoreID ()); pentru (;;) { float t = dht.readTemperature (); Serial.print ("Temperatura:"); Serial.print (t); întârziere (2000); } }
3. Aici funcția buclă nulă va rămâne goală. După cum știm deja că bucla și funcția de configurare rulează pe core1, astfel încât să puteți implementa sarcina core1 și în funcția de buclă nulă .
Acum partea de codare s-a terminat, deci încărcați codul utilizând Arduino IDE alegând placa ESP32 din meniul Instrumente. Asigurați-vă că ați conectat senzorul DHT11 la pinul D13 al ESP32.
Acum, rezultatele pot fi monitorizate pe Serial Monitor sau Arduino IDE așa cum se arată mai jos:
Aplicații complexe, cum ar fi sistemul în timp real, pot fi construite executând mai multe sarcini simultan folosind nuclee duale de ESP32.
Codul complet împreună cu un videoclip Demo sunt prezentate mai jos.