Przejdź do głównej zawartości

Programowanie AVR cz. ostatnia: Wyświetlacz 3D (LED Cube) 4x4x4 - ciekawy wizualnie, modny gadżet z ogromnymi możliwościami.

Pora kończyć cykl wpisów dydaktyczno-eksperymentalnych na temat programowania AVR-ów. Koniec jednak powinien być mocny. No to będzie.

Przed Wami oto:
Wyświetlacz 3D, czyli LED Cube, o rozmiarach 4 x 4 x 4.


000. Pomysł


Kostką diod LED, sterowaną dowolnym mikrokontrolerem, zainteresował mnie parę lat temu jeden z absolwentów. Było to jeszcze w czasie, gdy mój powrót do lutownicy nie był praktycznie brany pod uwagę - zajmowałem się wyłącznie softwarem, a programowania mikrokontrolerów uczyłem z wykorzystaniem gotowych, zamkniętych zestawów (DSM-51 - fajnie pomyślana i zrobiona rzecz, niestety bazująca na lekko przestarzałej i przez wielu krytykowanej technologii). Gdy w zeszłym roku zająłem się AVR-ami pomyślałem sobie - czemu nie? Przejrzałem kilka rozwiązań, przyglądnąłem się możliwościom różnych mikrokontrolerów i... znalazłem coś odpowiedniego dla siebie.
Czym właściwie jest popularny LED Cube, lub też wyświetlacz LED 3D? Otóż jest to eleganckie i efekciarskie urządzonko pozwalające na prezentację kształtów geometrycznych oraz - co najważniejsze - animacji w rzeczywistym 3D. Taką kostkę możemy obejść dookoła i za każdym razem zobaczymy obraz z innej perspektywy. Gdyby zbudować taką kostkę z 8*10^9 diod LED RGB, to mielibyśmy wtedy dopiero prawdziwy obraz trójwymiarowy - i to w dodatku w HD! Problem w tym, że gabaryty byłyby nieco większe, niż w przypadku klasycznego telewizora LCD/OLED/Plasma z czterdziestocalową przekątną ekranu. Ale za to obraz byłby prawdziwie trójwymiarowy, a nie prezentowany w rzucie, jak to ma miejsce w przypadku gier komputerowych czy filmów. W grach, owszem, grafika tworzona jest tak, jakby miała być prezentowana za pomocą prawdziwego ekranu 3D, ale potem wykonywany jest szereg operacji przygotowujących obraz do pokazania na... płaskim ekranie...
Do czego może taki LED-owy wyświetlacz 3D służyć, czy też gdzie znajdzie zastosowanie? Pomijając jego gadżetowość, póki co - choćby ze względu na koszta i gabaryty tych dużych wyświetlaczy (prezentowany tutaj to zabawka w porównaniu z niektórymi super-projektami) - w reklamie, rozrywce, nowoczesnej dekoracji...
Dla mnie osobiście jest to wyłącznie zabawka - ot na przykład do wymyślania kolejnych ciekawych (?) animacji.

001. Inspiracje


Jak wspomniałem, zanim zrobiłem własną kostkę, przejrzałem parę rozwiązań. Wszystkie były ciekawe, choć niektóre niepotrzebnie skomplikowane - złożony sterownik przy niewielkim rozmiarze fizycznym kostki. Postawiłem na najprostsze moim zdaniem rozwiązanie (uwielbiam takie - bez zbędnych kombinacji), wymagające dwóch układów scalonych, kilkunastu rezystorów, kilku kondensatorów i 64 diod świecących.
Rozwiązaniem, na którym bazowałem, był projekt prezentowany w serwisie Instructables - możecie go obejrzeć pod tym adresem: http://www.instructables.com/id/LED-Cube-4x4x4/

002. Projekt


