Serwisy partnerskie:
Close icon
Serwisy partnerskie

Kurs Arduino odcinek 20b - przyciski i biblioteki do obsługi wyświetlaczy

W poprzednim miesiącu wykorzystywaliśmy biblioteki stworzone przez Marco Colli (MajicDesigns) z Australii, dostępne w Githubie
Article Image
1. Kurs Arduino: wprowadzenie 2. Kurs Arduino odcinek 1 - co to jest i jak zacząć? (sprzęt, schematy, programowanie) 3. Kurs Arduino odcinek 2 - termometry: 'diodowy', pokojowy oraz 'scalony' analogowy 4. Kurs Arduino odcinek 3 - moduł wyświetlacza LCD (HD44780) 5. Kurs Arduino odcinek 4 - czujnik BME280 (pomiar ciśnienia, wilgotności i temperatury) 6. Kurs Arduino odcinek 5 - biblioteki do trzyfunkcyjnego czujnika BME280 7. Kurs Arduino odcinek 6 - wykorzystanie łącza I2C (TWI) 8. Kurs Arduino odcinek 7 - wykorzystanie łącza SPI (karty pamięci, MAX31865, MAX31855) 9. Kurs Arduino odcinek 8 - wykorzystanie czujnika dwutlenku węgla (MH-Z19) 10. Kurs Arduino odcinek 9 - wykorzystanie modułów do odmierzania czasu 11. Kurs Arduino odcinek 10 - wykorzystanie czujników temperatury (DS18B20) 12. Kurs Arduino odcinek 11 - budowa loggera (rejestratora danych) 13. Kurs Arduino odcinek 12 - rejestracja i prezentacja danych oraz obsługa karty SD 14. Kurs Arduino odcinek 13 - rejestracja danych (wykorzystanie modułu OpenLog) 15. Kurs Arduino odcinek 14 - czym zastąpić płytkę Arduino Uno? 16. Kurs Arduino odcinek 15 - budowa rejestratora (chiński klon Arduino Pro Mini) 17. Kurs Arduino odcinek 16 - problemy z kwadratowym modułem Strong 18. Kurs Arduino odcinek 17 - czujniki do pomiaru wilgotności gleby (instalacja, konfiguracja) 19. Kurs Arduino odcinek 18 - protokół MODBUS i łącze RS-485 20. Kurs Arduino odcinek 19 - wyświetlacze od podstaw (matrycowe, 7-segmentowe, MAX7219) 21. Kurs Arduino odcinek 20a - wyświetlacze matrycowe i biblioteki MD_MAX 22. Kurs Arduino odcinek 20b - przyciski i biblioteki do obsługi wyświetlaczy 23. Kurs Arduino odcinek 20c - biblioteki do obsługi wyświetlaczy graficznych 24. Kurs Arduino odcinek 21 - moduł wyświetlacza OLED 25. Kurs Arduino odcinek 22 - moduł wyświetlacza 1,3 cala 26. Kurs Arduino odcinek 23 - przygotowanie bitmap do wyświetlania 27. Kurs Arduino odcinek 24 - omówienie fontu podstawowego (Adafruit GFX) 28. Kurs Arduino odcinek 25 - font podstawowy biblioteki Adafruit GFX 29. Kurs Arduino odcinek 26 - wykorzystanie bitmapowych fontów GFX 30. Kurs Arduino odcinek 27 - polskie znaki w glcdfont.c 31. Kurs Arduino odcinek 28 - zmiana ulepszonych fontów GFX

Oprócz MD_MAX72xx, biblioteki do obsługi sprzętu, używaliśmy też biblioteki MD_Parola, która jest swego rodzaju rozszerzeniem, nakładką i pozwala w prosty sposób uzyskać najróżniejsze efekty tekstowe. Zmodyfikowane przykładowe szkice z tej biblioteki dostępne są w Elportalu jako szkice 2003.ino oraz 2004.ino.

Jak już wiemy, szkice pracowały w modelu pokazanym na fotografii 8, ale podczas pracy szkicu 2004.ino działanie klawiszy zmieniających ustawienia było dziwne, niepewne. Teoretycznie bez powodu program sygnalizował na ekranie komputera nieustanne zmiany napięcia na nóżce A5. Tani chiński potencjometr aż tak dużych szumów na pewno nie miał. Podejrzenie padło na obwody zasilania.

