Powrót

Kurs Arduino – Wyświetlacze matrycowe LED

W poprzednich dwóch odcinkach (UR017 i UR018) omawialiśmy wykorzystanie łącza RS-485 i standardu MODBUS na przykładzie czujnika wilgotności gleby. Według planów mieliśmy zająć się obsługą graficznego wyświetlacza OLED. Jednak nadesłane listy na temat wyświetlaczy graficznych i matrycowych spowodowały, że tematem tym zajęliśmy się dokładniej, od podstaw.

Dlatego też w odcinku 19 wykorzystamy wyświetlacze, na razie matrycowe, potem także graficzne. I znów boleśnie zderzymy się ze specyfiką Arduino… Przede wszystkim raz na zawsze trzeba pożegnać się z klasycznymi matrycami LED. Przypomnijmy tylko, że jak najbardziej możliwe jest dołączenie wprost do pinów Arduino zestawu wyświetlaczy 7-segmentowych jak pokazuje rysunek 1 ze strony:

https://create.arduino.cc/projecthub/SAnwandter1/programming-4-digit-7-segment-led-display-2d33f8

w skrócie: https://bit.ly/2kzaxXj.

Rysunek 1

Można też dołączyć wprost matrycę jednakowych punktów LED, jak na mocno nieestetycznym rysunku 2 ze strony:

https://www.instructables.com/id/8×8-LED-Matrix-Using-Arduino/

w skrócie: https://bit.ly/2k4PUC0.

Rysunek 2

Kto chce, może na podanych stronach sprawdzić, jak realizowana jest obsługa wyświetlaczy. Jednak takie sposoby są absolutnie przestarzałe i niegodne uwagi. Choćby tylko dlatego, że aby dołączyć matrycę 16×16 z rysunku 3, potrzebne byłyby 32 piny, a Arduino UNO ma ich tylko kilkanaście.

Rysunek 3

Zapominamy więc o bezpośrednim dołączaniu matryc do pinów procesora.

Innych, lepszych sposobów, jest wiele.

Jeden z nich, bodaj najprostszy, to wykorzystanie rejestrów przesuwających szeregowo-równoległych oraz dekoderów. Przykładem wykorzystania rejestrów i dekoderów jest pokazany na fotografii 4 moduł matrycy 16×16, czyli zawierający 256 punktów świetlnych.

Fotografia 4

Jak pokazuje schemat widoczny na rysunku 5, zawiera on dwa dekodery 74HC138 i dwa rejestry przesuwne 74HC595. Te moduły z kilku powodów są jednak mało popularne.

Rysunek 5

Do współpracy z Arduino UNO i płytkami pokrewnymi może być wykorzystany szyld z fotografii 6, nazywany Multi-function Shield (MSF).

Fotografia 6

Zawiera on szereg pożytecznych obwodów, a czterocyfrowy wyświetlacz jest sterowany za pośrednictwem dwóch rejestrów 74HC595 według rysunku 7.

Rysunek 7

Zainteresowani bibliotekę dla MSF znajdą pod adresem: https://github.com/DireCat/MFShield, a inne szczegóły odszukają wpisując w wyszukiwarkę właśnie: multi-function shield.

Pożyteczny może się też okazać moduł, zawierający układ scalony TM1638, produkcji Titan Micro Electronics. Procesor obsługuje ten układ za pomocą trzyżyłowego interfejsu (odmiana SPI). W wersji maksymalnej ta 28-nóżkowa  kostka może wysterować 80 diod LED (np 10 wyświetlaczy 7-segmentowych) i kontrolować stan nawet 24 przycisków (rysunek 8).

Rysunek 8

Na rynku dostępnych jest kilka rodzajów płytek z tą kostką, między innymi popularny i pożyteczny moduł, pokazany na fotografii 9.

Fotografia 9

Najpopularniejsza biblioteka dla TM1638 dostępna jest pod adresem:

https://github.com/rjbatista/tm1638-library.