Matrycę (kostkę) LED wykonałem zgodnie z opisem w linkowanym wcześniej artykule - moje rozwiązanie również bazuje na multipleksowaniu, dlatego też kostka jest podzielona na cztery płaszczyzny (warstwy) i szesnaście kolumn. Jedna płaszczyzna obejmuje 16 diod LED połączonych katodami, zaś w kolumnie są cztery diody połączone anodami. Podłączenie wyprowadzenia danej warstwy (czyli połączonych katod) do masy (podanie stanu niskiego) i jednocześnie podanie stanu wysokiego na wybraną kolumnę (anodę) spowoduje zapalenie się diody znajdującej się na przecięciu warstwy z kolumną.
Rolę sterownika pełni mikrokontroler ATmega 48P (to praktycznie ten sam układ, co w Arduino Uno, z tym, że 48P ma tylko 4kB pamięci flash, co w przypadku kostki stanowi wystarczającą ilość), taktowany zegarem wewnętrznym 8MHz - zdecydowałem się na to, ponieważ zależało mi, żeby ATmega miała wolne dwa pełne osmiobitowe porty wejścia-wyjścia. A przy tego typu projektach stabilność generatora nie jest najważniejsza. Porty B i D ATmegi zasilają kolumny kostki, czyli domyślnie ustawione są w stanie niski, a sterowanie odbywa się poprzez podawanie jedynek logicznych na poszczególne linie portów. Który port steruje którymi kolumnami - wyjaśnione zostało schematycznie w komentarzu do przykładowego programu (patrz dalej). Kolumny diod LED podłączone są do wyprowadzeń portów B i D poprzez rezystory 220Ω. Warstwy, czyli katody, sterowane są za pomocą drivera ULN2803A (podawany jest na wybraną warstwę stan niski) i tutaj pojawia się multipleksowanie.
Multipleksowanie realizowane jest w dosyć prosty sposób. Otóż programowy licznik pierścieniowy, operujący na młodszej połówce portu C (wyprowadzenia te sterują ULN-em), wybiera w określonych odstępach czasu (posługuję się timerem sprzętowym, który zgłasza przerwanie co ok. 2ms) kolejne warstwy, podczas gdy główna część programu "dba" o wyprowadzenie na porty B i D właściwych danych (klatki animacji).

Oto schemat sterownika (tym razem zadziałałem we Fritzingu - gdyby schemat był bardzo nieczytelny, obiecuję przygotować normalny w Eagle'u) z wykazem elementów:

Po zakończeniu prac projektowych zostały dwa wolne wyprowadzenia portu C, szczęśliwie będące przy okazji wyprowadzeniami przetwornika analogowo-cyfrowego, dlatego też można je wykorzystać do ciekawej rozbudowy sterownika lub po prostu do podłączenia modułów sterowania za pomocą sygnału analogowego (wzmacniacz mikrofonowy i ciekawy program mogą dać nieziemskie efekty ;)). W wersji końcowej wyposażyłem układ w goldpiny udostępniające w łatwy sposób te dwie linie (plus jeden goldpin na masę).
Warto również przewidzieć gniazdko na podłączenie do ATmegi programatora w celu wgrywania efektów (programów) - projekt jest do tego stopnia uproszczony, że nie zaimplementowałem możliwości wgrywania czystych efektów. Wyprowadziłem za to na niezastąpionych goldpinach gniazdo dla programatora - można wgrywać pełne programy z efektami, bazujące choćby na przedstawionym niżej przykładzie. Lub napisane w języku C, nie wiem jednak, czy najprostszy efekt, przepuszczony przez GCC, zmieści się w czterokilobajtowej pamięci programu...
W każdym razie możliwość wymiany całego oprogramowania wydaje mi się rozwiązaniem dużo lepszym, ciekawszym.

A oto kod źródłowy przykładowego programu. Myślę, że jest wystarczająco zrozumiały nawet dla początkujących:

W trakcie rozwoju projektu i programu szybko okazało się, że przeznaczona na dane wbudowana pamięć EEPROM ma zbyt małą pojemność, dlatego linie zawierające definicje efektów i animacji zostały umieszczone we flashu.

Jeszcze kilka słów na temat struktury animacji.
Prezentowany sterownik może wyświetlać efekty uzyskane na dwa sposoby. Pierwszy z nich to coś, co popularnie nazywamy "renderem", czyli napisanie kodu generującego dany efekt. W zależności od stopnia skomplikowania, może to być nie lada wyzwanie.
Drugi sposób to przygotowanie swego rodzaju mapy bitowej (patrz: linie Data w kodzie źródłowym), znając sposób wyświetlania obrazu.
Każdy efekt składa się z animacji, która podzielona jest na klatki, a te podzielone są na warstwy. Warstwa to - jak się domyślacie biorąc pod uwagę wcześniejszy opis - 1/4 klatki. W danym momencie wyświetlana jest tylko jedna warstwa (w przypadku pesymistycznym świeci na raz 16 diod). Warstwy zmieniane są w równych odstępach czasu, generowanych przez timer. Program główny decyduje o czasie wyświetlania danej klatki, ładując do specjalnej tablicy roboczej dane z odpowiadającej pojedynczej klatce linii Data. Animacja może się składać z dowolnej liczby klatek.
Struktura linii Data jest prosta: jedna linia to jedna klatka, w której zdefiniowane są cztery warstwy (od góry wyświetlacza do dołu), czyli cztery pary bajtów w kolejności: port B, port D. Proste? Chyba prościej się nie da :)
Żeby stworzyć nowy efekt trzeba po prostu złapać kartkę papieru i sobie trochę pogłówkować... Lub poczekać, aż znajdę odrobinę czasu i napiszę planowany od początku projektu, klikany program do definiowania efektów.

