Avtor: dr. Simon Vavpotič
e-mail: simon.vavpotic@gmail.com
Kako načrtovati krmilno aplikacijo z grafičnim uporabniškim vmesnikom?
V preteklem članku smo poznali, kako hitre in zanesljive so brezžične komunikacije z M5Dial? Katere so njihove prednosti in ali lahko v zidno konzolo vgrajen okrogli M5Dial krmilnik z barvnimi LCD zaslonom zanesljivo komunicira z različnimi krmilniki doma in upravlja tako luči kot gospodinjske aparate. Tokrat se lotimo načrtovanja krmilne aplikacije za M5Dial in njenega grafičnega uporabniškega vmesnika.
Ta vsebina je samo za naročnike
Načrtovanje iz izris grafičnih elementov
Grafični elementi so lahko zelo preprosti, lahko pa vsebujejo tudi fotografije ipd. GFX grafična programska knjižnica, ki je del M5Stack programskega sklada, je seveda na voljo tudi za M5Dial, vendar ne prek razreda Lcd, ampak razreda Display. Ker med primeri za M5Dial najdemo samo najpreprostejšega z izpisom teksta in nekaj grafičnih elementov, si lahko pri načrtovanju kompleksnejše grafike pomagamo tudi s primeri iz veliko obsežnejšega M5Stacka, pri katerih razred Lcd v programski kodi zamenjamo z Display. Toliko o osnovah, zdaj pa h konkretnemu primeru!
V preteklem članku v SE332 ste si lahko ogledali shemo krmilnika luči, ki prižiga in ugaša tri LED trakove, obenem pa lahko nastavi tudi jakost osvetlitve z 256 nivoji. M5Dial z zaslonom občutljivim na dotik in rotacijskim enkoderjem je več kot dovolj zmogljiv za njihovo krmiljenje.
Zaslon sem se odločil razdeliti na 4 polja, ki sem jih označil s ciframi od 1 do 4. Dotik vsakega od njih vklopi ali ugasne enega od LED trakov, medtem ko je 4. polje rezervirano za prihodnjo uporabo. Vendar to še ni dovolj! Za nastavljanje jakosti osvetlitve potrebujemo tudi rotacijski gumb z enkoderjem na obodu M5Dial. Jakost nastavimo med 0 % in 100 %, pri čemer nastavljamo vse vklopljene LED trakove hkrati.
Kako deluje?
Izris grafike je preprost! Na zaslon narišemo 4 pravokotnike, od katerih vsak zaseda njegovo četrtino. Ker pa je na robovih prikazovalnik okrogel, deli pravokotnikov ostanejo skriti, kar pa ne vpliva na siceršnji prikaz grafike, za katerega poskrbi krmilnik prikazovalnika.
V začetku so vsi LED trakovi izklopljeni in na prikazovalniku ponazorjeni s črnimi polji. S pritiskom na kateregakoli od njih, se polje (pravokotnik) obarva s svojo aktivno barvo hkrati pa se vklopi ustrezen LED trak, katerega jakost osvetlitve je odvisna od trenutne nastavitve, ki ostane shranjena v krmilniku osvetlitve tudi, če fizično odklopimo napajanje. Barve LED trakov so: modra (1. trak), zelena (2. trak), oranžna (3. trak) in rdeča (4. trak).
Programska koda za prižiganje in ugašanje LED segmentov je razdeljena na 2 dela: funkcijo za detekcijo dotika in določanje barve posameznega pravokotnika na prikazovalniku ter kodo glavne programske zanke za izris grafičnih elementov in vodenja stanja LED segmentov. Poglejmo najprej funkcijo za obdelavo posameznega polja , glej program 1.
Vhodna parametra sta f, s katerim izberemo polje na zaslonu, ki ga želimo obdelati, in t, ki je trirazsežni vektor, ki določa trenutno pozicijo dotika: t.x in t.y in stanje zaslona na dotik, t.state. Spremenljivka t.state ima lahko 16 vrednosti (od 0 do 15), ki imajo naslednji pomen: 0 – ni dogodka, 4, 8 in 12 – so rezervirane in nimajo določenega pomena, 1 – dotik, 3 – dotik se je začel, 2 – dotik se je končal, 5 – držanje prsta na mestu, 7 – držanje prsta na mestu se je začelo, 6 – držanje prsta na mestu se je končalo, 9 – hiter poteg prsta čez zaslon, 11 – hiter poteg prsta čez zaslon se je začel, 10 – hiter poteg prsta čez zaslon se je končal, 13 – vlečenje prsta čez zaslon, 15 – začetek vlečenja prsta čez zaslon, 14 – končanje vlečenja prsta čez zaslon.
Nadaljnja programska koda določa spremembo barve polja na prikazovalniku, na katerega smo pritisnili in preprečuje ponavljanje obravnave pritiska na zaslon, dokler ne odmaknemo prsta z njega. Omenimo še globalno spremenljivko BR, ki določa jakost osvetlitve, njena vrednost pa je v obsegu od 0 do 100 procentov.
Zajem vrednosti enkoderja rotacijskega gumba na obodu poteka v glavni zanki takole:
void loop() {M5Dial.update(); auto t =
M5Dial.Touch.getDetail(); ….
Kot vidimo, vrednost t pridobimo preprosto s klicem ene same funkcije, medtem ko za njeno osveževanje poskrbi funkcija M5Dial.update. Vendar, kot bomo videli v nadaljevanju, lahko M5Dial.update tudi izpustimo, če jo kličemo že iz programske niti enkoderja.
Poglejmo nadaljevanje glavne programske zanke:
if (prev_state != t.state) {
prev_state = t.state;
for(int n=0;n<4;n++)LEDfunc(n,t);
M5Dial.Display.fillRect(0,0,120,120,LED[0]);
M5Dial.Display.fillRect(120,0,255,120,LED[1]);
M5Dial.Display.fillRect(0,120,120,255,LED[2]);
M5Dial.Display.fillRect(120,120,255,255,LED[3]);
M5Dial.Display.setTextColor(WHITE);
M5Dial.Display.drawString(„1“,60,60);
M5Dial.Display.drawString(„2“,170,60);
M5Dial.Display.drawString(„3“,60,170);
M5Dial.Display.drawString(„4“,170,170);
…
V tretji vrstici se štirikrat izvede pravkar razložena funkcija LEDfunc, za vsak del zaslona po enkrat. V nadaljevanju sledi izris pravokotnikov v njihovih trenutnih barvah, čeznje pa se z belo barvo izrišejo njihove oznake od 1 do 4. Pomembni sta tudi prva in druga vrstica kode, saj določata, da se vse omenjeno izvede le, če se vrednost t.state spremeni.
Zajemanje pozicije iz rotacijskega gumba
Čeprav smo rotacijski gumb že omenili, je prav, da si ogledamo še nekaj podrobnosti zajemanja pozicije. Zajemanje signalov z enkoderja mora biti nepretrgano, saj je časovno kritično. Čeprav so preklopi mehanskega enkoderja, ki meri premikanje rotacijskega gumba, sorazmerno počasni, ESP32S3 ne sme nobenega od njih spregledati, saj v nasprotnem pride do nekonsistentnega delovanja in v najslabšem primeru tudi do detekcije napačne smeri rotacije, zaradi česar se bo pozicija, npr. znižala, namesto da bi se povečala, ko gumb vrtimo iz leve proti desni.
Da bi slednje preprečili, je dobro programsko kodo za sprejemanje signalov enkoderja realizirati kot programsko nit, na primer takole:
void EncoderTask(void *parameter)
{
esp_task_wdt_delete(xEncoderTask);
while(true){
M5Dial.update();
BR = M5Dial.Encoder.read();
if(BR<0)BR=0; else if(newPosition>100)BR=100;
M5Dial.Encoder.write(BR);
if(BR!=oldBR)oldBR=BR;
vTaskDelay(1);
}
}
Med pregledom programske kode lahko hitro opazimo, da sta spremenljivki BR in oldBR globalni, zato ju lahko beremo tudi iz glavne programske zanke. Neskončna zanka bere pozicijo enkoderja in preverja, če je ta v obsegu med 0 in 100. Vse vrednosti izven obsega pretvori v najbližjo mejno vrednost, 0 ali 100.
Povejmo še, da je pomemben tudi klic funkcije vTaskDelay(1), ki za eno milisekundo preda procesiranje glavni programski niti, saj v nasprotnem ta ne more delovati, kar posledično povzroči neželen ponovni zagon ESP32S3.
Implementacija
Kot vidimo, programiranje uporabniškega grafičnega vmesnika zaradi kopice zmogljivih programskih knjižnic sploh ni zapleteno. Vedeti moramo predvsem, kakšno funkcionalnost potrebujemo in želimo. Če potrebujete le 3 ali 4 tipke in rotacijski gumb, tako kot jaz, potem se res ni treba posebej truditi z meniji, še pa manj iskati programske knjižnice za njihovo implementacijo.
Manjka le še povezava s krmilnikom LED-ic, ki jo lahko realiziramo prek SPI ali I2C. Šlo bi tudi prek zaporednega vmesnika, a bi morali dvigniti napetostne nivoje na +/- 12 V, kar pomeni polna implementacija RS232.
Brezžično komunikacijo, ki je s strojnega vidika najenostavnejša, lahko izvedemo prek Wi-Fi ali Bluetooth. Pri tem moramo M5Dialu zagotoviti le neprekinjeno napajanje: 5 V prek USB-C priključka, ali med +6 V in +36 V prek namenskega priključka, obenem pa je navadno krmilna enota dovolj blizu, oziroma v istem prostoru, da praviloma ne bi smelo prihajati do izpadanja ali motenja povezave.
O implementaciji brezžične povezave smo v preteklem nadaljevanju že veliko povedali. Dodajmo še, da je potrebno za prenos podatkov v krmilnik LED razsvetljave realizirati funkcijo setLEDtrack(f,BR), z dvema parametroma:
f je številka LED traku,
BR pa želena je svetlost vseh LED trakov.
Za prenos krmilnih in povratnih statusnih kod med M5Diali in krmilnikom LED razsvetljave, lahko uporabimo, na primer Bluetooth. Ukaza SerialBT.write() in = SerialBT.read() omogočata brezžični zaporedni prenos podatkov.
Preostane le še definicija komunikacijskega protokola. Primer lahko vidite v preteklem nadaljevanju v SE332.
M5Dial – Digitalna konzola neštetih možnosti
Digitalno krmiljenje LED razsvetljave še zdaleč ni edini projekt, ki se ga lahko lotimo z M5Dial, je pa res, da je napravica prirejena za montažo na zid in zato omogoča različne možnosti pritrditve, še posebej na mesta, kjer smo prej uporabljali klasična mehanska stikala.
V mini seriji M5Dial ste lahko dobili predstavo o tem, kako se lotiti digitalizacije doma na čimbolj prijazen način in kako se elegantno izogniti uporabi nepregledne množice mehanskih stikal, ki obenem zasedajo veliko prostora, a še zdaleč ne morejo ponuditi toliko opcij upravljanja. Prav zato je je del številnih komercialnih paketov za gradnjo LED razsvetljave poleg LED traku, ki ga lahko razrežemo na manjše kose, in napajalnika, tudi (majhen) daljinski upravljalnik. Z M5Dial in krmilnikom LED osvetlitve iz preteklega nadaljevanja ga ne bomo več nujno potrebovali. Pa naj še kdo reče, da M5Dial ni od sile!
Spletna stran: https://pcusbprojects.com
Vstopna