Nas jednak najbardziej interesują moduły wyświetlaczy LED z kostką MAX7219. Ten układ scalony przewidziany jest zarówno do sterowania wyświetlaczami matrycowymi jak i 7-segmentowymi (rysunek 10) – wtedy można wykorzystać wbudowany obwód dekodowanie liczb dwójkowych 0…9 na kod wyświetlacza 7-segmentowego. W tej samej konfiguracji przeznaczony jest też do sterowania wyświetlaczami matrycowych 8×8 i wtedy bity poszczególnych bajtów zaświecają i gaszą poszczególne diody w matrycy.

Rysunek 10

Jak pokazuje rysunek 11 kostka ma też szereg rejestrów konfiguracyjnych i pamięć 8×8 bitów.

Rysunek 11

Procesor przysyła szeregowo do rejestru wejściowego 16 bitów. Co ciekawe, bity D12…D15 nie są wykorzystywane. Cztery bity D8…D11, czyli jedna liczba szesnastkowa określają (tabela 1) jak mają być interpretowane bity D0…D7. Czy jest to treść do wyświetlenia, czy też rozkaz konfiguracyjny.

Tabela 1

Jasność diod po pierwsze wyznacza dołączony z zewnątrz rezystor, ale co bardzo ważne, możliwa jest też programowa zmiana jasności (Intensity – rozkaz 0xXA), a także wyłączenie kostki wszystkich diod i przejście do stanu LowPower (Shutdown, rozkaz 0xXC) oraz ich zaświecenie (Display Test, rozkaz 0xXF). Jeden z rozkazów i rejestrów (Scan Limit, rozkaz 0xXB) określa, ile wyświetlaczy 7-segmentowych (cyfr) ma być czynnych. Co ważne kostki te można łączyć kaskadowo, szeregowo, co umożliwia wyjście DOUT. Wtedy procesor szeregowo przesyła jeden długi ciąg danych dla kilku wyświetlaczy, a potem stan aktywny linii LOAD powoduje ich wykorzystanie.

Zasady obsługi kostki MAX7219 nie są skomplikowane i w Internecie można znaleźć wiele przykładów wykorzystania bez użycia bibliotek. Oto trzy tego rodzaju przykłady:

http://www.electronoobs.com/eng_arduino_tut54.php

w skrócie: https://bit.ly/2k6K3Mv

www.whatimade.today/programming-an-8-digit-7-segment-display-the-easy-way-using-a-max7219/

w skrócie: https://bit.ly/2kq9dGk

https://docs.labs.mediatek.com/resource/linkit7697-arduino/en/tutorial/driving-7-segment-displays-with-max7219

w skrócie: https://bit.ly/2m7xOjz

Ale oczywiście dostępne są też biblioteki. Nie wszystkie są jednakowo użyteczne. Zasłużony też dla społeczności Arduino Nick Gammon szereg lat temu zrealizował prosta bibliotekę: https://github.com/nickgammon/MAX7219

Jednak najbardziej znana jest biblioteka LedControl, obsługująca MAX7219 zarówno do sterowania wyświetlaczy 7-segmentowych, jak i matryc. Wszystko byłoby dobrze, tylko  przykładowe szkice i dla wyświetlacza 7-segmentowego i matrycowego (rysunek 12) ze strony: https://github.com/wayoda/LedControl/tree/master/examples  w skrócie: https://bit.ly/2kcvaZi

Rysunek 12

pokazują, jak na takich wyświetlaczach wyświetlić napis „Arduino”, jak pokazuje fotografia 13 ze strony:

https://wayoda.github.io/LedControl/pages/software

w skrócie: https://bit.ly/2kzKiA1

Fotografia 13

Dla elektronika wyświetlanie napisu na wyświetlaczu 7-segmentowym, najdelikatniej mówiąc, nie jest zachęcającym przykładem. A wyświetlanie liczb za pomocą tej skądinąd popularnej biblioteki wcale nie jest takie proste. Oto przykłady:

https://cyaninfinite.com/8-digit-7-segment-serial-display/

w skrócie: https://bit.ly/2m7GQwZ

https://blog.circuits4you.com/2016/04/arduino-display-module-7-segment-8.html

w skrócie: https://bit.ly/2kqgUMI

Warto wejść na te strony i przeanalizować zamieszczone tam szkice. Można też poszukać jeszcze innych rozwiązań, wpisując w wyszukiwarkę: MAX7219 Arduino 7 segment