Fot.8 Model wykorzystujący szkic 2003.ino

W większości dotychczasowych eksperymentów z Arduino Uno zasilamy system przez kabel z gniazda USB komputera. Wyświetlacz przy pełnej jasności pobiera duży prąd, co może powodować fluktuacje zasilania. Wprawdzie napięcie zasilające potencjometr jest jednocześnie napięciem odniesienia dla przetwornika ADC, więc teoretycznie fluktuacje napięcia zasilającego nie powinny zmieniać pomiaru napięcia z dzielnika – potencjometru.

Owszem, ale tylko przy powolnych zmianach napięcia zasilania. Natomiast szybkie zmiany – skoki napięcia zasilania mogą wpływać na wyniki pomiaru napięcia. Nie mierzyłem, ile prądu pobiera wyświetlacz, natomiast zbadałem oscyloskopem zmiany napięcia zasilania.

Rysunek 9 pokazuje, jakie były te zmiany w moim układzie po naciśnięciu S6 (negatyw). Jak widać, napięcie zasilające zmieniało się skokowo od około 4,1V do około 4,9V, czyli skoki miały amplitudę międzyszczytową około 0,8V, co stanowi aż 16% napięcia zasilania. Nic dziwnego, że powodowało to problemy.

Rys.9 Zmiany napięcia zasilania

Skutecznym rozwiązaniem zapewne byłoby zastosowanie zewnętrznego „sztywnego” zasilacza stabilizowanego. Ja jednak go nie zastosowałem. Problem nie tyle rozwiązałem, co ominąłem programowo: autor szkicu przytomnie wprowadził procedurę, która za zmianę stanu suwaka uznaje znaczącą zmianę napięcia.

Jak pokazuje szkic 8, wartość z przetwornika ADC z zakresu 0...1024 zostaje zmapowana na wartości z zakresu 0...100. W zmiennej speed (prędkość) mamy więc wartość z wcześniejszego pomiaru z zakresu 0...100.

Szkic 8

