Pamiętam jak wiele lat temu zmorą dla mnie było multipleksowanie matrycy diod. Jeny… jak ja to źle przeżywałem. Z dzisiejszej perspektywy zupełnie nie rozumiem siebie z tamtych lat. Przecież to wcale nie jest aż takie trudne jak mi się wtedy wydawało. Dzisiaj jest jeszcze prościej! Mamy specjalizowane układy multipleksujące stworzone z myślą o wyświetlaczach LED i to jest piękne. Lecimy z koksem!
Kompletny cykl wpisów:
Nigdy więcej multipleksowania na GPIO! MAX7219 w akcji cz.1
Nigdy więcej multipleksowania na GPIO! MAX7219 w akcji cz.2
Nigdy więcej multipleksowania na GPIO! MAX7219 w akcji cz.3
MAX7219
Jednym z takich układów jest MAX7129 ( MAX7219-MAX7221 Datasheet.pdf ) który dzisiaj omawiam. Jest to układ, który potrafi kontrolować wyświetlacze diodowe o wspólnej katodzie. Potrafi obsłużyć 8 wyświetlaczy 7-segmentowych + kropkę, czyli łącznie 64 diod. Niekoniecznie muszą to być wyświetlacze segmentowe. Mogą to też być matryce 8×8, o czym przekonasz się później. Co ciekawe, posiada wbudowany dekoder BCD który może ułatwić pracę z układem. Do pamiętania tego co ma wyświetlić używa wbudowanej pamięci RAM.
Z układem możemy porozmawiać przez interfejs SPI. Układ wspiera połączenie kaskadowe, co pozwala na łączenie kostek w długie łańcuchy. Jest to ficzer który pozwala uzyskać spore rozmiary matryc LED.
Dalekowschodni przyjaciele produkują moduły z MAX7219 w wersji z wyświetlaczem 7-segmentowym oraz z matrycami 8×8.
Schemat i Cube
Moduły dostarczane przez chińczyków są bardzo proste w podłączeniu. Płytka posiada piny z dwóch stron. Jedna strona to wejście, druga to wyjście dla połączenia kaskadowego. Jako, że nie możemy nic czytać z ukłądu, połączenie i konfiguracja SPI będzie w trybie Master Transmit Only. Dzisiaj na mój blat trafił STM32L476RG zamontowany w płytkę Nucleo.
Schemat podłączenia wygląda tak:
Zegar główny MCU jak zwykle ustawiam na tyle, ile fabryka pozwala – 80 MHz. Do testowania pojedynczych układów jest to całkiem wygodne. Preskaler SPI początkowo będzie miał wartość 64, co wynikowo daje 1,25 MHz na zegarze interfejsu szeregowego. Pin CS może być skonfigurowany jako Software lub Hardware. Obsłużymy obydwa przypadki.
Kodzimy, kodzimy, kodzimy!
MAX7219 udostępnia kilka rejestrów konfiguracyjnych.
Co możemy dzięki nim zrobić? Oprócz oczywistych rejestrów Digit X, pozostałe pozwalają na:
- Przejście w tryb Shutdown – wyłączenie oscylatora, wygaszenie diod
- Zmianę jasności diod przez ustawienie wypełnienia podawanego sygnału
- Zakres skanowania cyfr – ograniczenie wyświetlania do i-tej cyfry
- Włączenie testu – wszystkie diody świecą z maksymalną jasnością
Wszystkie te manewry są obsługiwane w mojej bibliotece przez wygodne enumy.
MAX7219_STATUS MAX7219_SetDecodeMode(uint8_t DeviceNumber, MAX7219_DecodeMode DecodeMode); MAX7219_STATUS MAX7219_SetIntensity(uint8_t DeviceNumber, uint8_t Intensity); MAX7219_STATUS MAX7219_SetScanLimit(uint8_t DeviceNumber, MAX7219_ScanLimit Limit); MAX7219_STATUS MAX7219_Shutdown(uint8_t DeviceNumber, MAX7219_ShutdownMode Shutdown); MAX7219_STATUS MAX7219_SetDisplayTest(uint8_t DeviceNumber, MAX7219_TestMode Enable);
Podstawowa konfiguracja wykonywana jest podczas inicjalizacji do której już klasycznie u mnie należy przekazać wskaźnik do SPI.
MAX7219_STATUS MAX7219_Init(SPI_HandleTypeDef *hspi);
No dobra, ale jest jescze taki ‘rejestr’ jak No-Op. Jak sama nazwa wskazuje, przesłanie tego do układu powoduje brak operacji. Na co to? Służy to do trybu kaskadowego, gdzie dane podawane na DIN przekazywane są później na DOUT.
MAX7219 działa jak rejestr przesuwny. Dane wpisane do niego są zatrzaskiwane w momencie powrotu sygnału CS do stanu wysokiego. Wtedy ostatnie 16 bitów, które trafiły do rejestru są tymi, które determinują wykonywaną operację. Opiszę to dokładniej, gdy dotrzemy do kaskady.
Ustawienie cyfry dla pojedynczego układu jest łatwe. Wystarczy wysłać do układu pod odpowiedni rejestr wybraną wartośc. Należy mieć na uwadzę jakie ustawienie kodowania jest wybrane. Jeśli MAX7219 ma sam dekodować BCD na odpowiednie segmenty, wystarczy wysłać liczbę z zakresu 0÷9.
Ja jednak namawiam do nie używania dekodera BCD. Dlaczego? Bo można zdefiniować więcej znaków na wyświetlaczu. Przygotowałem listę liter, które przyszły mi do głowy i da się je zrealizować na 7-segmentach. Nic nie stoi na przeszkodzie, aby dodać własne.
Do ustawiania pojedynczych cyfer służy funkcja
MAX7219_STATUS MAX7219_SetDigit(uint8_t DeviceNumber, uint8_t Digit, uint8_t Value, uint8_t Dot);
Zwróć uwagę, że numerowanie Digit zaczyna się jakby od końca. Cyfra zerowa jest z prawej strony, a siódma z lewej. Jest do dla nas mało naturalne, ale wyświetlacz jest tak fizycznie podłączony do pinów scalaka.
Printowanie
Jednak czy wysyłanie pojedynczych znaków jest wygodne? No nie. O wiele lepiej użyc czegoś w rodzaju printf’a. W tym celu powołałem kilka pomocnych funkcji.
MAX7219_STATUS MAX7219_PutString(int Start, char *String); MAX7219_STATUS MAX7219_PutStringRightAdjust(char *String); MAX7219_STATUS MAX7219_PutStringLeftAdjust(char *String); MAX7219_STATUS MAX7219_PutStringCenterAdjust(char *String);
Pierwsza z góry służy do wypisania ciągu znaków zaczynając od pozycji Start. W tym miejscu naprawiłem nieludzkie ułożenie cyfr w całym wyświetlaczu i zerowa pozycja jest z lewej strony. Funkcja łyka wszystkie znaki ASCII które zdefiniowałem pod ich prawdziwymi kodami. Łatwo jest więc wpisać po prostu co się chce. Znaki których nie ma w zdefiniowanej tablicy pomija.
No dobra, ale co z kropką?! Przecież na wyświetlaczach 7-segmentowych jest ona integralną częścią cyfry! Zgadza się i przygotowałem się na taki zarzut. Otóż printowanie obsługuje kropki. Gdy kropka znajdzie się jako znak w stringu, jest ona doklejana do cyfry. Sprawdź sam jak to działa.
Pozostałe 3 funkcje to taki bajer. Mają one za zadanie wyrównać wprowadzany napis odpowiednio do prawej, do lewej oraz wycentrować. Taki bajer jak w edytorach teskstów.
Wszystkie te funkcje obsługują połączenie kaskadowe, które omówię w kolejnej części wpisu.
Działanie
Jeszcze szybki rzut na to jak to działa. Sprawdźmy najpierw ile czasu zajmuje wyświetlenie wszystkich ośmiu cyfr.
SCK 1,25 MHz
SCK 2,5 MHz
Wyniki są następujące:
- 1,25 MHz – 176 µs
- 2,5 MHz – 118 µs
- 5 MHz – 88 µs
- 10 MHz – 73 µs
Układ niestety nie współpracuje jeśli chodzi o overclocking. Powyżej 10 MHz zaczyna pokazywać śmieci, więc wartość w dokumentacji jest już na prawdę maksymalną.
Podsumowanie
Jak widzisz można uznać, że multipleksowanie na GPIO odchodzi do lamusa. Komu teraz będzie chciało się robić to ręcznie? Byc może w aplikacjach, gdzie cena jednostkowa urządzenia musi być wyśrubowana do granic możliwości. Jednak wtedy też należy przemyśleć czy aby na pewno zaoszczędzenie na scalaku bedzie korzystniejsze niż oszczędność czasu potrzebnego na implementacje multipleksowania.
W kolejnej części omówię budowanie kaskady z układów MAX7219.
Jeżeli spodobał Ci się opisywany dzisiaj moduł z wyświetlaczami 7-segmentowymi, możesz nabyć go u mnie w sklepie.
Pełny projekt wraz z biblioteką znajdziesz jak zwykle na moim GitHubie: link
Jeśli zauważyłeś jakiś błąd, nie zgadzasz się z czymś, chciałbyś coś dodać istotnego lub po prostu uważasz, że chciałbyś podystkutować w tym temacie, napisz komentarz. Pamiętaj, że dyskusja ma być kulturalna i zgodna z zasadami języka polskiego.
6 komentarzy
Andrzej · 01/07/2023 o 10:55
Właśnie spróbowałem zaimportować Twój projekt do STM32CubeIDE w wersji 1.12.1 Przy próbie kompilacji otrzymuję komunikat:
**** Build of configuration Debug for project MAX7219_Digits ****
Nothing to build for project MAX7219_Digits
Jakby coś brakowało w zarchiwizowanym projekcie. Wiesz coś o tym problemie? Spróbuję stworzyć własny projekt i dołączyć twoje pliki. Zobaczę co z tego wyjdzie.
Andrzej · 01/07/2023 o 11:03
wygląda na to że projekt był tworzony dla SW4STM32 bo konfigurator procesora nie może się odpalić. I dodatkowo nie widzi biblioteki stdio.h
pam · 19/10/2022 o 14:04
nikt nie pisze o akłóceniach od tego mulipleksowania. Jak ktoś ma czułe urządzenia radiowe, to takie coś się nie nada.
Paweł · 18/02/2022 o 13:37
Dzięń dobry
Mam pytanie – jak z poziomami napiec 3.3vV na STM vs. 5V na MAX72xx
Czy nie ma problemu z różnicą napiec na liniach sterujących?
Co prawda nie ma tu odczytu a gdyby nawet był to większość pinów na STM toleruje 5V, natomiast czy w dugą stronę mamy pewność wysterowania MAX…, zwłaszcza przy wyższych częstotliwościach?
Pozdrawiam
Paweł
Mateusz Salamon · 20/02/2022 o 15:35
Tyyyy… faktycznie ten MAX w dokumentacji ma jedynkę od 3,5V. Teoretycznie nie powinno działać na 3V3 i widocznie miałem szczęście 😀 Powinien być translator.
mahmood · 21/11/2021 o 09:03
Cześć, drogi przyjacielu
Przeczytałem twój kod. Było świetnie. Tylko mam dwa problemy.
W zaprojektowanym przeze mnie obwodzie mam 16 segmentów, który jest ustawiony na 2 EC max7219. Wykonałem twój kod.
Dzieje się tak, że najpierw pojawia się tylko pierwszych 8 segmentów liczby, a kolejne 8 segmentów liczb zawsze się zmienia i nie jest widocznych.
Drugi problem polega na tym, że w pierwszych 8 segmentach pokazuje cyfry w odwrotnej kolejności. To znaczy chcę pokazać 12345678, ale w segmentach wyświetla się 87654321.
Dziękuję za pomoc.