Proponowane w Sieci rozwiązania nie zachęcają do korzystania z biblioteki LedControl. Ale poszukiwania mogą doprowadzić do innych bibliotek.

Na razie pominiemy bibliotekę Max72xxPanel, która nie oferuje obsługi wyświetlaczy 7-segmentowych. Zaglądamy natomiast na stronę Hobby Components Ltd, brytyjskiego sprzedawcy modułów:

https://hobbycomponents.com/displays/597-max7219-8-digit-seven-segment-display-module

w skrócie: https://bit.ly/2kqhkTj

Oprócz modułów firma opracowała i udostępniła bibliotekę HCMAX7219:

https://github.com/HobbyComponents/HCMAX7219 w skrócie: https://bit.ly/2lGHBga

Biblioteka ta obsługuje zarówno moduły z wyświetlaczami 7-segmentowymi, jak i matrycowymi. Dalsze informacje o modułach i objaśnienia można znaleźć na stronie:

https://blog.hobbycomponents.com/?p=325

a o bibliotece HCMAX7219 na stronach: https://blog.hobbycomponents.com/?p=334

https://forum.hobbycomponents.com//viewtopic.php?f=58&t=1794

Bardzo zachęcający jest fakt, że oprócz elementarnych funkcji „sprzętowych”, są też dostępne bardziej zaawansowane funkcje biblioteczne, między innymi wyświetlanie napisów oraz liczb. Wyświetlane mogą być liczby całkowite (także ujemne), opcjonalnie całkowite z dodanym punktem dziesiętnym (przecinkiem), a jak wskazują opisy na podanych stronach, na wyświetlaczu 7-segmentowym można też wyświetlić liczby zmiennoprzecinkowe (float).

Zachęceni takimi możliwościami za pomocą pięciu przewodów dołączyłem stosowny moduł do sprzętowego łącza SPI płytki Arduino według rysunku 14. Planowałem dodanie kondensatora elektrolitycznego w obwodzie zasilania, ale testy pokazały, że nie jest konieczny.

Rysunek 14

Trochę się zdziwiłem, iż biblioteki MCMAX7219 nie można zainstalować przez Menedżera bibliotek. Jednak błyskawicznie ściągnąłem ją z Github-a:

https://github.com/HobbyComponents/HCMAX7219

i zainstalowałem „ręcznie”, rozpakowując pliki do bibliotecznego katalogu:

.../Dokumenty/Arduino/libraries/

i dbając, żeby po rozpakowaniu nie zostały umieszczone „zbyt głęboko”.

Po podłączeniu zasilania zaświeciły wszystkie segmenty. Po otwarciu przykładowego szkicu HCMODU0082_Serial_7_Segment_Module_Example1.ino (rysunek 15) program dał się bez problemu skompilować i załadować do płytki Arduino.

Rysunek 15

Byłem przyjemnie zaskoczony, bowiem jak na razie „wszystko poszło jak po maśle”. Ale tylko na początku…

Po skompilowaniu i załadowaniu szkicu zestaw wyglądał jak na fotografii 16.

Fotografia 16

Wyświetlanie napisów na takim wyświetlaczu nie ma większego sensu, o czym przekonuje fotografia 17a, pokazująca pseudonapis: Kurs EdW. Jak widać niektóre litery są czytelne, ale większość jest zupełnie nieczytelna.

Fotografia 17a

Opinię o beznadziejnym wyglądzie tekstu potwierdza drugi przykładowy szkic  z pliku HCMODU0082_Serial_7_Segment_Module_Example2.ino, gdzie naprawdę trudno rozszyfrować, że pięciokrotnie przewijany ma być napis: HCMAX7219 SCROLLING TEXT DEMO. Fotografia 17b pokazuje fragment tego „napisu”, a zaświecone segmenty mają teoretycznie tworzyć litery tEXt dE.

Fotografia 17b

Niemniej w tym drugim szkicu są godne uwagi przykłady wyświetlania liczb. I to nie tylko liczb całkowitych (ze znakiem) typu long, ale też liczb całkowitych z arbitralnie zaświeconym punktem dziesiętnym (przecinkiem). Ten przykładowy szkic, nieco spolonizowany dostępny jest w pliku  A1901.ino.

