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ż: 14843 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:
GND - uziemnienie;
VCC - 5+;
SDA - linia przesyłanych danych;
SDL - linia zegara
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.
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.
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:
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:
MenuItem - reprezentująca pojedynczy obiekt pozycji menu;
Menu - reprezentująca menu i realizująca zadania związane z przewijaniem pozycji menu;
Klasa MenuItem jest swego rodzaju uproszczoną listą dwukierunkową. Oto deklaracje wyżej wymienionych klas:
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.