Arduino UNO i proste menu użytkownika wykonane z wykorzystaniem modułu LCD z magistralą szeregową i2c

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 14398 razy

Same Arduino nie wiele znaczy bez dodatkowych elementów. W tym przypadku postanowiłem stworzyć coś na kształt interfejsu użytkownika w postaci menu wyświetlanego na module LCD wyposażonym w magistralę szeregową i2c, która umożliwia podłączenie i komunikowanie się za pomocą zaledwie czterech przewodów:

Połączenie układu pokazane zostało na poniższym rysunku. Ważne jest, aby zdawać sobie sprawę, że w Arduino UNO piny A4 i A5 mają specjalne przeznaczenie i umożliwiają komunikowanie się z urządzeniami poprzez magistralę szeregową i2c. W tymże układzie w zależności od ustawienia rezystancji rezystora wyświetlana będzie pozycja menu.

Arduino UNO R3 - widok podłączenia modułu LCD z magistralą szeregową i2c oraz rezystora z regulowaną rezystancją
Rys. 1
Arduino UNO R3 - widok podłączenia modułu LCD z magistralą szeregową i2c oraz rezystora z regulowaną rezystancją

Poniżej zamieszczam dokładny opis magistrali szeregowej i2c wraz z modułem LCD. Każda magistrala szeregowa i2c ma przypisany adres, po którym urządzenie komunikuje się z Arduino. Takie rozwiązanie umożliwia podłączenie kilku różnych elementów sterowanych za pomocą magistrali szeregowej i2c pod warunkiem, że każda z nich ma przypisany inny adres. W przypadku poniższego modułu piny A1, A2 i A3 umożliwiają zmianę adresu magistrali. W moim przypadku adres mojej magistrali szeregowej i2c to 0x3F (zapis szesnastkowy), ale zdarzają się też moduły z ustawionym adresem na 0x27.

Rysunek poglądowy modułu LED z magistralą szeregową i2c
Rys. 2
Rysunek poglądowy modułu LED z magistralą szeregową i2c:
  1. piny sterujące i zasilające moduł;
  2. zworki umożliwiające zmianę adresu magistrali szeregowej i2c;
  3. rezystor regulujący kontrast wyświetlacza (jeżeli moduł nie wyświetla danych możliwe, że rezystor ten jest ustawiony w złym położeniu);
  4. zworka włączająca podświetlenie wyświetlacza LCD;
  5. dioda sygnalizująca podłączenie modułu do zasilania;

Jeżeli nie znasz adresu swojej magistrali szeregowej i2c poniższy kod umożliwi wykrycie tego adresu pod warunkiem, że do Arduino podpięte zostanie tylko jedno takie urządzenia.

#include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); while (!Serial); // Leonardo: wait for serial monitor Serial.println("nI2C Scanner"); } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); nDevices = 0; for(address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address<16) Serial.print("0"); Serial.print(address,HEX); Serial.println(" !"); nDevices++; } else if (error==4) { Serial.print("Unknown error at address 0x"); if (address<16) Serial.print("0"); Serial.println(address,HEX); } } if (nDevices == 0) Serial.println("No I2C devices foundn"); else Serial.println("donen"); delay(5000); // wait 5 seconds for next scan }

Zasada działania menu jest prosta, zmiana położenia pokrętła rezystora regulowanego powoduje zmianę odczytanego napięcia na pinie analogowym A0 i w zależności od jego wartości zmienia się pozycja wyświetlanego menu (co można zobaczyć na poniżej zamieszczonym filmie).

Do obsługi wyświetlacza konieczne jest załączenie następujących bibliotek:

#include <Wire.h> // standardowa biblioteka Arduino #include <LiquidCrystal_I2C.h> // dolaczenie pobranej biblioteki I2C dla LCD

Bibliotekę New LiquidCrystal można pobrać z strony tutaj.

Inicjalizacja obiektu klasy LiquidCrystal_I2C odpowiedzialnego za komunikację z modułem LCD wygląda następująco:

LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

Sama konfiguracja wyświetlacza w funkcji setup wygląda następująco:

lcd.begin(16,2); // liczba znaków w jednej linii, liczba linii tekstu lcd.setCursor(0,0); lcd.print("obliczeniowo.com"); lcd.setCursor(0,1); lcd.print(".pl"); lcd.setCursor(0,0);

Zadeklarowane przeze mnie klasy, które wykorzystuję do obsługi wyświetlania menu to:

Klasa MenuItem jest swego rodzaju uproszczoną listą dwukierunkową. Oto deklaracje wyżej wymienionych klas:

class MenuItem{ MenuItem* before; MenuItem* after; String text; public: MenuItem(String text, MenuItem* before = NULL, MenuItem* after = NULL) : text(text), before(before), after(after){}; ~MenuItem(){ if(after){ delete after; } } void addMenuPos(String text){ if(after){ after->addMenuPos(text); }else{ after = new MenuItem(text, this); } } byte count(){ if(after){ return 1 + after->count(); } return 1; } String getItemText(byte index){ if(index && after){ return after->getItemText(index - 1); } return text; } }; class Menu{ MenuItem *items; byte menuPos; public: Menu() : items(NULL), menuPos(0){}; ~Menu() { delete items; } void addMenuPos(String text){ if(items) items->addMenuPos(text); else items = new MenuItem(text); }; void setMenuPos(byte menuPos, LiquidCrystal_I2C &lcd){ if(this->menuPos != menuPos){ lcd.clear(); lcd.print(items->getItemText(menuPos)); this->menuPos = menuPos; } } void menuLoop(LiquidCrystal_I2C &lcd){ if(items){ byte count = items->count(); int maximum = 240; int minimum = 0; int dx = (maximum - minimum) / count; byte i = 0; int a0_read = analogRead(A0); for(int mp = maximum - dx; mp > minimum - dx; mp -= dx){ if(mp <= a0_read){ setMenuPos(i, lcd); break; } i++; } } } };

Globalnie utworzony obiekt klasy Menu:

Menu menu;

Tworzenie menu w funkcji setup jest banalnie proste:

menu.addMenuPos("Temperatura"); menu.addMenuPos("Cisnienie"); menu.addMenuPos("Naswietlenie"); menu.addMenuPos("Pogoda"); menu.addMenuPos("Czas"); menu.addMenuPos("Napiecie"); menu.addMenuPos("Menu 1"); menu.addMenuPos("Menu 2"); menu.addMenuPos("Menu 3");

Dodatkowo konieczne jest podciągnięcie rezystora pod pin A0:

pinMode(A0, INPUT_PULLUP);

Oraz wywołanie pętli menu w funkcji loop:

menu.menuLoop(lcd); delay(100);

Oczywiście powyższy przykład jest okrojoną wersją, albowiem w rzeczywistości często potrzebne są takie rozwiązania, które umożliwiają wywołanie konkretnej funkcji lub uruchomienie podmenu.

Strony powiązane
strony powiązane
  1. bitbucket.org/fmalpartida/new-liquidcrystal/downloads/ - biblioteka new-liquidcrystal
Propozycje książek