W materiałach dodatkowych dostępny jest też drugi przykład, pokazany w szkicu 1:

#include <HCMAX7219.h>
#include „SPI.h”
#define LOAD 10
HCMAX7219 HCMAX7219(LOAD); //obiekt
 
//void setup() {  } // wersja 0.2 nie ma inicjalizacji obiektu
// w wersji 0.5 – konieczna jest inicjalizacja obiektu:
void setup() {HCMAX7219.Init();}
 
void loop() {
 float Liczba = 3.1415926; //deklaracja i inicjalizacja
 byte Pozycja; //pozycja początku napisu lub punktu dziesietnego
// wyswietlimy liczby, najpierw zmiennoprzecinkową typu float
  HCMAX7219.Clear(); //wyczysc bufor danych w kostce MAX7219
  HCMAX7219.print7Seg(Liczba, 7, 8, 8); //załaduj liczbe
  HCMAX7219.Refresh(); delay(4000); //wyswietl i czekaj 2s
// liczba całkowita ujemna
  HCMAX7219.Clear(); //wyczysc bufor danych w kostce MAX7219
  HCMAX7219.print7Seg(„INTEGER „, 8); //najpierw załaduj napis
  HCMAX7219.Refresh(); delay(2000); //wyswietl i czekaj 2s
// liczba całkowita ujemna 
  HCMAX7219.Clear(); //wyczysc bufor danych w kostce MAX7219
  HCMAX7219.print7Seg(-2345678, 8); //załaduj liczbe do bufora
  HCMAX7219.Refresh(); delay(2000); //wyswietl i czekaj 2s
//teraz liczba z arbitralnie wyswietlanym punktem dziesietnym
  HCMAX7219.Clear(); //wyczysc bufor danych w kostce MAX7219
  HCMAX7219.print7Seg(„PUNKT D.”,8);  //najpierw załaduj napis
  HCMAX7219.Refresh(); delay(2000); //wyswietl i czekaj 2s
// a teraz punkt dziesietny na roznych pozycjach: 
  HCMAX7219.Clear(); //wyczysc bufor danych w kostce MAX7219
  for (Pozycja = 1; Pozycja <= 7; Pozycja++)
  { HCMAX7219.print7Seg(-3456789, Pozycja, 8);
    HCMAX7219.Refresh(); delay(1000); //wyswietl i czekaj
  }    }

Problem w tym, że szkic, zarówno oryginalny jak i A1901.ino, działa, ale niestety nie ma tam przykładu wyświetlenia liczby zmiennoprzecinkowej typu float. A nas bardzo interesuje właśnie wyświetlanie takich liczb, które są wynikiem pomiarów albo obliczeń. Dodałem stosowny fragment kodu, usunąwszy przewijanie napisu. Wykorzystujemy tu metodę .print7seg(), do której zgodnie ze wskazówkami producenta mamy przekazać cztery argumenty: liczbę typu float do wyświetlenia, liczbę cyfr po przecinku, liczbę wykorzystywanych cyfr-znaków wyświetlacza i pozycję początku wyświetlania, czyli na przykład:

HCMAX7219.print7Seg(Liczba, 7, 8, 8);

Niestety, próba kompilacji daje komunikat, że potrzebnej funkcji-metody… nie ma – rysunek 18.

Rysunek 18

W zainstalowanej bibliotece w pliku nagłówkowym HCMAX7219.h rzeczywiście nie było stosownej metody – rysunek 19.

Rysunek 19

Straciłem trochę czasu, żeby ustalić przyczynę. I wyjaśniło się dlaczego tej biblioteki nie można znaleźć przez Menedżera bibliotek ArduinoIDE. Otóż w Github-e zamieszczona jest wersja 0.2 z roku 2015, a w chwili pisania artykułu jest już wersja 0.5 z roku 2018. Jest, ale można ją ściągnąć tylko ze strony https://forum.hobbycomponents.com//viewtopic.php?f=58&t=1794 dopiero po zarejestrowaniu i zalogowaniu!

I rzeczywiście w tej wersji dodane jest wygodne wyświetlanie liczb zmiennoprzecinkowych, jak pokazuje rysunek 20. Ściągnąłem i zainstalowałem nową wersję biblioteki i skasowałem starą, która ma inną nazwę. Program zadziałał!