(...)
const uint16_t PAUSE_TIME = 1000; // in milliseconds
// const uint8_t SPEED_DEADBAND = 5; // in analog units
const uint8_t SPEED_DEADBAND = 10; //były problemy podczas pracy
(...)
void doUI(void) { // najpierw zbadaj napięcie z potencjometru
// set the speed if it has changed - Analog read
{ // uzyskujemy wynik pomiaru z zakresu 0...100:
int16_t speed = map(analogRead(SPEED_IN), 0, 1023, 0, 100);
if ((speed >= ((int16_t)P.getSpeed() + SPEED_DEADBAND)) ||
(speed <= ((int16_t)P.getSpeed() - SPEED_DEADBAND)))
{ P.setSpeed(speed);
DEBUG("\nChanged speed to ", P.getSpeed()); } } (...)

Następnie sprawdzane jest, czy świeżo odczytana prędkość jest większa lub mniejsza od wcześniejszej o więcej niż wynosi zadeklarowana wcześniej wartość SPEED_DEADBAND, która określa zakres nieczułości. W oryginale wartość SPEED_DEADBAND wynosiła 5,co daje ±5% pełnego zakresu. Zmieniłem ją na 10 i problem stał się nieznaczący (ale nie został rozwiązany).

Nadal reakcja przycisków była nieco dziwna, ale to oddzielna kwestia. W każdym razie naciskając przyciski oraz obserwując konsolę monitora i zmiany na wyświetlaczu LED, można było przetestować 27 dostępnych efektów, zmienianych przez naciskanie S5. Jeżeli przeprowadzisz takie testy, zwróć uwagę na problem obcinania dłuższych napisów. Rozwiązaniem są efekty numer 3 i numer 4, gdzie wykorzystane jest przewijanie napisów.

Naciśnięcie S6 wyświetla obraz w negatywie, gdy prawie wszystkie diody świecą. Właśnie wtedy pobór prądu jest największy i prawdopodobieństwo zakłóceń też największe. Zanim naciśniesz S6, naciśnij i przytrzymaj S4, co zmieni jasność. Proponuję ustawić jasność = 1, jak widać na rysunku 10.

Rys.10 Zmiana jasności wyświetlacza

Przy jasności 0 wyświetlacz jest całkowicie wygaszony (shutdown). Niezależnie od tego, czy zrealizujesz układ według rysunku 7, koniecznie obejrzyj następujące autorskie filmy:

  • https://www.youtube.com/watch?v=JgzVCSFaz3I
  • https://www.youtube.com/watch?v=u1iELyROjW8
  • https://www.youtube.com/watch?v=tfwAHx0MTxU https://www.youtube.com/watch?v=DUwtmrIVH58.

Możliwości opisanych właśnie bibliotek i przykładowych programów są ogromne. Nic dziwnego, że w Internecie jest wiele przykładów wykorzystania biblioteki MD_Parola, zawsze współpracującej z MD_MAX72xx. Być może i Ty zechcesz wykorzystać dostępne w niej efekty.

Możliwości jest mnóstwo, jednak opisanie zasad działania, dostępnych funkcji, ich argumentów i innych szczegółów byłoby zbyt obszerne, jak na jeden odcinek kursu Arduino. Jeżeli chcesz użyć tych bibliotek, poszukaj przykładowych szkiców najbliższych Twoim potrzebom i zmodyfikuj je według potrzeb.

Znajdziesz różne, w tym bardzo oryginalne i interesujące rozwiązania. Sam autor tych bibliotek na stronie prezentuje zegar pokazujący czas słowami (WordClock). Na jedną jedyną matrycę LED 8×8 naklejona jest maska z literami, które odpowiednio zaświecane informują o aktualnym czasie. Fotografia 11 pochodzi ze strony.

Fot.11 zegar pokazujący czas słowami (WordClock)

Trzeba podkreślić, że omawiane biblioteki, jak na Arduino, są wyjątkowo dobrze udokumentowane. W samych bibliotekach i przykładach są obszerne komentarze i wyjaśnienia. Jeszcze szersze opisy dostępne są na blogu.

Zapewne w związku z opisanymi ćwiczeniach zainstalujesz też wymaganą w niektórych przykładach kolejną bibliotekę MD_UISwitch. Warto wiedzieć, że może się ona okazać bardzo przydatna w licznych zastosowaniach. Oprócz pojedynczych przycisków dołączanych do pinów Arduino, biblioteka obsługuje klawiatury matrycowe, a także można ją wykorzystać w przypadku przycisków nietypowo dołączonych, na przykład za pośrednictwem kostki CMOS 4017 według rysunku 12.

Rys.12 Przyciski dołączone za pośrednictwem kostki CMOS 4017

Zawarty w tej bibliotece rysunek 13 pokazuje sprytny i oszczędny sposób dołączenia pięciu przycisków do jednego wejścia analogowego. Biblioteka zawiera też przykładowy szkic dotyczący kalibracji takiego zestawu. Takie rozwiązanie stosowane jest w dość popularnym szyldzie z wyświetlaczem LCD i pięcioma przyciskami (fotografia 14).

Fot.14 Szyld z wyświetlaczem LCD i pięcioma przyciskami

W Internecie można znaleźć podobne propozycje dołączenia znacznie większej liczby przycisków i klawiatur, ale wtedy rośnie ryzyko błędów interpretacji, wynikających z tolerancji rezystorów oraz zmian termicznych i długoczasowych. Pięć przycisków według rysunku 13 plus indywidualna kalibracja zapewnią niezawodność i brak błędów.

Rys.13 Sposób dołączenia pięciu przycisków do jednego wejścia analogowego (schemat z biblioteki MD_UISwitch)

Obsługując przyciski, biblioteka pozwala rozróżniać naciśnięcie zwykłe, długie oraz podwójne (dwuklik), a można też ustawić opcję auto repeat. W zasadzie badamy temat wyświetlaczy matrycowych i graficznych, ale jeśli mamy już zestawiony układ według rysunku 7 i fotografii 8, wykorzystajmy zawarte w niej bardzo pouczające przykłady. Możesz też odłączyć wyświetlacz według rysunku 15.

Rys.15 Arduino bez wyświetlacza

Ja w pliku MD_UISwitch_Multi_Digital.ino dokonałem zmian według szkicu 9 i zapisałem jako A2005.ino. Po skompilowaniu i wgraniu szkicu trzeba otworzyć na komputerze Monitor portu szeregowego (Ctrl+Shift+M), gdzie pojawią się komunikaty dotyczące naciskania klawiszy (B0...B5).

// define pin numbers for individual switches
// const uint8_t SW_PIN[] = { 4, 5, 6, 7 }; // tak było
const uint8_t SW_PIN[] = {2, 3, 4, 5, 6, 7 }; //mamy 6 przycisków , dołączonych do pinów 2...7
(...)
switch (state)
{ /* tak było w oryginale -
case MD_UISwitch::KEY_NULL: /*Serial.print("KEY_NULL");*/ /* break;
case MD_UISwitch::KEY_UP: Serial.print("KEY_UP"); break;
case MD_UISwitch::KEY_DOWN: Serial.print("KEY_DOWN"); break;
case MD_UISwitch::KEY_PRESS: Serial.print("KEY_PRESS"); break;
case MD_UISwitch::KEY_DPRESS: Serial.print("KEY_DPRESS"); break;
case MD_UISwitch::KEY_LONGPRESS: Serial.print("KEY_LONGPRESS"); break;
case MD_UISwitch::KEY_RPTPRESS: Serial.print("KEY_RPTPRESS"); break;
default: Serial.print("KEY_UNKNWN"); break; */
// zmieniamy opisy na polskie:
case MD_UISwitch::KEY_NULL: /*Serial.print("brak naciśnięcia");*/ break; //możesz odkomentować
case MD_UISwitch::KEY_UP: Serial.print("zwolnienie"); break;
case MD_UISwitch::KEY_DOWN: Serial.print("naciśnięcie"); break;
case MD_UISwitch::KEY_PRESS: Serial.print("interpretacja = normalne naciśnięcie"); break;
case MD_UISwitch::KEY_DPRESS: Serial.print("interpretacja = \"dwuklik\""); break;
case MD_UISwitch::KEY_LONGPRESS: Serial.print("interpretacja = długie naciśnięcie"); break;
case MD_UISwitch::KEY_RPTPRESS: Serial.print("interpretacja = autopowtarzanie (auto repeat)"); break;
default: Serial.print("błąd - nierozpoznane działanie"); break; (...)

Działanie może wydać się dziwne z uwagi na ustawienia w bibliotece, a konkretnie w pliku .../src/MD_UISwitch.h, gdzie domyślne czasy są ustawione wbrew zaleceniom podanym w opisie tejże biblioteki, co może być mylące.

Otóż w tej bibliotece przewidziano skuteczną, ale dość skomplikowaną procedurę likwidowania skutków drgań styków (debounce), a dodatkowo określono także czasy:

KEY_PRESS_TIME,
KEY_DPRESS_TIME,
KEY_LONGPRESS_TIME,
KEY_REPEAT_TIME,

które decydują o interpretacji naciśnięcia klawisza czy klawiszy.

Rozszyfrowanie znaczenia tych czasów na podstawie oryginalnego opisu ze strony nie jest łatwe. Wątpliwości możesz wyjaśnić sam podczas testów. W bibliotece klasie przewidziane są funkcje-metody do ustawiania tych czasów, ale znacznie łatwiej ustawić je właśnie w pliku MD_UISwitch.h według szkicu 10. Proponuję, żebyś otworzył w edytorze (ja używam Notepad++) plik MD_UISwitch.h i zmieniał ustawienia tych czasów.

(...) /* // poniżej oryginalne wartości domyslne:
const uint16_t KEY_PRESS_TIME = 150; ///< Default key press time in milliseconds
const uint16_t KEY_DPRESS_TIME = 250; ///< Default double press time between presses in milliseconds
const uint16_t KEY_LONGPRESS_TIME = 600; ///< Default long press detection time in milliseconds
const uint16_t KEY_REPEAT_TIME = 300; ///< Default time between repeats in in milliseconds
const uint8_t KEY_ACTIVE_STATE = LOW; ///< Default key is active low - transition high to low detection */
// nowe wartości czasów w milisekundach:
const uint16_t KEY_PRESS_TIME = 300; ///< maksymalny czas zwykłego = minimalny czas długiego
naciśnięcia
const uint16_t KEY_DPRESS_TIME = 350; ///< maksymalny czas pojawienia się "dwukliku" (nie za długi)
const uint16_t KEY_LONGPRESS_TIME = 1200; ///< maksymalny czas długiego naciśnięcia = moment interpretacji
const uint16_t KEY_REPEAT_TIME = 300; ///< czas między powtórzeniami przy ciągłym naciskaniu klawisza
const uint8_t KEY_ACTIVE_STATE = LOW; ///< naciśnięcie = stan niski na pinie Arduino (...)

Zmień długości czasów, zapisz plik nagłówkowy (a nie plik szkicu) MD_UISwitch.h, a potem od nowa skompiluj szkic A2005.ino z tymi nowymi czasami i obserwuj, jak są interpretowane naciśnięcia przycisku (lub kilku przycisków naraz).

Mamy cztery przypadki (i wyniki):
- krótkie naciśnięcie,
- długie naciśnięcie,
-„dwuklik”, czyli szybkie dwukrotne naciśnięcie,
- bardzo długie naciskanie, które w efekcie daje ciąg „impulsów” – wyników przez cały czas naciskania.

Według moich ustaleń czas KEY_PRESS_TIME to granica między zwykłym i długim naciśnięciem. Czas KEY_LONGPRESS_TIME to czas, po którym następuje interpretacja i uzyskanie wyniku także przy ciągłym naciskaniu klawisza. Przy naciśnięciach krótszych od czasu KEY_LONGPRESS_TIME, zwolnienie klawisza powoduje zinterpretowanie pomiaru (krótkie lub długie naciśnięcie) i wyświetlenie na konsoli monitora).

Gdy w czasie KEY_DPRESS_TIME po naciśnięciu przycisku nastąpi jego ponowne naciśniecie, wtedy wynikiem interpretacji będzie „dwuklik”. A jeżeli dwa kliknięcia pojawią się w odległości czasowej większej niż KEY_DPRESS_TIME, wtedy wynikiem interpretacji będą dwa naciśnięcia: zwykłe lub długie, zależnie od ustawień KEY_PRESS_TIME i KEY_LONGPRESS_TIME.

Gdy przycisk jest długo (ciągle, stale) naciskany, to po czasie KEY_LONGPRESS_TIME następuje interpretacja. Wynikiem interpretacji jest „normalne naciśnięcie” (a nie długie!), a potem co czas KEY_REPEAT_TIME pojawiają się kolejne „normalne naciśnięcia”. Można to nieco zmienić: jeśli w pliku .../src/MD_UISwitch.cpp zmienimy ustawienie:

enableRepeatResult(false) na enableRepeatResult(true)

wtedy po czasie KEY_LONGPRESS_TIME też pojawi się wynik „pojedyncze naciśnięcie ”, ale następne występujące co KEY_REPEAT_TIME impulsy – wyniki nie będą „zwykłymi naciśnięciami ”, tylko „autopowtarzaniem”, co czasem może być przydatne.

We własnym zakresie zmodyfikuj i skompiluj przykładowy szkic MD_UISwitch_Example.ino. Masz tam warunkową kompilację i do naszego zestawu 6 przycisków (digital array) musisz zmodyfikować dwie linie:

#define TEST_DIGITAL_SIMPLE 0
#define TEST_DIGITAL_ARRAY 1
#define TEST_ANALOG 0
#define TEST_MATRIX_4b4 0
#define TEST_MATRIX_1b6 0
#define TEST_MATRIX_4017KM 0

i dalej w szkicu dodać numery pinów, do których dołączone są przyciski. Program testowania zestawu „digital array” działa podobnie jak A2005.ino, tylko wyświetla na konsoli inne napisy.

Zależnie od potrzeb można wykorzystać wszystkie albo tylko niektóre z tych czterech możliwości (krótkie, długie, dwuklik i ciągłe), które domyślnie są włączone i dostosować do tego ustawienia wspomnianych czasów.

W omawianym szkicu znajdziesz trzy następujące zakomentowane linie:

(...)
S.begin();
//S.enableDoublePress(false);
//S.enableLongPress(false);
//S.enableRepeat(false);
S.enableRepeatResult(true);
(...)

Domyślnie dwuklik (DoublePress), długie naciśnięcie (LongPress) i powtarzanie (Repeat) są włączone. Odkomentowanie ich (z atrybutem false) wyłączy je.

Jeżeli z kolei w ostatniej linii zmienisz true na false, ciągłe naciskanie da wyniki „normalne naciśniecie”, a nie „autopowtarzanie”. Poćwicz!

A w następnym odcinku wreszcie przejdziemy do biblioteki Adafruit GFX.

1. Kurs Arduino: wprowadzenie 2. Kurs Arduino odcinek 1 - co to jest i jak zacząć? (sprzęt, schematy, programowanie) 3. Kurs Arduino odcinek 2 - termometry: 'diodowy', pokojowy oraz 'scalony' analogowy 4. Kurs Arduino odcinek 3 - moduł wyświetlacza LCD (HD44780) 5. Kurs Arduino odcinek 4 - czujnik BME280 (pomiar ciśnienia, wilgotności i temperatury) 6. Kurs Arduino odcinek 5 - biblioteki do trzyfunkcyjnego czujnika BME280 7. Kurs Arduino odcinek 6 - wykorzystanie łącza I2C (TWI) 8. Kurs Arduino odcinek 7 - wykorzystanie łącza SPI (karty pamięci, MAX31865, MAX31855) 9. Kurs Arduino odcinek 8 - wykorzystanie czujnika dwutlenku węgla (MH-Z19) 10. Kurs Arduino odcinek 9 - wykorzystanie modułów do odmierzania czasu 11. Kurs Arduino odcinek 10 - wykorzystanie czujników temperatury (DS18B20) 12. Kurs Arduino odcinek 11 - budowa loggera (rejestratora danych) 13. Kurs Arduino odcinek 12 - rejestracja i prezentacja danych oraz obsługa karty SD 14. Kurs Arduino odcinek 13 - rejestracja danych (wykorzystanie modułu OpenLog) 15. Kurs Arduino odcinek 14 - czym zastąpić płytkę Arduino Uno? 16. Kurs Arduino odcinek 15 - budowa rejestratora (chiński klon Arduino Pro Mini) 17. Kurs Arduino odcinek 16 - problemy z kwadratowym modułem Strong 18. Kurs Arduino odcinek 17 - czujniki do pomiaru wilgotności gleby (instalacja, konfiguracja) 19. Kurs Arduino odcinek 18 - protokół MODBUS i łącze RS-485 20. Kurs Arduino odcinek 19 - wyświetlacze od podstaw (matrycowe, 7-segmentowe, MAX7219) 21. Kurs Arduino odcinek 20a - wyświetlacze matrycowe i biblioteki MD_MAX 22. Kurs Arduino odcinek 20b - przyciski i biblioteki do obsługi wyświetlaczy 23. Kurs Arduino odcinek 20c - biblioteki do obsługi wyświetlaczy graficznych 24. Kurs Arduino odcinek 21 - moduł wyświetlacza OLED 25. Kurs Arduino odcinek 22 - moduł wyświetlacza 1,3 cala 26. Kurs Arduino odcinek 23 - przygotowanie bitmap do wyświetlania 27. Kurs Arduino odcinek 24 - omówienie fontu podstawowego (Adafruit GFX) 28. Kurs Arduino odcinek 25 - font podstawowy biblioteki Adafruit GFX 29. Kurs Arduino odcinek 26 - wykorzystanie bitmapowych fontów GFX 30. Kurs Arduino odcinek 27 - polskie znaki w glcdfont.c 31. Kurs Arduino odcinek 28 - zmiana ulepszonych fontów GFX
Tematyka materiału: Arduino Uno
AUTOR
Źródło
Elektronika dla Wszystkich grudzień 2019
Udostępnij
UK Logo