Podcast
Questions and Answers
Care este scopul principal al utilizării unei structuri MenuItem
într-un proiect ESP32 cu meniu navigabil?
Care este scopul principal al utilizării unei structuri MenuItem
într-un proiect ESP32 cu meniu navigabil?
- Pentru a oferi acces la toți pinii GPIO.
- Pentru a reduce dimensiunea sketch-ului.
- Pentru a accelera comunicarea SPI.
- Pentru a gestiona facil stările și legăturile dintre itemi. (correct)
Ce membru al unei structuri de tip MenuItem
indică submeniul asociat acelui item?
Ce membru al unei structuri de tip MenuItem
indică submeniul asociat acelui item?
- label
- callback
- child (correct)
- parent
Cum se realizează afișarea unui item de meniu selectat pe un ecran LCD 16x2?
Cum se realizează afișarea unui item de meniu selectat pe un ecran LCD 16x2?
- Serial.println(item.label);
- Icd.print(item->label);
- oled.display(item.label);
- Icd.clear(); Icd.print(item->label); (correct)
Ce rol are funcția callback
asociată unui item de meniu?
Ce rol are funcția callback
asociată unui item de meniu?
Care este metoda recomandată de a parcurge un meniu cu encoder rotativ?
Care este metoda recomandată de a parcurge un meniu cu encoder rotativ?
Ce funcție se poate apela pentru a reveni la meniul părinte?
Ce funcție se poate apela pentru a reveni la meniul părinte?
Într-o structură de meniu, ce legătură asigură navigarea laterală (left/right)?
Într-o structură de meniu, ce legătură asigură navigarea laterală (left/right)?
Ce tip de pointer este uzual folosit pentru a defini structura de itemi într-un meniu?
Ce tip de pointer este uzual folosit pentru a defini structura de itemi într-un meniu?
Cum se asigură stabilitatea afișajului când un utilizator rotește encoderul rapid?
Cum se asigură stabilitatea afișajului când un utilizator rotește encoderul rapid?
Cum previi trecerea în afara limitelor meniului când se rotește encoderul?
Cum previi trecerea în afara limitelor meniului când se rotește encoderul?
Care este scopul variabilei currentMenu
într-un sistem de meniu?
Care este scopul variabilei currentMenu
într-un sistem de meniu?
Care dintre următoarele este o bună practică în definirea meniurilor statice?
Care dintre următoarele este o bună practică în definirea meniurilor statice?
Cum afișezi un meniu cu mai mult de două opțiuni pe un LCD 16x2?
Cum afișezi un meniu cu mai mult de două opțiuni pe un LCD 16x2?
Ce tehnică este utilă pentru a implementa un meniu „circular"?
Ce tehnică este utilă pentru a implementa un meniu „circular"?
Ce avantaj oferă folosirea unui pointer constant (const MenuItem*) pentru meniuri statice?
Ce avantaj oferă folosirea unui pointer constant (const MenuItem*) pentru meniuri statice?
De ce este preferat millis()
în loc de delay()
într-un proiect cu meniu și encoder?
De ce este preferat millis()
în loc de delay()
într-un proiect cu meniu și encoder?
Cum se gestionează un refresh periodic al ecranului fără a bloca execuția?
Cum se gestionează un refresh periodic al ecranului fără a bloca execuția?
Ce problemă poate apărea dacă nu se resetează timestamp-ul după un millis()
trigger?
Ce problemă poate apărea dacă nu se resetează timestamp-ul după un millis()
trigger?
Care dintre următoarele este o abordare corectă pentru multitasking soft cu flag-uri?
Care dintre următoarele este o abordare corectă pentru multitasking soft cu flag-uri?
Cum poți evita conflictele între două procese ce folosesc același timer (millis()
)?
Cum poți evita conflictele între două procese ce folosesc același timer (millis()
)?
Ce valoare returnează millis()
după aproximativ 50 de zile de uptime?
Ce valoare returnează millis()
după aproximativ 50 de zile de uptime?
Care e metoda recomandată pentru actualizarea non-blocantă a unei variabile de afișaj?
Care e metoda recomandată pentru actualizarea non-blocantă a unei variabile de afișaj?
Cum afectează folosirea while(true)
în loop()
procesele de fundal?
Cum afectează folosirea while(true)
în loop()
procesele de fundal?
Ce bibliotecă se poate folosi pentru multitasking simplu pe ESP32?
Ce bibliotecă se poate folosi pentru multitasking simplu pe ESP32?
Ce tip de variabile trebuie protejate în procese paralele (cu FreeRTOS)?
Ce tip de variabile trebuie protejate în procese paralele (cu FreeRTOS)?
Flashcards
Scopul structurii struct MenuItem
Scopul structurii struct MenuItem
Permite gestionarea ușoară a stărilor și a legăturilor dintre elementele meniului.
Membru 'child' în MenuItem
Membru 'child' în MenuItem
Indică submeniul asociat unui element de meniu.
Afișarea unui item de meniu pe LCD 16x2
Afișarea unui item de meniu pe LCD 16x2
Se folosește lcd.clear()
pentru a curăța ecranul, apoi lcd.print()
pentru afișare.
Rolul funcției callback
Rolul funcției callback
Signup and view all the flashcards
Metoda de parcurgere cu encoder rotativ
Metoda de parcurgere cu encoder rotativ
Signup and view all the flashcards
Revenirea la meniul părinte
Revenirea la meniul părinte
Signup and view all the flashcards
Navigare laterală în meniu
Navigare laterală în meniu
Signup and view all the flashcards
Tipul de pointer pentru structura itemilor
Tipul de pointer pentru structura itemilor
Signup and view all the flashcards
Stabilitatea afișajului la rotire rapidă
Stabilitatea afișajului la rotire rapidă
Signup and view all the flashcards
Prevenirea trecerii în afara limitelor meniului
Prevenirea trecerii în afara limitelor meniului
Signup and view all the flashcards
Scopul variabilei currentMenu
Scopul variabilei currentMenu
Signup and view all the flashcards
Practică bună pentru meniurile statice
Practică bună pentru meniurile statice
Signup and view all the flashcards
Afișarea unui meniu cu mai mult de două opțiuni pe un LCD 16x2
Afișarea unui meniu cu mai mult de două opțiuni pe un LCD 16x2
Signup and view all the flashcards
Tehnică pentru implementarea unui meniu circular
Tehnică pentru implementarea unui meniu circular
Signup and view all the flashcards
Avantajul pointerilor constanți pentru meniuri statice
Avantajul pointerilor constanți pentru meniuri statice
Signup and view all the flashcards
millis()
vs. delay()
pentru meniu și encoder
millis()
vs. delay()
pentru meniu și encoder
Signup and view all the flashcards
Refresh periodic al ecranului non-blocant
Refresh periodic al ecranului non-blocant
Signup and view all the flashcards
Problema lipsei resetării timestamp-ului după trigger
Problema lipsei resetării timestamp-ului după trigger
Signup and view all the flashcards
Abordare corectă pentru multitasking software cu flag-uri
Abordare corectă pentru multitasking software cu flag-uri
Signup and view all the flashcards
Evitarea conflictelor între procese cu același timer
Evitarea conflictelor între procese cu același timer
Signup and view all the flashcards
Valoarea returnată de millis()
după 50 de zile
Valoarea returnată de millis()
după 50 de zile
Signup and view all the flashcards
Actualizarea non-blocantă a unei variabile de afișaj
Actualizarea non-blocantă a unei variabile de afișaj
Signup and view all the flashcards
Efectul lui while(true)
în loop()
asupra proceselor de fundal
Efectul lui while(true)
în loop()
asupra proceselor de fundal
Signup and view all the flashcards
Bibliotecă pentru multitasking simplu pe ESP32
Bibliotecă pentru multitasking simplu pe ESP32
Signup and view all the flashcards
Variabile care trebuie protejate în procese paralele
Variabile care trebuie protejate în procese paralele
Signup and view all the flashcards
Study Notes
Structuri de Meniu în ESP32
- Structurile de tip
Menultem
facilitează gestionarea stărilor și legăturilor logice (următor, anterior, părinte, copil) ale itemilor din meniu. - Membrul
child
dintr-o structurăMenultem
indică submeniul asociat. - Afișarea unui item de meniu selectat pe un LCD 16x2 se face prin curățarea ecranului cu
Icd.clear()
și apoi afișarea textului cuIcd.print(item->label)
. - Funcția
callback
asociată unui item de meniu execută acțiunea specifică acelui item la selectare. - Parcurgerea unui meniu cu un encoder rotativ se face prin incrementarea/decrementarea indexului curent.
- Funcția
goToParent()
permite revenirea la meniul părinte. - Legăturile
previous
șinext
asigură navigarea laterală între itemi la același nivel în structura meniului. - Un pointer de tip
Menultem*
este folosit pentru a defini structura itemilor într-un meniu. - Stabilitatea afișajului la rotirea rapidă a encoderului se asigură prin actualizarea afișajului doar dacă poziția s-a schimbat.
- Trecerea în afara limitelor meniului este prevenită prin verificarea dacă pointerul
next
esteNULL
înainte de accesare. - Variabila
currentMenu
reprezintă pointerul către itemul curent din meniu. - În definirea meniurilor statice, initializarea tuturor legăturilor în
setup()
este o practică bună. - Un meniu cu mai mult de două opțiuni pe un LCD 16x2 se afișează prin schimbarea paginii afișate la fiecare două itemi.
- Implementarea unui meniu "circular" se face prin asignarea primului item la
next
atunci când se ajunge la ultimul item:if(next == NULL) next = firstItem;
. - Folosirea unui pointer constant (
const Menultem*
) pentru meniuri statice reduce memoria RAM utilizată, deoarece itemii constanți pot fi stocați în flash.
Procese în Fundal
millis()
este preferat luidelay()
deoarece permite execuția non-blocantă, verificând condițiile fără a opri programul.- Un refresh periodic al ecranului fără blocarea execuției se realizează prin compararea
millis()
cu un timestamp anterior. - Dacă timestamp-ul nu se resetează după un trigger
millis()
, evenimentul se va repeta constant fără pauză. - Multitasking-ul soft cu flag-uri implică folosirea flag-urilor (
shouldUpdate
,trigger
, etc.) pentru controlul execuției înloop()
fărădelay
. - Conflictele între procese care folosesc același timer (
millis()
) sunt evitate prin declararea a două variabile timestamp separate pentru fiecare proces. - Valoarea returnată de
millis()
revine la 0 după aproximativ 49.7 zile (overflow), necesitând precauție. - Actualizarea non-blocantă a unei variabile de afișaj se realizează cu
if (millis() - lastRefresh > 100)
, verificând timpul necesar fără blocare. - Utilizarea
while(true)
înloop()
oprește complet procesele de fundal. - Biblioteca
TaskScheduler.h
poate fi folosită pentru multitasking simplu pe ESP32. - Variabilele globale modificate de mai multe task-uri trebuie protejate în procese paralele, deoarece pot crea condiții de cursă.
- Funcția
vTaskDelay()
amână executarea unui task în FreeRTOS pe ESP32 fără a bloca restul sistemului. - Unitatea de timp implicită pentru
vTaskDelay(1000)
în FreeRTOS este Ticks, unde 1 tick ≠ 1 ms și depinde de frecvența sistemului. - Un task care rulează fără
vTaskDelay()
într-un sistem FreeRTOS acaparează toată execuția CPU. - Sincronizarea între două task-uri în ESP32/FreeRTOS se realizează cu
xSemaphore
sauxQueue
. - Un task separat pentru controlul LCD-ului permite delay-uri în paralel cu restul logicii.
Controlul Afișajelor LCD
- Orice doi pini de pe ESP32 pot fi conectați la LCD-ul I2C, fiind configurați ca SDA și SCL la inițializare prin
Wire.begin(SDA, SCL)
. - Comanda corectă pentru inițializarea unui LCD I2C 16x2 este
Icd.init(); Icd.backlight()
. - Curățarea afișajului LCD fără flicker se face prin
Icd.setCursor(0,0); lcd.print(" ");
, care suprascrie linia cu spații. - Poziția cursorului pe LCD se controlează cu
Icd.setCursor(col, row)
, metoda standard. - Animația de scroll pe un ecran 16x2 se creează cu
Icd.scrollDisplayLeft()
, care derulează întregul display. - Comanda
Icd.noBacklight()
oprește iluminarea de fundal, economisind curent. - Suprascrierea unui text scurt peste unul mai lung pe LCD se evită prin adăugarea de spații la finalul textului.
- Dacă se încearcă scrierea pe rândul 2 (index 1) înainte de
Icd.begin()
, nu apare nimic pe ecran deoarece LCD-ul trebuie inițializat corect. - Caractere custom pe un LCD 16x2 se crează cu
Icd.createChar(nr, pattern[])
, LCD-urile 16x2 suportând până la 8 caractere speciale. - Limita standard de caractere customizabile pentru un LCD clasic HD44780 este de 8 caractere, definite de utilizator în CGRAM.
- Afișarea rapidă fără întârziere între caractere se asigură prin scrierea într-un buffer (string) și afișarea completă.
- Biblioteca necesară pentru a folosi LCD-ul cu I2C în Arduino IDE este
LiquidCrystal_I2C.h
. - Dacă se scriu mai mult de 16 caractere pe un rând, textul continuă în afara ecranului, fiind invizibil.
- Simbolul ° (grad) pe un LCD 16x2 se afișează cu
lcd.print((char)223)
, codul ASCII 223 corespunzând simbolului de grad. - Consumul energetic al unui LCD când nu e necesar afișajul se reduce cu
lcd.noBacklight(); şi lcd.noDisplay();
, care opresc iluminarea și afișajul dar mențin conexiunea activă.
Butoane și Encodere
- Conectarea corectă a unui buton la un pin ESP32 pentru a obține LOW la apăsare se face între pin și GND, cu activare
INPUT_PULLUP
, care folosește rezistența internă. - Efectul de "bounce" la un buton sunt apăsări false cauzate de oscilații rapide.
- Debounce-ul software se realizează cu debounce logic cu
millis()
, care ignoră tranzițiile rapide. - Citirea butonului care evită blocarea
loop()
se face printr-o implementare de tipmillis()
non-blocking. - Un encoder rotativ generează două semnale digitale în cuadratură la rotire.
- Direcția de rotație a unui encoder se determină comparând semnalele A și B.
- Reacția imediată la o schimbare de stare a unui buton se obține cu
attachInterrupt()
pe pin. - O limitare a folosirii întreruperilor cu encodere rotative este pierderea semnalului dacă se rotește rapid, dacă codul ISR nu este optimizat.
- Un encoder cu 3 pini utilizează două cuadraturi și un pin LOW/HI pentru buton.
- Biblioteca Arduino frecvent utilizată pentru encodere este
Encoder.h
. - Pentru un encoder standard (20 pulsuri), se obțin 40 de stări distincte per clic dacă se citesc ambele faze (A și B).
- Filtrarea zgomotului la encoder la nivel hardware se face cu condensatori pe semnale.
- Asigurarea citirii corecte a encoderului în
loop()
fără întreruperi se face verificând fiecare pin individual și deducând rotația. - O abordare eficientă pentru debounce software al encoderului este
millis()
cu verificare de tranziție. - Funcția
read()
asigură citirea non-blocking a unui encoder în bibliotecaEncoder.h
, returnând poziția actuală fără a bloca rularea programului.
EEPROM
- ESP32 folosește memoria Flash (emulare EEPROM) pentru stocarea datelor persistente, neavând EEPROM reală.
- Biblioteca
EEPROM.h
trebuie inclusă pentru a folosi EEPROM pe ESP32. - Funcția
EEPROM.begin(size)
trebuie apelată pentru a începe lucrul cu EEPROM, ESP32 necesitând rezervarea memoriei în flash. - Scrierea unui
int
la adresa 0 în EEPROM pe ESP32 se face cuEEPROM.put(0, val)
. - Funcția
EEPROM.commit()
este esențială după scrierea în EEPROM pentru salvarea datelor în memoria flash. - Dimensiunea maximă ce poate fi alocată prin
EEPROM.begin()
pe ESP32 este de 4096 bytes (4KB). - Citirea unei structuri de date din EEPROM se face cu
EEPROM.get(adr, var)
. - Un risc al scrierii frecvente în EEPROM este uzura memoriei flash.
- Scrierile repetate inutile în EEPROM se evită verificând dacă valoarea s-a schimbat.
- O structură personalizată este recomandată pentru salvarea mai multor parametri în EEPROM.
- După salvarea datelor cu
EEPROM.put()
, este necesar să se apelezeEEPROM.commit()
pentru salvarea fizică. - Datele salvate în EEPROM pot fi "șterse" prin rescrierea cu valori 0 sau default.
- Pentru a salva 2 structuri diferite în EEPROM, este necesar să se aloce zone diferite de memorie.
- Funcția
EEPROM.get()
returnează datele salvate ca referință în EEPROM. - Accesul concurent la EEPROM dintr-un task paralel (FreeRTOS) necesită protecție, altfel datele se pot corupe.
PWM
- Funcția
ledcAttachPin(pin, channel)
asociază un canal PWM cu un pin pe ESP32. - ESP32 nu setează frecvență implicită a semnalului PWM – este obligatoriu să o definești cu
ledcSetup()
. - Funcția
ledcSetup(channel, freq, resolution)
setează frecvența și rezoluția unui canal PWM. - Valoarea maximă a duty-cycle-ului pentru o rezoluție de 8 biți este 255.
- ESP32 permite 16 canale PWM independente (0-15).
- Setarea unui semnal PWM de 10kHz și 10 biți pe canalul 2 se face cu
ledcSetup(2, 10000, 10)
. - Nivelul de duty-cycle pe un canal PWM se setează cu
ledcWrite(channel, duty)
. - Frecvența unui canal PWM se modifică în timp real apelând
ledcSetup()
din nou cu noua frecvență. - Setearea unei rezoluții de 16 biți și a unei frecvențe mare pe PWM poate duce la instabilitatea semnalului sau la nefuncționarea acestuia, din cauza consumului ridicat de resurse.
- Dacă două canale PWM diferite controlează același pin, doar ultimul atașat va funcționa, suprascriind legătura pinului.
- ESP32 poate genera semnale PWM simultan pe mai multe piese hardware (e.g., LED + motor) cu canale diferite.
- Un avantaj al PWM software față de PWM hardware este că orice pin poate fi folosit, deoarece nu este legat de timere hardware.
- Controlul luminozității unui LED cu PWM se realizează cu
ledcWrite()
pe ESP32. - Canalele PWM care folosesc același timer pot fi sincronizate precis.
ADC
- PWM este o metodă de modulare a duratei impulsurilor.
- Funcția
analogRead(pin)
citește o valoare analogică pe ESP32. - Rezoluția implicită a ADC-ului pe ESP32 este de 12 biți, valoarea returnată de
analogRead()
fiind între 0 și 4095. - ADC-ul ESP32 funcționează fără calibrare specială în intervalul de tensiune 0-3.3V.
- Funcția
analogSetBits(bits)
setează rezoluția ADC-ului pe ESP32, controlând câți biți are conversia analogică. - O problemă care apare adesea la citirea semnalelor analogice brute pe ESP32 este zgomotul și fluctuațiile mari.
- Media mai multor citiri reduce fluctuațiile la citirea valorilor analogice.
- Anumiți pini (GPIOs) care NU sunt folosiți de SPI/Flash sunt siguri pentru citire analogică pe ESP32.
- Valoarea brută
analogRead()
poate fi convertită într-o tensiune (V) cu formula:tensiune = analogRead(pin) / 4095.0 * 3.3;
. - Funcția
analogSetAttenuation()
setează factorul de atenuare al canalului ADC, crescând intervalul de tensiune măsurabil. - Dacă un senzor de
Studying That Suits You
Use AI to generate personalized quizzes and flashcards to suit your learning preferences.