Avtor: mag. Vladimir Mitrović
E-pošta: vmitrovic12@gmail.com
2018_260_45
V preteklem članku smo pojasnili koncept in vsebino programskih knjižnic WS2812B$SE.sub in WS2812Bmaster$SE.sub. Če eno od teh dodamo našemu Bascom-AVR programu, bodo ukazi iz knjižnice omogočili enostavno delo z RGB LED trakovi in prstani na osnovi WS2812B LED čipov.
Na zgornji polovici slike 16 je prikazan osnovni princip povezovanja LED prstanov in trakov na osnovi RGB čipov WS2812B z mikrokontrolerjem. Čeprav napetost napajanja LED traku tipično znaša 5 V, obstaja potreba da ločimo napajanje mikrokontrolerja in LED traku. To pa zato: skozi vsakega od LED pikslov WS2812B čipa pri maksimalni osvetlitvi teče okoli 20 mA, kar nas vodi do porabe do 60 mA na en čip, oziroma do polnih 6 A, če uporabljamo LED trak s 100 RGB čipi. Ker čipi uporabljajo PWM za upravljanje z intenzivnostjo svetilnosti posameznega piksla, se to pozna pri neenakomerni obremenitvi in visokim nivojem motenj, ki so neželene v mikrokontrolerskih vezjih. Na spletu boste našli mnogo nasvetov kako LED trak povezati na ustrezen vir napajanja, npr. na mrežni modul osebnega računalnika. Za napajanje mikrokontrolerja je dovolj “navaden” dobro stabilizirani izvor napajanja.
Ta vsebina je samo za naročnike
Na spodnji polovici slike 16 je prikazano moje testno vezje. Uporabil sem dva LED prstana, manjši s 7 in večji z 12 RGB čipi. Če gledate takšne prstane od blizu, z oddaljenosti okoli 0,5 m, intenzitete večje od 32/255 dajejo premočno svetilnost, ki je neugodna za gledanje. Če se omejimo na intenzitete do 32, maksimalna poraba po RGB čipu ne bo presegla 10 mA, poraba celotnega vezja pa je manjša od 150 mA. V tem primeru skupno napajanje mikrokontrolerja in LED prstana več ne bo predstavljalo problem. Ampak se je pokazala potreba, da uporabimo kondenzator velike kapacitete, ki je spojen paralelno s priključki LED prstana – brez njega so LED-ice neprijetno utripale.
Ko so LED prstani povezani kot na sliki 16, je notranji LED čip prvi v nizu, LED čipi manjšega prstana imajo redne številke 2-7, LED čipi večjega prstana pa 8-19. Če medsebojno zložimo prstane tako, da bodo LED čipi 1, 2 in 8 eden nad drugim, bomo dobili razpored, kot ga vidimo na sliki 17a. Prav za takšno konfiguracijo sem napisal nekaj programskih primerov, ki kažejo princip uporabe ukazov iz knjižnice WS2812B$SE.sub in WS2812Bmaster$SE.sub. Programi so testirani na mikrokontrolerjih ATtiny45, ATtiny4313 in ATmega328P. ATtiny45 je delal z internim oscilatorjem frekvence 8 MHz, medtem ko sem preostala dva testiral s kvarčnimi kristali na frekvencah 6, 8, 10, 12, 16 in 20 MHz in v vseh primerih so delali dobro. Bistveno je, da se uskladi $crystal ukaz Bascom-AVR programa s frekvenco oscilatorja; če so odstopanja večja od 15%, se mikrokontroler in WS2812B ne bosta dobro “razumela” in zato bo barva posameznih LED čipov napačno postavljena ali pa bo komunikacija v popolnosti odpovedala.
Tukaj bomo analizirali samo dele programa, ki se nanašajo na ukaze iz knjižnic; za popolno razumevanje dela je potrebno pogledati celotne programe.
Programi LED_ring_1.bas in LED_ring_2.bas
Namen prvega programa je, da preverimo vse ukaze iz knjižnice WS2812B$SE.sub., v drugem programu pa pokažemo kako doseči enostavne animacije. Na začetku vsakega programa, ki uporabljaWS2812B$SE.sub knjižnico, je najprej potrebno definirati kateri pin mikrokontrolerja bomo uporabili za komunikacije z LED prstani:
Const Led_port = Portb Const Led_pin = 0
V skladu s shemo je za komunikacijo izbran pin PB0. Nato definiramo osnovne parametre LED traku/prstana, kot so trajanje reset impulza in število RGB čipov:
Const Led_reset = 80 Const Led_number = 19
Trajanje reset impulza je postavljeno na 80 µs (mora biti daljši od 50 µs). V mojem testnem vezju imajo LED prstani skupno 19 RGB čipov. V svojem programu boste prilagodili vrednosti lastnim zahtevam, vendar pa morajo konstante zadržati ista imena. Po tem vključujemo programsko knjižnicoWS2812B$SE.sub:
$include "WS2812B$SE.sub"
S tem se bo izbrani komunikacijski pin konfiguriral kot izhodni in se bo postavil v reset stanje, v programu pa se bodo definirale potrebne WS2812B$ konstante in spremenljivke. Sočasno bodo postali dostopni vsi ukazi iz knjižnice, vendar pa bodo kot sestavni del programa postali samo tisti ukazi, ki jih boste uporabljali. Opomba: knjižnica uporablja novi način definiranja podprograma (Config Submode = New), kar je potrebno upoštevati, če se v programu uporabljajo podprogrami iz nekaterih drugih knjižnic ali lastnih podprogramov.
Po vklopu napajanja se bodo RGB čipi postavili v naključna stanja; zato jih bomo najprej ugasnili:
Ws2812b$clear_all Ws2812b$show_all
Opazili boste kako Ws2812b$clear_all, pa tudi vsi drugi ukazi, ki na kateri koli način menjajo stanje enega ali več pikslov to delajo v »sliki« LED prstana ali traku, ki se nahaja v RAM-u mikrokontrolerja. Da bi sprememba postala vidna, jo je potrebno poslati v RGB čipe z nekim show ukazom, v tem primeru je to Ws2812b$show_all.
Zdaj bomo na vseh LED čipih vklopili zelene piksle z intenziteto 16:
For I = 1 To 19 Ws2812b$set_pixel_color I , 16 , 0 , 0 Next
Tudi ta sprememba je vpisana samo v RAM-u mikrokontrolerja, manjka show ukaz, s katerim bi jo prenesli v RGB čipe. V tem primeru želimo, da se postopno vključuje eden po eden RGB čip, zato bomo za prikaz uporabili ukaz, s katerim lahko omejimo število RGB čipov katerim se sporočilo pošilja,Ws2812b$show:
Dim Led_no As Byte ... For Led_no = 0 To 19 Ws2812b$show Led_no Waitms 100 Next
Če želimo LED prstane popolniti z vsebino kot je prikazana na slikah 17b do 17f, lahko to naredimo na nekaj načinov. Najenostavneje je barvo in intenziteto vsakega RGB čipa definirati s posebnim ukazom:
Ws2812b$clear_all Ws2812b$set_pixel_igrb 8 , &HF400 Ws2812b$set_pixel_igrb 9 , &HF310 Ws2812b$set_pixel_igrb 10 , &HF220 Ws2812b$set_pixel_igrb 11 , &HF130 Ws2812b$set_pixel_igrb 12 , &HF040 Ws2812b$set_pixel_igrb 13 , &HF031 Ws2812b$set_pixel_igrb 14 , &HF022 Ws2812b$set_pixel_igrb 15 , &HF013 Ws2812b$set_pixel_igrb 16 , &HF004 Ws2812b$set_pixel_igrb 17 , &HF103 Ws2812b$set_pixel_igrb 18 , &HF202 Ws2812b$set_pixel_igrb 19 , &HF301 Ws2812b$show_all
S to kombinacijo ukazov nastane prikaz s paleto barv prikazan na sliki 17c. Isti efekt dosežemo če barve in intenzitete vpišemo v tabelo, katere vsebino kasneje beremo z Read ukazi:
Dim I As Byte, W As Word ... Ws2812b$clear_all Restore Color_table For I = 8 To 19 Read W Ws2812b$set_pixel_igrb I , W Next Ws2812b$show_all ... Color_table: Data &HF400% Data &HF310% Data &HF220% Data &HF130% Data &HF040% Data &HF031% Data &HF022% Data &HF013% Data &HF004% Data &HF103% Data &HF202% Data &HF301%
Če je odvisnost intenzitete in/ali barve možno računsko povezati z redno številko RGB čipa, delamo definiranje intenziteta in barve v programski zanki. Primer na sliki 17b kaže kako je “gornji” RGB čip (8) ugasnjen in zatem se pomikajoč v smeri gibanja ure, intenziteta vsakega naslednjega RGB čipa povečuje in zadnji čip (19) sveti najmočneje. Programsko to dosežemo tako:
Dim I As Byte Dim R As Byte, G As Byte, B As Byte ... For I = 8 To 19 R = I - 8 G = I - 8 B = I - 8 Ws2812b$set_pixel_color I , G , R , B Next Ws2812b$show_all
Na podoben način lahko dobimo tudi mešanje barv oziroma postopni prehod z ene osnovne barve na drugo. Slika 17d ilustrira mešanje rdeče in zelene barve, kar je programsko možno rešiti tako:
Dim I As Byte, J As Byte Dim R As Byte, G As Byte, B As Byte ... For I = 8 To 19 J = I - 7 R = 12 - J G = J - 1 B = 0 Ws2812b$set_pixel_color I , G , R , B Next Ws2812b$show_all
Slike 17e in 17f kažejo mešanje zelene in modre oziroma modre in rdeče barve. Programska rešitev je enaka predhodnemu primeru, potrebno je samo na ustrezen način zamenjati spremenljivke R, G in B.
Če želite zarotirati nekaterega od prikazov s slike 17, poizkusite tako:
For I = 1 To 24 ' Ws2812b$rotate_ring_cw 8 , 19 Ws2812b$rotate_ring 8 , 19 Ws2812b$show_all Waitms 50 Next
Ta primer bo zavrtel zunanji prstan v smeri gibanja ure za dva polna kroga. Isto v obratni smeri dosežete s sledečo zanko:
For I = 1 To 24 ' Ws2812b$rotate_ring_ccw 8 , 19 Ws2812b$rotate_ring 19 , 9 Ws2812b$show_all Waitms 50 Next
V obeh primerih so zakomentirane alternative ukazov s katerimi dosežete isti efekt.
Že želite doseči vrtenje kjer se hitrost povečuje od mirovanja do neke maksimalne hitrosti, uporabite naslednjo zanko:
Dim I As Byte, J As Byte, W As Word ... I = 64 While I > 1 For J = 1 To 96 Step I Ws2812b$rotate_ring 8 , 19 Ws2812b$show_all W = I * 8 Waitms W Next Shift I , Right Wend
Ker se vrednost spremenljivke I zmanjšuje (postaja pol manjša) v vsakem prehodu skozi While-Wend zanko, postanek na določeni poziciji postaja pol krajši in s tem se hitrost rotacije poveča za dvakrat. Postopno upočasnjevanje rotacije od maksimalne hitrosti do stanja mirovanja dosežemo s podobno logiko, samo se zdaj vrednost spremenljivke I, in s tem postanek na določeni poziciji z vsakim prehodom skozi While-Wend zanko podvoji:
I = 1 While I < 128 For J = 1 To 96 Step I Ws2812b$rotate_ring 8 , 19 Ws2812b$show_all W = I * 8 Waitms W Next Shift I , Left Wend
Enak učinek s postopnim povečevanjem hitrosti in upočasnjevanjem rotacije v nasprotni smeri dobimo, če zamenjamo razpored parametrov v ukazu za rotacijo:
Ws2812b$rotate_ring 19 , 8
Ostali ukazi v zankah ostajajo enaki.
Program LED_ring_2.bas vsebuje še en interesanten efekt, “zvezdno nebo”. V njemu se barve in intenzitete RGB čipov naključno določajo z Bascom-AVR Rnd() funkcijo:
Dim Cnt As Word ... Cnt = 0 Ws2812b$clear_all Do I = Rnd(19) I = I * 3 Ws2812b$led(i + 1) = Rnd(19) Ws2812b$led(i + 2) = Rnd(19) Ws2812b$led(i + 3) = Rnd(19) Ws2812b$show_all Waitms 12 Incr Cnt Loop Until Cnt >= 1200
Rnd(19) generira naključno številko v razponu od 0-18. To številko uporabimo kot intenziteto zelenega, rdečega in modrega piksla izbranega RGB čipa. RGB čipe prav tako slučajno izbiramo s pomočjo iste funkcije. Primer tudi kaže, kako tekočo številko preračunavamo v naslov piksla in kako intenziteto nekega piksla vpisujemo direktno v Ws2812b$led niz, brez uporabe ukazov Ws2812b$set_pixel_color ali Ws2812b$set_pixel_igrb. Namen števca Cnt je omejitev trajanja zanke; v tem primeru bo zvezdno nebo utripalo 12*1200 ms, tj. okoli 14 s.
Programi LED_ring_3_master.bas in LED_ring_3_slave.bas
Prej smo omenili kako je točen timing krmilnih signalov WS2812B čipa ključen za pravilno komunikacijo, zaradi česar ukazaWs2812b$show in Ws2812b$show_all med svojim izvajanjem onemogočata izvrševanje prekinitev. Če ima program mikrokontrolerja neke aktivnosti vezane na prekinitve, lahko to predstavlja problem. V takšnem primeru je priporočljivo uporabiti master-slave konfiguracijo (slike 18 in 19).
V master-slave konfiguraciji “mali” mikrokontroler (v mojem primeru je to ATtiny45), je slave, krmili del LED prstana ali traku z uporabo knjižnice WS2812B$SE. “Veliki” mikrokontroler (v mojem primeru je to ATtiny4313), je master, ki uporablja knjižnico WS2812Bmaster$SE in pošilja navodila slave mikrokontrolerju katere ukaze naj izvrši. Komunikacija med mikrokontrolerji se odvija s posredovanjem data, clock in sync signala. Kadar želi poslati ukaz in pripadajoče podatke (parametre tega ukaza), master prične proizvajati clock impulze frekvence okoli 50 kHz in sinhrono z njimi pošilja bit po bit bodisi za ukaz ali podatek po data liniji. Slave prebere data linijo na padajočem robu clock impulza in po prvih 8 bitih analizira sprejeti ukaz. Tako ugotovi koliko parametrov še mora prejeti od master mikrokontrolerja. Ko je sprejel ukaz in pripadajoče parametre, ga slave izvrši in nato je pripravljen za sprejem naslednjega ukaza.
Postopek je sinhroniziran s pomočjo sync linije. Ko je pripravljen za prevzem novega ukaza ali podatka, slave postavi sync pin v stanje “1”; dokler je zaseden s sprejemom in analizo ali pač z izvajanjem ukaza, slave drži sync pin v stanju “0”. Ws2812b$send ukaz iz WS2812Bmaster$SE.sub knjižnice preverja stanje sync linije in bo začel pošiljati novi podatek šele takrat, ko bo slave javil, da je pripravljen. Pomembno je opomniti, da je postopek prenosa podatkov v popolnosti sinhroniziran s clock impulzi, ki jih generira master; tudi takrat, kadar je program v master-ju zelo obremenjen s prekinitvami in je perioda clock impulza spremenljiva, hitrost komunikacije bo zmanjšana, vendar se ne bo zrušila kvaliteta prenesene informacije.
Naj pojasnim še »skupni« reset master in slave mikrokontrolerja, na shemi s slike 18 prikazan s pikčasto črto. Po vklopu napetosti napajanja, časovne konstante v obeh programih so nastavljene tako da se komunikacija lahko pravilno vzpostavi. Če obstaja potreba, da bi resetirali enega od mikrokontrolerjev, je v tem primeru potrebno sočasno resetirati oba – v nasprotnem primeru se bo izgubil del prvega sporočila, ki ga master pošilja slave mikrokontrolerju.
Na začetku master programa je nujno definirati, katere pine bomo uporabljali za komunikacijo s slave mikrokontrolerjem:
Const Data_port = Portb Const Data_pin = 1 Const Clock_port = Portb Const Clock_pin = 2 Const Sync_port = Portb Const Sync_pin = 3
Navedeni podatki ustrezajo shemi s slike 18. Master-ju ni potrebno definirati povezave z RGB prstanom ali trakom, ker on z njima direktno niti ne komunicira.
Sledi vklop WS2812Bmaster$SE.sub knjižnice:
$include "WS2812Bmaster$SE.sub"
Tako master programu postanejo dostopni vsi ukazi iz knjižnice. Sočasno se konfigurirajo predhodno definirani komunikacijski pini za slave mikrokontroler in se postavijo v začetno stanje. Opomba: tudi ta knjižnica uporablja novi način definiranja podprogramov (Config Submode = New) in to moramo upoštevati če se v programu uporabljajo podprogrami iz nekih drugih knjižnic ali lastne podprograme.
Po vklopuWS2812Bmaster$SE.sub knjižnice program master mikrokontrolerja lahko uporablja iste Ws2812b$ ukaze (in na isti način) kot v predhodno analiziranih programih. Ker pa gre za drugo knjižnico, se ukazi obnašajo drugače: ukazi se ne bodo dejansko izvrševali v master programu, pač pa bodo skupaj s pripadajočimi parametri samo posredovali slave mikrokontrolerju. S tem program postaje krajši in se tako, npr. v programu LED_ring_3_master.bas nahajajo vsa preverjanja in animacije iz obeh predhodnih programov.
Na začetku slave programa je potrebno definirati, kateri pin se bo uporabljal za komunikacijo z LED prstanom/trakom, kot tudi osnovne parametre prstana/traku:
Const Led_port = Portb Const Led_pin = 0 Const Led_reset = 80 Const Led_number = 19
Nato definiramo pine, ki jih bomo uporabljali za komunikacijo z master-jem:
Const Data_port = Portb Const Data_pin = 1 Const Clock_port = Portb Const Clock_pin = 2 Const Sync_port = Portb Const Sync_pin = 3
Z vklopom WS2812B$SE.sub knjižnice,
$include "WS2812B$SE.sub"
se bo naredilo vse kot v preteklih primerih. Naslednji ukaz je klic makro definicije iz knjižnice, in to je hkrati tudi konec programa:
Ws2812b$receive&Execute End
Makro ukaz Ws2812b$receive&Execute je ključen; ukaz generira celotno potrebno kodo za prevzem in obdelavo podatkov z master mikrokontrolerja in izvršuje ustrezne ukaze WS2812B$SE.sub knjižnice. Kako to dejansko izgleda poglejte v programu LED_ring_3_slave.bas. Program ni veliko večji od tega, ki smo ga videli v analizi!
V master-slave konfiguraciji s slike 18 lahko uporabljate tudi druge mikrokontrolerje. Izbira master-ja je odvisna od kompleksnosti njegovega programa. Izbira slave mikrokontrolerja je odvisna izključno od števila RGB čipov prstana/traku. ATtiny45 bo ustrezen v konfiguracijah do 42 RGB čipov; za konfiguracije do 128 RGB čipov je potrebno vzeti ATtiny85, za večje pa AVR z 1 kB RAMa. Naj spomnim, da je največje število RGB čipov, ki ga programske knjižnice podpirajo, 255 čipov.
Vse to o čemer smo pisali je, seveda samo začetek. Efekti ki jih lahko realizirate z RGB LED trakovi in prstani so zelo raznovrstni in so odvisni samo od vaše domišljije – naj vam ukazi iz WS2812B knjižnic dobro služijo, da boste lažje realizirali svoje ideje!
Opomba: WS2812B$SE.sub in WS2812Bmaster$SE.sub knjižnice, kot tudi vse omenjene testne programe, lahko brezplačno dobite v uredništvu revije Svet elektronike.Barduino (6)