003. Prototyp


Teraz już z górki.
Prototyp sterownika zmontowałem na dużej płytce stykowej (patrz: zdjęcia). Największym jednak wyzwaniem, jak mi się początkowo wydawało, było zlutowanie matrycy trójwymiarowej diod LED. Zastosowałem metodę przedstawioną we wspomnianym wcześniej artykule (deseczka z otworami i montowanie warstw po kolei). Niestety, diody, których użyłem do konstrukcji matrycy, miały krótsze niż zwykle wyprowadzenia, dlatego odstępy między pojedynczymi LED-ami wyniosły około 1,5 cm, co trochę zmniejszyło ogólny gabaryt kostki. Później pożałowałem też trochę, że LED-y nie są niebieskie, ale na tych żółto-pomarańczowych też na szczęście uzyskałem przyjemny efekt wizualny.

Prototyp na płytce stykowej:



I matryca diod z podłączeniem do kontrolera:


Nie obyło się oczywiście bez testów. Na szczęście staram się dosyć precyzyjnie podchodzić do elektronicznych zabawek, dzięki czemu projekt ruszył od "pierwszego kopa". Warto poświęcić trochę więcej czasu na staranny montaż - dotyczy to zarówno prototypowania, jak i przygotowania urządzenia w wersji finalnej.

004. Gotowe urządzenie


Po zmontowaniu na płytce uniwersalnej (wraz ze wspomnianymi wcześniej dodatkowymi wyprowadzeniami dla programatora i przetworników AD) oraz umieszczeniu wszystkiego na gustownie przyciętej sklejce z filcowymi nóżkami, efekt końcowy przedstawia się elegancko (w geekowsko-nerdowskim tego słowa znaczeniu - druty rządzą ;)):




006. Podsumowanie


Oczywiście przedstawiony projekt jest tylko moją własną wariacją na popularny temat. Można go wykonać w całkowicie inny sposób - poguglacie i znajdziecie kilka niezłych rozwiązań.
Powiem więcej - całość można sterować nawet za pomocą pogardzanego przez wielu (bo programy w C się w nim nie mieszczą...;-)), malutkiego ATtiny 2313. Wystarczy przecież jeden port ośmiobitowy, jeden czterobitowy i jedno wyprowadzenie do sterowania zatrzaskiem. Być może całość będzie działała odrobinę wolniej, ale będzie to faktycznie zaledwie odrobina... I można będzie zastosować kwarc np. 16MHz, jeśli kogoś rajcują wyższe częstotliwości ;-)
Wracając jednak do ATmegi i mojego rozwiązania, jedyną wadą w tym projekcie może się wydawać zastosowanie dosyć w sumie wolnego drivera ULN2803A, który przy szybszych animacjach może nie dawać rady (i nie daje - częstotliwość zgłaszania przerwania timera została dobrana empirycznie dla osiągnięcia jak najlepszego efektu wizualnego). Zrobiłem tak jednak dla zmniejszenia gabarytów układu i stopnia komplikacji połączeń na płytce uniwersalnej, tym bardziej, że chciałem wykorzystać jedną z posiadanych przeze mnie płytek, bez konieczności zamawiania nowych. Być może zastosowanie w tym miejscu szybkich tranzystorów byłoby bardziej efektywne.
W każdym bądź razie udało mi się wykonać urządzonko, o którym od dawna myślałem, a na którego zrobienie nigdy nie miałem czasu. Działa i cieszy oko - to najważniejsze... Chociaż nie, najważniejsze jest chyba to, że mam teraz całkiem niezłą, choć o niskiej rozdzielczości, platformę do zabawy z grafiką trójwymiarową :-)

Postscriptum:


W ostatniej chwili dopisałem do programu demonstracyjnego kilka efektów. Kod źródłowy oraz gotowy do wgrania wsad (HEX) można pobrać z GitHuba:


Komentarze

  1. A mógłbyś podać pełny kod do kostki? - Do jej zaprogramowania?

    OdpowiedzUsuń
    Odpowiedzi
    1. Program, który umieściłem w tym wpisie to jest własnie to :-) Wystarczy go pobrać i odpowiednio zmodyfikować. Do atmegi ładujemy dowolnym programatorem.
      Co do modyfikacji, w zasadzie część uniwersalna to ta, która jest przeznaczona do pobierania danych binarnych efekty z linii "DATA". Tzw. rendery trzeba już sobie dopisać w oparciu o własny pomysł.

      Przy okazji odkryłem, ze numeracja efektów w komentarzach jest nieodświeżona ... Nie ma to oczywiście wpływu na sam program.

      Usuń
  2. Fajny projekt. Z synem zbudowaliśmy kostkę 3*3*3. Mam pytanie czy jest może jakiś program na kompa do wyliczania danych do linii DATA. Bo ręczne liczenie sprawia trochę problemu. Planujemy budowę większej kostki.

    OdpowiedzUsuń
    Odpowiedzi
    1. Dzięki! Otóż właśnie – program na PC (Linux/Windows) był w planach i ciągle jest, niestety jakoś nigdy nie miałem czasu, żeby go napisać. Ale dzięki za "upomnienie" – spróbuję coś popełnić w najbliższym czasie (będzie dobra okazja przetestować najnowsze Visual Studio ;-)).

      Usuń

Prześlij komentarz

Popularne posty z tego bloga

Niesamowicie prosty czujnik zmierzchowy.

Tym razem zero programowania, będzie natomiast nostalgiczno-wspomnieniowy układzik, lekko zmodyfikowany. Otóż kilka dni temu rozmawialiśmy w gronie znajomych o różnego rodzaju czujnikach zmierzchowych i czujnikach ruchu. Ponieważ należę do tych wariatów, co to hołdują jeszcze owej przestarzałej i kompletnie odrealnionej dziś zasadzie: "po co kupować, gdy można zrobić", stwierdziłem, że poskładam takie coś (czujnik zmierzchowy; sensor ruchu faktycznie lepiej nabyć, choćby ze względu na rozmiary ;)) i być może podłączę do jakiegoś mikrokontrolera. Przypomniało mi się też przy okazji, że znalazłem ostatnio w elektronicznych śmieciach stary fotorezystor (dla niewtajemniczonych: element zmieniający rezystancję, czyli opór elektryczny, pod wpływem działania strumienia światła) RPP130, jeden z kilku pozostałych po montowanych wieki temu układach tranzystorowych do zdalnego sterowania pracą urządzeń za pomocą latarki... No OK, nie było to specjalnie rozbudowane zdalne sterowanie ;)

Płytka prototypowa na bazie ESP8266 (ESP-01)

To nie jest kolejny artykuł traktujący od początku do... nieco dalej (bo na pewno nie do końca) o płytkach ESP8266 . Żeby się dowiedzieć, co to takiego, odwiedźcie proszę np. tę stronę (oraz wiele innych – poproście o pomoc Waszą ulubioną wyszukiwarkę): http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family . No ale żeby nie było, ESP8266 to układ zawierający na pokładzie wydajny mikrokontroler z rdzeniem RISC-owym, taktowany zegarem 40MHz (wersja, o której jest ten wpis) lub 80MHz, 512KB pamięci flash i podsystem komunikacji przez sieć WiFi . Jest powszechnie wykorzystywany jako swego rodzaju karta sieciowa do połączeń bezprzewodowych naszych urządzeń IoT , które budujemy w zaciszu domowych laboratoriów (i nie tylko). Układ montowany jest na płytkach występujących w kilku wersjach, różniących się przede wszystkim liczbą wyprowadzeń uniwersalnych, czyli GPIO – im większa liczba, tym większe możliwości wykorzystania układu (więcej urządzeń peryferyjnych itp.). Są też pewne

Programowanie AVR cz.8: Przetwornik analogowo-cyfrowy oraz modulacja szerokości impulsu.

Dziś kolejny wgląd w wyposażenie mikrokontrolera ATmega48P - tym razem przyglądamy się wbudowanemu w układ przetwornikowi analogowo-cyfrowemu oraz - dostępnej również w modelach ATtiny - modulacji szerokości impulsu realizowanej przez timery. Artykuł ten jest w pewnym sensie wstępem do następnego, który pojawi się już wkrótce, a którego tematykę zdradziłem na końcu. Przetwornik A-C (skrót spotykany w anglojęzycznej literaturze to ADC od Analog to Digital Converter ) to układ pozwalający na zamianę wartości napięcia (elektrycznego sygnału analogowego ;-)) na liczbę. W przypadku mojej ATmegi przetwornik ma rozdzielczość 10-bitową, co oznacza, że wartość napięcia podawanego na wejście przetwornika może być po konwersji zapisana jako liczba z przedziału od 0 do 1023 (musimy użyć zmiennej word do zapamiętania tej liczby). Jeśli jesteśmy w posiadaniu mikrokontrolera w obudowie PDIP 28-wyprowadzeniowej, to mamy do dyspozycji sześć kanałów (niezależnych wejść) przetwornika A-C, przyporzą