Rysunek 20

Podsumujmy tę część ćwiczeń. Otóż aktualnie wyświetlacze 7-segmentowe stopniowo tracą znaczenie. Jednak nadal je stosujemy. Gdy potrzebne są takie wyświetlacze, nie warto dołączać ich wprost do pinów procesora/Arduino. Zabiera to wiele pinów, potrzebnych jest wiele linii/ścieżek/przewodów. Dużo lepsze jest wykorzystanie modułów ze sterownikiem MAX7219. Aby obsługa była lekka, łatwa i przyjemna, trzeba wykorzystać sensowną bibliotekę. Dlatego proponuję, żebyś samodzielnie przeprowadził eksperymenty i zmodyfikował podane przykłady z plików A1901.ino, A1902.ino. Przekonaj się, że wykorzystanie modułu z kostką MAX7219 i biblioteki HCMAX7219 do wyświetlania liczb jest naprawdę dobrym pomysłem!

Tak, ale TYLKO do  przy użyciu wyświetlaczy 7-segmentowych. A my oczywiście dążymy do wyświetlaczy graficznych i bardzo nas interesuje sterowanie wyświetlaczy matrycowych LED. Niestety, choć biblioteka HCMAX7219 obsługuje takie matryce, nie zawsze efekt będzie zadowalający.

Tak jak w moim przypadku. Otóż zakupiłem swego czasu chiński moduł zawierający zestaw czterech kostek MAX7219 i czterech wyświetlaczy matrycowych 8×8.

Fotografia 21

Fotografia 21 pokazuje szczegóły jego budowy. Zmiana wyświetlacza była dziecinnie prosta, bo podłączenie jest identyczne jak na rysunku 14. Skompilowałem i załadowałem trzeci z dostarczonych przykładów (rysunek 15).

I znów pojawił się typowy niesympatyczny smaczek Arduino.

Po pierwsze biblioteka w starej wersji 0,2 nie wymaga inicjalizacji obiektu wyświetlacza, a wersja 0.5 wymaga inicjalizacji za pomocą metody .Init(), a nie .begin():

void setup() {HCMAX7219.Init();}

Po drugie wykorzystując zestaw czterech kostek MAX7219 połączonych poniekąd szeregowo, trzeba zaingerować w plik biblioteczny HCMAX7219.h, a konkretnie w linii:

#define NUMBEROFDRIVERS 1

zmienić liczbę drajwerów MAX7219 i zamiast jedynki wstawić czwórkę. A swoją drogą, pouczające jest skompilowanie i uruchomienie programu przed taką zmianą – wtedy na każdym z czterech wyświetlaczy pokazywana jest ta sama treść.

Po trzecie, po ingerencji w plik biblioteczny i skompilowaniu zawartego w bibliotece trzeciego przykładu, program zadziałał, ale obraz na wyświetlaczu był inny niż spodziewany. Zasadniczo przewijanie działało, ale nie we właściwą stronę i cztery kawałki obrazu były niejako obrócone o 90 stopni – przykład na fotografii 22.

Fotografia 22

Znów straciłem sporo czasu na wyjaśnienie sytuacji.

Okazało się, że biblioteka przewidziana jest dla modułów sprzedawanych przez Hobby Components i na nich daje prawidłowy obraz – rysunek 23.

Rysunek 23

Ja musiałbym albo przeciąć mój moduł na cztery kawałki i przekręcić każdy o 90 stopni, albo zmienić coś w programie. Demolować zgrabnego wyświetlacza nie chciałem, a biblioteka HCMAX7219 przewidziana do konkretnych modułów w sumie jest stosunkowo prosta i nie przewidziano w niej możliwości obracania obrazu.

Możliwości takie mają inne, bardziej zaawansowane biblioteki.

Podsumowując, biblioteka HCMAX7219, najlepiej w nowej wersji 0,5 jak najbardziej może przydać się do obsługi wyświetlaczy 7-segmentowych, natomiast raczej nie przyda się dla wyświetlaczy matrycowych. A tego rodzaju wyświetlaczami zajmujemy się  w następnych odcinkach naszego kursu.

Piotr Górecki