Powrót

Kurs Arduino – Adafruit GFX

 

Ten odcinek zaczniemy od kolejnego przykładu wykorzystania znanej już biblioteki MD_UISwitch, stworzonej przez Marco Colli (MajicDesigns).

Jeżeli masz klawiaturę matrycową 4×4, dołącz ją do płytki Arduino według rysunku 16 i fotografii 17.

Rysunek 16

Fotografia 17

Niestety potrzeba do tego aż ośmiu pinów, które musisz wskazać, jak pokazuje szkic 11, gdzie widać też, że klawiaturę matrycową można dołączyć do dowolnych pinów Arduino.

Szkic 11.

(…)  #if TEST_MATRIX_4b4
#define TITLE „Matrix 4×4”
uint8_t rowPins[] = { 9, 8, 7, 6 };   // rzędy
uint8_t colPins[] = {5, 4, 3, 2 };   // kolumny
const uint8_t ROWS = sizeof(rowPins);
const uint8_t COLS = sizeof(colPins);
char kt[(ROWS*COLS) + 1] = „123A456B789C*0#D”; //symbole
MD_UISwitch_Matrix S(ROWS, COLS, rowPins, colPins, kt);
#endif  (…)

Ja skompilowałem tak zmodyfikowany szkic MD_UISwitch_Example.ino z jedynką w linii:

#define TEST_MATRIX_4b4  1

Po otwarciu na komputerze Monitora portu szeregowego (Ctrl+Shift+M) możemy testować reakcje poszczególnych klawiszy. Jak wskazuje szkic 11, definiujemy tablicę znaków o nazwie kt, w której zawarte są oznaczenia klawiszy: cyfry, litery A, B, C, D oraz symbole * i #. Dlatego naciśniecie klawisza powoduje  zwrócenie i wyświetlenie na ekranie znaku z tego klawisza. A konkretnie znaku ASCII i jego numeru w kodzie szesnastkowym.

Co ważne, dla każdego klawisza dostępne są wszystkie wcześniejsze możliwości: naciśnięcie krótkie, długie, „dwuklik” i naciskanie ciągłe. Przykładowy zrzut ekranu konsoli monitora pokazany jest na rysunku 18.

Rysunek 18

Możliwości są duże, ale niestety, sposoby wykorzystania tej biblioteki nie są najłatwiejsze. Zapewne poradzisz sobie jednak z adaptacją ich w swoich szkicach, by wykorzystać wartości zwracane przez funkcje – metody: numer-nazwa przycisku oraz jego stan, badany instrukcją switch-case. Możesz zacząć od wyczyszczenia przykładowych szkiców z tego, co nie jest konieczne i wtedy pozostanie sama esencja, którą możesz przenieść do własnych szkiców.

Możesz zacząć od pojedynczego przycisku. Kluczową funkcją – metodą jest .read(), określająca rodzaj naciśnięcia. Zwraca ona stan przycisku za pomocą własnego typu wyliczeniowego keyResult_t. W przypadku większej liczby przycisków trzeba też określić, który z nich został naciśnięty, co zwykle jest realizowane za pomocą wcześniej określonej tablicy.

Możesz też zapoznać się z łatwiejszą do wykorzystania biblioteką MD_REncoder do obsługi obrotowego enkodera (elektronicznego potencjometru – Rotary Encoder) ze strony: https://github.com/MajicDesigns/MD_REncoder. Zwraca ona nie tylko impulsy wskazujące aktywność i kierunek obrotu, ale też prędkość pokręcania, co można wykorzystać do wzbogacenia funkcji takiego enekodera.

