Prostota jest ostateczną formą wyrafinowania.
🙂 ot wynalazek – w strukturę LED 5050 „zatopiono” specjalizowany sterownik PWM dla wygody i prostoty sterowania. Brzmi groźnie lecz do sterowania niezbędny jest jeden pin µC i „trochę” kodu … w dodatku LED może „sterować” kolejnym LED-em … Jest to niebywała zaleta.
Od pewnego czasu przyglądam się nowalijkom w postaci sterowników LED lub diodom świecącym pod intrygującą nazwą DIGI LED. Innowacyjność rozwiązania polega na sterowaniu zwykłej diody RGB jedną linią danych. Czyli z pojedynczego elementu (diody RGB) wychodzą 3 wyprowadzenia, zasilanie masa i sterowanie wszystkimi kolorami oraz dodatkowo intensywnością świecenia poszczególnych barw indywidualnie. Niebywałą zaletą jest również to że każdy taki element może być łączony w szeregu z kolejnym. Skutkiem tego powstaje taśma LED RGB z możliwością sterowania każdego elementu indywidualnie. Producentem tych wynalazków jest firma Worldsemi. W moje łapki wpadły następujące produkty: dioda LED ze zintegrowanym sterownikiem WS2812B, układ scalony WS2811, oraz moduły z nim, i moduł z WS2801. Różnorodność asortymentu spowodowana moją ciekawością 😉
Rozwiązanie spodobało mi się i chciałem je wypróbować w aktualnie opracowywanym projekcie sterownik łazienkowy do bojlera, ogrzewania i wentylacji jako LED podświetlający wyświetlacz, dodatkowo sygnalizujący kolorem różne zdarzenia. Ponieważ µC ma skończoną ilość wyprowadzeń zdecydowałem się na zakup tego niedrogiego wynalazku w postaci WS2812B, i przy okazji innych. ;-p Przeglądając notę katalogową i wykresy czasowe stwierdziłem że niema się czego bać ;-d i sprawa wydaje się dość oczywista. Dane wysyła się szeregowo, do sterownika w diodzie, który je stosownie interpretuje i pogania LEDa do pracy. To co wydało mi się istotne to proporcja stanu wysokiego do niskiego dla interpretowanej jedynki i zera logicznego. Ochoczo zabrałem się do pracy kombinując co zrobić żeby się nie narobić … Zacząłem szczegółowo przyglądać się nocie … obrazek z timmingiem jest bardzo wymowny ale ważniejsza część do jego opisu jest na stronie poprzedniej ;-p i TRZEBA ją brać pod uwagęTrzeba być na tyle rozgarniętym aby połączyć wszystkie te dane w „kupę” i wtedy otwierają się szeroko oczy … wymagane jest odmierzenie czasu 400ns 😯 Biorąc pod uwagę iż µC standardowo nie pędzę szybciej niż 8MHz bo i po co poprzeczka idzie w górę ;-d Takkk w takim przypadku jeden takt zegarowy trwa 0,000000125s (1s / 8000000), czyli 125ns, a zrobienie jeszcze czegokolwiek nawet dla RISC-a może być niezłym wyzwaniem – choć chyba większym dla programisty w Bascom 😉 A tu trzeba generować fale prostokątną uzależnioną od obrabianych danych …
Na wstępie zabrałem się ochoczo do kombinowania, bez liczenia czegokolwiek … obrazki czytam ze zrozumieniem a tekst …. hehehehee czasem przeszkadza. 😉 Ponieważ dioda mnie najwyraźniej ignorowała trzeba było zacząć czytać tę literaturę piękną. Powstał zaczątek kodu i zacząłem „podziwiać” przebiegi czasowe. Na załączonych obrazkach można obejrzeć co udało się wygenerować … po przejściu na sprzęt z rezonatorem kwarcowym 16MHz. Przebieg ma częstotliwość zbliżoną do 180kHz. Poszczególne stany wysokie mieszczą się w zadanych kryteriach tj. 400ns i 800ns z zadaną tolerancją ±150ns. natomiast poszczególne stany niskie są dalekie od ideału – nawet bardzo ;-d niemniej sterownikowi to nie przeszkadza bo dioda funkcjonuje znakomicie.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
$regfile = "m328pdef.dat" $crystal = 16000000 Config Submode = New 'nowy tryb deklaracji procedur Config Portb.5 = 1 'status LED Config Portd.3 = 1 'WS2812B LED-IC Config Portd.4 = 0 'guzik 'pin dla wejścia, port dla wyjścia Reset Pind.3 Set Portd.4 Const Full = 255 Const Middle = 128 Const Lovv = 10 Const Offf = 0 'Config Serialout1 = Buffered , Size = 72 Sub Wyslij(byval Kolorek As Byte) For I = 0 To 7 'Step -1 If Kolorek.i = 1 Then Rcall Jeden Else Rcall Zero End If Next I End Sub Dim Klik As Bit, Kolor As Byte, I As Byte '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Set Portb.5 Waitms 500 Reset Portb.5 $baud = 9600 Print "puk puk ;-)" Do Waitms 100 Klik = Pind.4 Select Case Kolor Case 0: Green = Full Red = Full Blue = Full Case 1: Green = Full Red = Offf Blue = Offf Case 2: Green = Offf Red = Offf Blue = Full Case 3: Green = Offf ' High Red = Full Blue = Offf Case 4: Green = Middle Red = Middle Blue = Middle Case 5: Green = Offf Red = Offf Blue = Offf End Select If Klik = 0 Then Print "klik" Incr Kolor If Kolor = 6 Then Kolor = 0 Toggle Portb.5 Call Wyslij(green) Call Wyslij(red) Call Wyslij(blue) End If Loop End Zero: sbi PORTd,3 Nop nop nop nop cbi PORTd,3 'stan niski ' nop ' nop 'nop ' Nop ' nop ' nop Ret Jeden: sbi portd,3 'stan wysoki nop nop nop nop nop nop nop nop nop nop cbi portd,3 'stan niski ' nop ' nop ' nop Ret |
Do tych 800Kbps z noty katalogowej daleko 😉 ale co mnie tam trzeba do jednego LEDa … Niemniej zacząłem się zastanawiać jak wycisnąć więcej … w tym celu powstał podobny kod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
$regfile = "m328pdef.dat" $crystal = 16000000 Config Submode = New 'nowy tryb deklaracji procedur Config Portb.5 = 1 'status LED Config Portd.3 = 1 'WS2812B LED-IC Config Portd.4 = 0 'guzik 'pin dla wejścia, port dla wyjścia Reset Pind.3 Set Portd.4 Const Full = 255 Const Middle = 128 Const Lovv = 10 Const Offf = 0 'Config Serialout1 = Buffered , Size = 72 Dim Klik As Bit, Kolor As Byte, I As Byte '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Set Portb.5 Waitms 500 Reset Portb.5 $baud = 9600 Print "puk puk ;-)" Do Waitms 100 Klik = Pind.4 Select Case Kolor Case 0: Green = Full Red = Full Blue = Full Case 1: Green = Full Red = Offf Blue = Offf Case 2: Green = Offf Red = Offf Blue = Full Case 3: Green = Offf ' High Red = Full Blue = Offf Case 4: Green = Middle Red = Middle Blue = Middle Case 5: Green = Offf Red = Offf Blue = Offf End Select If Klik = 0 Then Print "klik" Incr Kolor If Kolor = 6 Then Kolor = 0 Toggle Portb.5 I = Green And 128 If I = 0 Then Rcall Zero Else Rcall Jeden I = Green And 164 If I = 0 Then Rcall Zero Else Rcall Jeden I = Green And 32 If I = 0 Then Rcall Zero Else Rcall Jeden I = Green And 16 If I = 0 Then Rcall Zero Else Rcall Jeden I = Green And 8 If I = 0 Then Rcall Zero Else Rcall Jeden I = Green And 4 If I = 0 Then Rcall Zero Else Rcall Jeden I = Green And 2 If I = 0 Then Rcall Zero Else Rcall Jeden I = Green And 1 If I = 0 Then Rcall Zero Else Rcall Jeden I = Red And 128 If I = 0 Then Rcall Zero Else Rcall Jeden I = Red And 164 If I = 0 Then Rcall Zero Else Rcall Jeden I = Red And 32 If I = 0 Then Rcall Zero Else Rcall Jeden I = Red And 16 If I = 0 Then Rcall Zero Else Rcall Jeden I = Red And 8 If I = 0 Then Rcall Zero Else Rcall Jeden I = Red And 4 If I = 0 Then Rcall Zero Else Rcall Jeden I = Red And 2 If I = 0 Then Rcall Zero Else Rcall Jeden I = Red And 1 If I = 0 Then Rcall Zero Else Rcall Jeden I = Blue And 128 If I = 0 Then Rcall Zero Else Rcall Jeden I = Blue And 164 If I = 0 Then Rcall Zero Else Rcall Jeden I = Blue And 32 If I = 0 Then Rcall Zero Else Rcall Jeden I = Blue And 16 If I = 0 Then Rcall Zero Else Rcall Jeden I = Blue And 8 If I = 0 Then Rcall Zero Else Rcall Jeden I = Blue And 4 If I = 0 Then Rcall Zero Else Rcall Jeden I = Blue And 2 If I = 0 Then Rcall Zero Else Rcall Jeden I = Blue And 1 If I = 0 Then Rcall Zero Else Rcall Jeden End If Loop End Zero: sbi PORTd,3 Nop nop nop nop cbi PORTd,3 'stan niski ' nop ' nop 'nop ' Nop ' nop ' nop Ret Jeden: sbi portd,3 'stan wysoki nop nop nop nop nop nop nop nop nop nop cbi portd,3 'stan niski ' nop ' nop ' nop Ret |
bez procedury i pętli. Po kompilacji zeżarło 1468 bajtów, ten pierwszy dla porównania 866 ;-d Przyrost wydajności w szybkości wykonywania nieporównywalny … jak i objętość wygenerowanego kodu hehehee.
Częstotliwość przebiegu ~444kHz – więc różnica kolosalna. Osiągnięty efekt był bardzo dużym pozytywnym zaskoczeniem dla mnie. Odpowiednią ilością instrukcji NOP można wydłużać lub skracać czas stanu wysokiego przebiegu. Stan niski nie wymaga korekty i zależny jest głównie od pozostałych instrukcji wykonywanych przez µC, co zresztą dokładnie widać po moich doświadczeniach.
Element który posiadam – WS2812B ma braciszka WS2812 moim zdaniem starszego. W „moim” elemencie, uważam, że zostały ujednolicone czasy interpretowanego przebiegu, co wypadło bardzo pozytywnie. Stosując przebiegi dla WS2812B ten drugi – WS2812 też powinien działać bezproblemowo pomimo nieznacznych różnic, które mieszczą się w określonej tolerancji. Diody świecą BARDZO jasno w pełnym wysterowaniu. Więcej istotnych informacji można wyczytać w notce, co bardzo polecam uczynić! Tak że praktycznie opracowany kod dla jednego powinien też być prawidłowo interpretowany przez drugi. Szczegóły można pooglądać w notach katalogowych które załączam.
Od czasu gdy zacząłem „produkować” ten „poradnik ” minęło już ze dwa tygodnie (dziś jest 2014-08-25), a ja jestem bogatszy w doświadczenia. Wiem iż notka katalogowa zawiera jedną nieścisłość … o tutaj zaznaczyłem czerwonym kolorem
mogę powiedzieć, że sytuacja taka przytrafiła mi się i element przestał funkcjonować – LED jest jak się to mówi sztywny i zimny ;-D. Tak że przy podłączaniu trzeba zachować szczególną ostrożność, jak z resztą zawsze. Dodatkowo powiem, iż się uparłem i postanowiłem się sprawdzić. Test polegał na uruchomieniu prawidłowej komunikacji elementu WS2812B z µC gonionym generatorem wewnętrznym 8MHz i oprogramowanym w Bascom AVR. Powiem tyle DA SIĘ 😉 – z mojej strony okupione to było długim ślęczeniem ale cel został osiągnięty. Oto przykład prawidłowo działającej komunikacji choć nie w 100%, od czasu do czasu przytrafi się że LED „nie skuma” przebiegu prostokątnego z tytułu małych rozbieżności czasowych. Na moje potrzeby do wysterowania jednej sztuki wystarczy. Jeśli kiedyś zechcę wysterować większą ilość takich LEDów – żegnaj rezonatorze 8MHz.
oraz przykład kolejny gdzie układ w ogóle nie wie o co sterującemu µC chodzi 😉 Może to objawiać się podobnym efektem:
Cała sztuczka polega na tym, aby sygnał miał odpowiednie proporcje T0H do T1H i mieścił się w określonym kryterium, co do częstotliwości to zauważyłem zupełną dowolność. Moim zdaniem czasy T0L i T1L nie są jakieś krytyczne i w moim przypadku bardzo się rozciągały, co nie przeszkadzało elementowi WS2812B w zrozumieniu transmisji. Największą uwagę trzeba skupić na odpowiednich proporcjach TH0 do TH1 i czasach ich trwania, jak przytaczam to wcześniej, aby komunikacja była efektowna.
Zastanawiam się czy gdybym wewnętrzny generator RC zastąpił rezonatorem kwarcowym o tej samej częstotliwości (8MHz) czy jakość transmisji nie uległa by poprawie …. Ale niech to pozostanie niewiadomą 😉
Bardzo istotnym faktem jest to, że w trakcie transmisji do WS2812B nie powinny odbywać się inne czynności, a ta powinna trwać NIEPRZERWANIE do samego końca. Więc proponuję zalążek algorytmu: tworzymy bufor dla wszystkich LED, w którym program robi sobie co chce (ustawia kolorki), a co jakiś czas wypychamy te dane do LEDów. W trakcie tego wypychania nikt i nic nie ma dostępu do bufora, i nie dzieje się nic innego. Wtedy będzie 100% skuteczność sterowania, a LEDy będą mrugały tak jak się tego spodziewa programista.
A.D. 2015-10-10 Jakby kto nie wiedział powstała biblioteka do obsługi tego specyfiku. Również od pewnego czasu środowisko Bascom AVR ma zaimplementowaną obsługę digiled.
A.D. 2017-02-06 Powstał kolejny opis dla równie ciekawego sterownika WS2801.
nota katalogowa
WS2812B.pdf (7452 pobrania )
nota katalogowa
WS2812.pdf (4548 pobrań )
nota katalogowa
WS2811.pdf (3486 pobrań )
nota katalogowa
WS2801.pdf (3555 pobrań )
Hej, masz babola powtórzonego trzy razy w programie, jest:
I = Blue And 164
Winno być:
I = Blue And 64
Pozdrawiam!
😉
Miałem napisać, że choć jeden czytelnik się przytrafił co bezmyślnie nie kopiuje i wkleja, ale tego nie zrobię…
Brawo za spostrzegawczość, oczywiście nie poprawię bo Twoja uwaga była by nie na miejscu.
Jak najbardziej masz rację i ma być 64 i tak mam w środowisku IDE 😀
Niedługo zmierzę się z tymi diodami, spotkałem się z opiniami że MEGA nie da rady ale wogóle się tym nie przejmuję. Zamierzam wykorzystać SPI do transmisji danych do diód, jedynka w formie 1110 i zero w formie 1000. Trzeba będzie zadbać o odpowiednio szybkie wpisywanie danych, mam nadzieję że interfejs diód odporny jest na drobne przerwy w transmisji chociaż wolałbym go nie testować w tej roli. Na Aliexpress są fajne paski z tymi diodami. Pozdrawiam!
Opinie opiniami – dużo zależy od tego jak kto podchodzi do programowania czy też „pisania programu”. Ja mogę tylko tyle powiedzieć, że zadałem sobie trud by tą obsługę odpalić na rezonatorze 8MHz – z powodzeniem. Lecz nie testowałem na większej ilości LEDów. Moje końcowe uwagi mogą być bardzo przydatne w rozgryzaniu i oprogramowaniu komunikacji – możesz dzięki nim zaoszczędzić wiele czasu na testach. Chętnie obejrzałbym końcowy efekt Twojej pracy.
I pierwszy i drugi kod jest niepełny i zawiera błędy. Nie wiem po co coś takiego publikować.
Na dziś dzień jest to wspomnienie majsterkowania. Moje stanowisko co do małego psikusa (nazwałeś go błędem) przedstawione jest powyżej.
Jak dobrze wiesz od tamtego czasu powstała biblioteka do obsługi tych elementów, a nowsza wersja środowiska IDE (2079) jest już wyposażona w wersję biblioteki firmowaną przez MCS.
Potrzebujesz pomocy w czymś?