Oprócz bibliotek omówionych w tym artykule, Marco Colli (MajicDesigns) udostępnił też szereg innych bibliotek i projektów (https://github.com/MajicDesigns?tab=repositories). Mają one bardzo dobrą jakość i mogą okazać się bardzo przydatne. Jednak nie przywiązuj się zbytnio do skądinąd znakomitych bibliotek MD_MAX72xx, MD_MAXPanel i MD_Parola. Są one przeznaczone tylko dla wyświetlaczy matrycowych LED z kostką MAX7219. Wyświetlacze takie niewątpliwie są bardzo atrakcyjne, ale nas ciągnie też do wyświetlaczy graficznych LCD i OLED o wyższej rozdzielczości. A niestety, tam te trzy biblioteki nie są przydatne. Dlatego powinniśmy  przyjrzeć się zupełnie innym bibliotekom do obsługi wyświetlaczy matrycowych i graficznych. Pozostańmy jeszcze przy matrycach LED, ale zainteresujmy się biblioteką Adafruit GFX oraz biblioteką arduino-Max72xxPanel, której twórcą jest Mark Ruys z Holandii.

Wcześniej mieliśmy podstawową bibliotekę MD_MAX72xx, która zapewniała komunikację z kostką (kostkami) MAX7219 i wyświetlaczem, a do tego biblioteki pomocnicze, które realizowały bardziej zaawansowane funkcje. Teraz jest podobnie: mamy sprzętową bibliotekę arduino-Max72xxPanel, a do tego  pomocniczą bibliotekę Adafruit GFX, która realizuje bardziej zaawansowane funkcje związane z rysowaniem elementarnych figur geometrycznych, grafik oraz napisów z wykorzystaniem (fontów-czcionek).

Biblioteka Adafruit GFX, jak wskazuje nazwa, powstała w znanej firmie Adafruit, ale wcale nie dla kostki MAX7219. Adafruit ma w swej bogatej ofercie handlowej mnóstwo większych i mniejszych wyświetlaczy graficznych: kolorowych i monochromatycznych. Można to sprawdzić na stronie: https://www.adafruit.com/?q=graphic%20display.

Biblioteka Adafruit GFX  jest uniwersalna, bo realizuje „wyższe” funkcje, wspólne dla wszystkich wyświetlaczy graficznych. Nie ma ona natomiast możliwości bezpośredniej współpracy z jakimkolwiek wyświetlaczem, bo jest tylko swego rodzaju nakładką, która ma współpracować z oddzielną biblioteką sprzętową, przeznaczoną do konkretnego wyświetlacza, a raczej do konkretnego scalonego sterownika.

Adafruit udostępnia biblioteki sprzętowe do wszystkich sprzedawanych przez siebie wyświetlaczy graficznych LCD i OLED – będziemy z niektórych korzystać. A zapoznanie się z biblioteką GFX jest absolutnie niezbędne, ponieważ będzie ona potrzebna, gdy będziemy chcieli wykorzystać różne wyświetlacze graficzne.

Firma Adafruit ma dobrą opinię, jej sprzęt i oprogramowanie także, więc także Ty możesz z powodzeniem skorzystać z udostępnionych przez nią bibliotek. Ale trzeba też wiedzieć, że są i inne możliwości obsługi wyświetlaczy graficznych. Na przykład od szeregu lat znana jest biblioteka  U8glib, obecnie zastąpiona przez U8g2 (wraz z U8x8), która realizuje „wyższe” funkcje graficzne i tekstowe, a jednocześnie zapewnia bezpośrednią współpracę z szeregiem wyświetlaczy graficznych, ale tylko monochromatycznych, a nie kolorowych. Dla zainteresowanych: biblioteka U8g2 w wersji dla Arduino jest dostępna pod adresem: https://github.com/olikraus/U8g2_Arduino, ale można ją też zainstalować z pomocą Menedżera bibliotek. My pominiemy bibliotekę U8g2, a bliżej zainteresujemy się bardziej uniwersalną biblioteką Adafruit GFX, bowiem przyda się ona też do wyświetlaczy kolorowych.

A na razie wracamy do matrycowego wyświetlacza LED 32 × 8 z czterech modułów FC16. Podłączenie jest identyczne jak wcześniej (rysunek 7). Mark Ruys, twórca biblioteki arduino-Max72xxPanel, napisał ją tak, żeby współpracowała z popularną biblioteką Adafruit-GFX-Library, którą możemy zainstalować przez Menedżera bibliotek. Natomiast sprzętową bibliotekę arduino-Max72xxPanel trzeba zainstalować ręcznie, po ściągnięciu jej ze strony: https://github.com/markruys/arduino-Max72xxPanel.

czyli po prostu rozpakować do katalogu

…/Dokumenty/Arduino/libraries/

W bibliotece arduino-Max72xxPanel-master jest katalog /examples/, a w nim katalog /Snake ze szkicem o starym rozszerzeniu (Snake.pde) realizującym popularnego węża, który wije się po całym wyświetlaczu. Najpierw możesz skompilować i wgrać oryginalny szkic (Snake.pde). Gdyby nie chciał się skompilować, zapisz go pod inną nazwą. Na wyświetlaczu zobaczysz cztery jednakowe węże.

Aby uzyskać prawidłowy efekt, musisz podać odpowiednie informacje, jak widać w spolszczonym szkicu A2006.ino i w szkicu 12: liczbę modułów poziomo (4) i pionowo (1) oraz rozmieszczenie modułów za pomocą funkcji .setPosition() (gdzie pierwszy wyświetlacz o numerze 0 jest najbliższy Arduino) i ich „obrót” – setRotation(), gdzie dla FC16 należy wpisać 1 (obrót o 90°).

Szkic 12:

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
int pinCS = 10; // który pin ma być CS w sprzetowym łaczu SPI?
int ModulowPoziomo = 4; // cztery moduły
int ModulowPionowo = 1; // w jednym rzedzie
// tworzymy tylko obiekt wyświetlacza = wysw
Max72xxPanel wysw = Max72xxPanel(pinCS, ModulowPoziomo, ModulowPionowo);
const int pinRandom = A0; //”ziarno” dla gen. pseudolosowego
const int wait = 100; // opóźnienie w milisekundach
const int length = 12; //długość węża
int x[length], y[length]; //pozycja
int ptr, nextPtr; // dwa wskaźniki
 
void setup() { // jednorazowo w funkcji setup():
wysw.setIntensity(1); // jasność (0…15)
// określamy, jak połączone i obrócone są cztery moduły o nr 0…3
wysw.setPosition(0, 0, 0); // najbliższy płytki Arduino
wysw.setPosition(1, 1, 0); // następny jest drugi w tym samym rzędzie
wysw.setPosition(2, 2, 0); // trzeci jest następny w tym samym rzędzie
wysw.setPosition(3, 3, 0); // czwarty – następny w tym samym rzędzie
wysw.setRotation(0, 1); // w czteromodułoej płytce wszystkie cztery FC16
wysw.setRotation(1, 1); // są niejako obrócone o 90 stopni w prawo
wysw.setRotation(2, 1); //stąd we wszystkich czterech przypadkach
wysw.setRotation(3, 1); // liczba 1, czyli „rotated 90o clockwise”

Gdy pobawisz się wężem, możesz wykorzystać inne zawarte w tej bibliotece przykłady. Nie namawiam do analizy treści tych szkiców. Koniecznie musisz się jednak zapoznać z biblioteką Adafruit GFX, której najnowszy opis znajdziesz pod adresem:

https://cdn-learn.adafruit.com/downloads/pdf/adafruit-gfx-graphics-library.pdf

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

Na początku wspomniane jest tam o instalacji biblioteki o nazwie Adafruit_ZeroDMA, co miałoby sens w przypadku wycofanej już ze sprzedaży płytki Arduino Zero z potężnym 32-bitowym procesorem Atmel’s SAMD21 (ARM), a nie z płytkami Arduino zawierającymi ATmega328P, gdzie nie ma DMA.

Raz na zawsze trzeba zapamiętać, że w wyświetlaczach graficznych piksele numeruje się, począwszy od górnego, lewego rogu, jak pokazuje pochodzący z tego pliku PDF rysunek 19 i tak trzeba podawać w funkcjach współrzędne x, y (w pikselach).

Rysunek 19

Biblioteka GFX wykorzystuje 16-bitowy model koloru (65536 odcieni) według rysunku 20. W wyświetlaczach monochromatycznych mamy tylko dwa kolory piksela: 0 (wyłączony) i 1 (aktywny).

Rysunek 20

Jak pokazuje szkic 13, w bibliotece GFX mamy szereg funkcji-metod do rysowania na ekranie podstawowych elementów graficznych: punktów, linii, (szybkich) linii pionowych i poziomych, prostokątów, wypełnionych prostokątów, okręgów i kół, prostokątów z zaokrąglonymi rogami oraz trójkątów. W każdym przypadku podajemy wymagane współrzędne i rozmiary oraz kolor.

Szkic 13:

drawPixel(x, y, color);
drawLine(x0, y0, x1, y1, color);
drawFastVLine(x0, y0, length, color);
drawFastHLine(x0, y0, length, color);
drawRect(x0, y0, w, h, color);
fillRect(x0, y0, w, h, color);
drawCircle(x0, y0, r, color);
fillCircle(x0, y0, r, color);
drawRoundRect(x0, y0, w, h, radius, color);
fillRoundRect(x0, y0, w, h, radius, color);
drawTriangle(x0, y0, x1, y1, x2, y2, color);
fillTriangle(x0, y0, x1, y1, x2, y2, color);
 
fillScreen(color);
 
drawChar(x, y, char c, color, bg, size);
 
setCursor(x0, y0);
setTextColor(color);
setTextColor(color, backgroundcolor);
setTextSize(size);
setTextWrap(w);
 
print(„napis do wyswietlenia”);

 

Ekran możemy zawsze wyczyścić / wypełnić kolorem za pomocą funkcji fillScreen(color)

W bibliotece Adafruit GFX wbudowany jest jeden podstawowy font (czcionka). Mamy dwie funkcje „tekstowe”. Pierwsza z nich:

drawChar(x, y, char c, color, bg, size)

wyświetla tylko jeden znak (character). Jako argumenty do funkcji przekazujemy: współrzędne x, y, gdzie ma on zostać wyświetlony, znak do wyświetlenia (w pojedynczym cudzysłowie), kolor – color, kolor tła – bg (background) oraz wielkość – size (1, 2 lub 3).

Współrzędne x, y w przypadku podstawowego, wbudowanego fontu wskazują górny, lewy róg znaku, jak widać na rysunku 21.

Rysunek 21

Druga funkcja „tekstowa” jest dobrze znana z wcześniejszych ćwiczeń: print(„tekst do wyswietlenia”)

Ona tylko wypisze na ekranie tekst umieszczony w podwójnym cudzysłowie. Ale gdzie i jak?

Jak pokazuje szkic 12, przed jej użyciem trzeba określić, w którym punkcie ekranu należy zacząć pisać, trzeba ustawić kolor i kolor tła oraz wielkość czcionki. Można też włączyć zawijanie tekstu do następnego wiersza (TekstWrap).

Znaki podstawowego fontu mają wielkość 5 × 7 pikseli, ale wpisując ich rozmiar (size) 2 lub 3, powiększymy rozmiar 2- lub 3-krotnie.

Aby poćwiczyć te podstawowe funkcje, przygotowałem szkic A2007.ino (dostępny w Elportalu), gdzie możesz też wpisać dodatkowo własny tekst za pomocą Monitora portu szeregowego według rysunku 22. Wykorzystałem fragment kodu ze strony: https://mytectutor.com/max7219-led-matrix-interfacing-with-arduino/

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

Rysunek 22

Warto tam zajrzeć, bowiem Autor pokazuje, jak ten sam efekt zrealizować za pomocą różnych bibliotek.

Modyfikuj szkic A2007.ino i w ten sposób zapoznaj się z podstawowymi funkcjami biblioteki Adafruit-GFX. oraz z ograniczeniami związanymi z małą liczbą pikseli naszego matrycowego wyświetlacza LED.

Zwróć uwagę, że polecenia biblioteki arduino-Max72xxPanel-master nie powodują od razu wyświetlenia na ekranie tego, co określa rozkaz. Dlatego w naszym szkicu po każdym takim rozkazie za każdym razem dodatkowo używamy funkcji: wysw.write();

Dopiero ona powoduje wyświetlenie czegoś na ekranie. Jest to normalne, ponieważ przy obsłudze takich wyświetlaczy wykorzystujemy tak zwany bufor: pamięć pomocniczą treści całego obrazu. Funkcje rysowania/pisania modyfikują tylko treść bufora (pamięci), a nie wyświetlają go na ekranie. Zawartość bufora zostaje wyświetlona na ekranie dopiero po wykonaniu funkcji wysw.write();

Dlatego możesz zrealizować kilka funkcji rysowania/pisania, a dopiero potem wyświetlić je na ekranie.

Na razie pomijamy problem polskich liter, natomiast chcemy wykorzystać bardziej pojemny wyświetlacz, choćby najbardziej obecnie popularny OLED 128 × 64 pikseli.

W szkicu A2007.ino trzeba tylko zmienić informacje o wyświetlaczu, a kluczowe fragmenty programu pozostaną te same.

W zasadzie tak, ale w grę wchodzi kilka dodatkowych szczegółów, dlatego wyświetlaczami tymi zajmujemy się w następnym odcinku naszego kursu (UR021).

Piotr Górecki