W artykule zostanie przedstawione menu do wyświetlacza dotykowego za pomocą którego jest możliwość odczytywania aktualnych wartości z wagi (belki tensometrycznej). Na wyświetlaczu również można ustawić wartość do jakiej ma zostać obciążona waga (np. jakimś płynem w połączeniu z pompą).


Spis treści
- Wykorzystane komponenty
- Wstęp
- Zaprogramowanie
- Pliki do pobrania
Wykorzystane komponenty
- Arduino Mega
- Dotykowy Wyświetlacz LCD TFT przekątna 3.2″
Wstęp
Program jak i wyświetlacz można wykorzystać w różnych projektach z wagą, posiada on 3 funkcje: pierwsza to pokazywanie aktualnego obciążenia na wadze, druga to możliwość ustawienia gramów do którego momentu ma zostać obciążona, a trzecia to tarowanie. Po naciśnięciu wyświetlacza w miejscu ustaw wagę, wyświetli się klawiatura na której będziemy mogli wpisać interesującą nas wartość. Program posiada również zabezpieczenie i więcej niż 4 liczby nie wpiszemy. Wszystkie te funkcje można zmodyfikować pod swój projekt albo dodać własne. Niezbędna do zaprogramowania wyświetlacza będzie tutaj wiedza z tego artykułu https://ajmaker.pl/2022/01/20/dotykowe-ekran-lcd-3-2-wykorzystanie-w-praktyce/.
Zaprogramowanie
Na początku deklarujemy wszystkie potrzebne zmienne, definicje, biblioteki oraz najważniejsze ustawienia w funkcji setup.
#include <Adafruit_GFX.h> #include <MCUFRIEND_kbv.h> #include <TouchScreen.h> MCUFRIEND_kbv tft; // Stworzenie obiektu pełniącego rolę wyświetlacza /* Zmienne do obsługi ekranu dotykowego */ uint8_t YP = A1; uint8_t XM = A2; uint8_t YM = 7; uint8_t XP = 6; /* --------------------------------- */ int16_t BOXSIZE; // zainicjowanie zmiennej służącej nam do tworzenia przycisków /* Definicja poszczególnym boków ekranu */ uint16_t TS_LEFT = 880; uint16_t TS_RT = 170; uint16_t TS_TOP = 950; uint16_t TS_BOT = 180; /* --------------------------------- */ #define MINPRESSURE 20 // Minimalna wartość jaką może odczytać program aby uznać, że dotknęliśmy ekranu #define MAXPRESSURE 500 // Maksymalna wartość jaką może odczytać program aby uznać, że dotknęliśmy ekranu #define PWM 3 #define IN1 2 #define IN2 5 /* --------------------------------- */ TouchScreen ts = TouchScreen(XP, YP, XM, YM, 250); // Stworzenie obiektu pełniącego rolę ekranu dotykowego TSPoint tp; // Stworzenie obiektu do ustalania aktualnego punktu na ekranie /* przypisanie do nazw kolorów odpowiadających im wartości w systemie szesnastkowym*/ #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF bool mieszanie = true; //zmienna do silnika bool pompa = true; //zmienna do pomy int obroty = 100; //obroty silnika int value = 255; //wartosc obrotow bool menu_mierzenie = false; //menu do wazenia int num_count_A = 0; //liczba wpisanych liczb w menu wagi A int num_count_B = 0; //liczba wpisanych liczb w menu wagi B bool wazenie = true; //zadeklarowanie zmiennej wazenie int once = 0; //zadeklarowanie zmiennej oncet unsigned long ustawgramy_A = 0; //ustawione gramy wagi A unsigned long last_number_A = 0; //poprzedni numer wpisany w funkcji ustawGramy() bool ustaw_wage_A = false; //menu do ustawiania wagi A unsigned long ustawgramy_B = 0; //ustawione gramy wagi B unsigned long last_number_B = 0; //poprzedni numer wpisany w funkcji ustawGramy() bool ustaw_wage_B = false; //menu do ustawiania wagi B void setup() { Serial.begin(9600); // Rozpoczęcie transmisji szeregowej pinMode(PWM, OUTPUT); //ustawienie PWM jako wyjście pinMode(IN1, OUTPUT); //ustawienie IN1 jako wyjście pinMode(IN2, OUTPUT); //ustawienie IN2 jako wyjście analogWrite(PWM, 0); //ustawienie prędkości obrotów digitalWrite(IN1, LOW); //ustawienie stanu niskiego na IN1 digitalWrite(IN2, LOW); //ustawienie stanu niskiego na IN2 tft.begin(0x9327); // Rozpoczęcie pracy ekranu o id 0x9327 ( odpowiada naszemu modelowi ekranu) tft.fillScreen(BLACK); // Wypełnienie ekranu kolorem czarnym tft.setRotation(1); // ustawienie rotacji ekranu na poziomą tft.setTextColor(WHITE); // Ustawienie koloru tekstu na czarny BOXSIZE = tft.height() / 3; menuWazenie(); // wyświetl menu ważenie }
Teraz zajmiemy się główną funkcją loop, na początek standardowe ustawienia wyświetlacza oraz niezbędny if.
void loop() { uint16_t xpos, ypos; // inicjacja zmiennych służących do ustalenia składowych x i y pozycji kursora tp = ts.getPoint(); // przypisanie do zmiennej tp aktualnego punktu na ekranie /*ustawienie na wyjście pinów służących do obsługi ekranu dotykowego*/ pinMode(XM, OUTPUT); pinMode(YP, OUTPUT); pinMode(XP, OUTPUT); pinMode(YM, OUTPUT); /* --------------------------------- */ if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) { // sprawdzanie czy punkt znajduje się w granicach ustalonych na początku programu xpos = map(tp.x, TS_LEFT, TS_RT, 0, tft.width()); // rozdzielenie zmiennej tp na składową x poprzez funkcję mapowania ypos = map(tp.y, TS_TOP, TS_BOT, 0, tft.height()); // rozdzielenie zmiennej tp na składową y poprzez funkcję mapowania
Teraz pozostałe instrukcje warunkowe, które określą gdzie aktualnie dotykamy ekran i przypisujemy do nich odpowiednie działanie.
if (xpos > 240) // jeżeli składowa x punktu jest większa od 240, czyli znajdujemy się w pierwszym wierszu { if (ypos > 144 && ypos < 192) // jeżeli składowa y punktu jest większa od 144 i mniejsza od 188, czyli znajdujemy się w obszarze przycisku mieszanie { once = 0; //wyzerowanie zmiennej once ustaw_wage_A = true; //ustaw zmienną ustaw_wage_A na true while (ustaw_wage_A) // do póki ustaw_wage_A prawda, wykonuj pentle { if (once < 1) // jeżeli zmienna once mniejsza od 1 wykonaj poniższe instrukcje { klawiatura(ustawgramy_A); //wywołanie funkcji klawiatury once++; //dodaj 1 do zmiennej once } tp = ts.getPoint(); // przypisanie do zmiennej tp aktualnego punktu na ekranie /*ustawienie na wyjście pinów służących do obsługi ekranu dotykowego*/ pinMode(XM, OUTPUT); pinMode(YP, OUTPUT); pinMode(XP, OUTPUT); pinMode(YM, OUTPUT); /* --------------------------------- */ if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) { // sprawdzanie czy punkt znajduje się w granicach ustalonych na początku programu xpos = map(tp.x, TS_LEFT, TS_RT, 0, tft.width()); // rozdzielenie zmiennej tp na składową x poprzez funkcję mapowania ypos = map(tp.y, TS_TOP, TS_BOT, 0, tft.height()); // rozdzielenie zmiennej tp na składową y poprzez funkcję mapowania if (num_count_A < 1) // jeżeli zmienna once mniejsza od 1 wykonaj poniższe instrukcje { tft.setCursor(22, 30); //ustawienie kursora tft.setTextColor(WHITE, BLACK); //zmiana koloru tekstu } wpiszGramy(xpos, ypos); //wyświetl menu z ważeniem } } menuWazenie(); //wyświetl menu z ważeniem } else if (ypos > 192 && ypos < 240) { Serial.println("taruj wage A"); //tutaj będzie tarowanie wagi A } } else if (xpos > 120 && xpos < 240) { if (ypos > 144 && ypos < 192) // jeżeli składowa y punktu jest większa od 144 i mniejsza od 188, czyli znajdujemy się w obszarze przycisku mieszanie { once = 0; //wyzerowanie zmiennej once ustaw_wage_B = true; //ustaw zmienną ustaw_wage_B na true while (ustaw_wage_B) // do póki ustaw_wage_B prawda, wykonuj pentle { if (once < 1) // jeżeli zmienna once mniejsza od 1 wykonaj poniższe instrukcje { klawiatura(ustawgramy_B); //wywołanie funkcji klawiatury once++; //dodaj 1 do zmiennej once } tp = ts.getPoint(); // przypisanie do zmiennej tp aktualnego punktu na ekranie /*ustawienie na wyjście pinów służących do obsługi ekranu dotykowego*/ pinMode(XM, OUTPUT); pinMode(YP, OUTPUT); pinMode(XP, OUTPUT); pinMode(YM, OUTPUT); /* --------------------------------- */ if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) { // sprawdzanie czy punkt znajduje się w granicach ustalonych na początku programu xpos = map(tp.x, TS_LEFT, TS_RT, 0, tft.width()); // rozdzielenie zmiennej tp na składową x poprzez funkcję mapowania ypos = map(tp.y, TS_TOP, TS_BOT, 0, tft.height()); // rozdzielenie zmiennej tp na składową y poprzez funkcję mapowania if (num_count_B < 1) { tft.setCursor(22, 30); //ustawienie kursora tft.setTextColor(WHITE, BLACK); //zmiana koloru tekstu } wpiszGramy(xpos, ypos); //wywołanie funkcji wpiszGramy } } menuWazenie(); //wyświetl menu z ważeniem } else if (ypos > 192 && ypos < 240) { Serial.println("taruj wage B"); //tutaj będzie tarowanie wagi B } } } }
Z głównego programu byłoby na tyle, ale zostały jeszcze wykorzystane w nim funkcje. Pierwsza z nich ustawGramy() odpowiada za łączenie wpisywanych liczb z wyświetlacza, wyświetlanie liczby i wysyłanie jej do odpowiedniej zmiennej. Zależy to od tego czy korzystamy z menu A czy B. Funkcja posiada jeden argument w którym przyjmowana jest aktualnie wciskana liczba na wyświetlaczu.
void ustawGramy(int l) { if (ustaw_wage_A) { if (num_count_A > 0 && num_count_A < 4) //jeżeli ilość liczb jest większa od zera i mniejsza od 4 wykonaj poniższe instrukcje { ustawgramy_A = last_number_A * 10 + l; //pomnożenie ostatniej liczby przez 10 i dodanie liczby, która została wybrana last_number_A = ustawgramy_A; //przypisanie gramów jako ostatnia liczba } else if (num_count_A < 1) //jeżeli ilość liczb jest mniejszy od 1 wykonaj poniższe instrukcje { ustawgramy_A = l; //ustawienie gramów wagi A last_number_A = ustawgramy_A; //przypisanie gramów jako ostatnia liczba } num_count_A++; //zwiększenie ilości numerów tft.setCursor(22, 30); //ustawienie pozycji kursora tft.print(ustawgramy_A); //wyświetlenie tekstu } else { if (num_count_B > 0 && num_count_B < 4) //jeżeli ilość liczb jest większa od zera i mniejsza od 4 wykonaj poniższe instrukcje { ustawgramy_B = last_number_B * 10 + l; //pomnożenie ostatniej liczby przez 10 i dodanie liczby, która została wybrana last_number_B = ustawgramy_B; //przypisanie gramów jako ostatnia liczba } else if (num_count_B < 1) //jeżeli ilość liczb jest mniejszy od 1 wykonaj poniższe instrukcje { ustawgramy_B = l; //ustawienie gramów wagi B last_number_B = ustawgramy_B; //przypisanie gramów jako ostatnia liczba } num_count_B++; //zwiększenie ilości numerów tft.setCursor(22, 30); //ustawienie pozycji kursora tft.print(ustawgramy_B); //wyświetlenie tekstu } }
Kolejna funkcja menuWazenie wyświetla całe menu.
void menuWazenie() { tft.fillScreen(BLACK); //wypełnij wyświetlacz czarnym kolorem tft.setTextColor(WHITE); //ustaw kolor tekstu na biały //pierwsza kolumna tft.setTextSize(1); //ustawienie rozmiaru tekstu tft.setCursor(10, 35); //ustawienie pozycji kursora tft.print("WAGA A"); //wyświetlenie tekstu tft.setCursor(10, 115); //ustawienie pozycji kursora tft.print("WAGA B"); //wyświetlenie tekstu tft.setCursor(10, 195); //ustawienie pozycji kursora //pierwszy wiersz tft.setCursor(345, 55); //ustawienie pozycji kursora tft.print("TARUJ"); //wyświetlenie tekstu tft.setCursor(250, 55); //ustawienie pozycji kursora tft.print("USTAW WAGE"); //wyświetlenie tekstu tft.setTextColor(WHITE); //ustawienie koloru tekstu tft.setCursor(159, 55); //ustawienie pozycji kursora tft.print("AKT. WAGA"); //wyświetlenie tekstu tft.setTextSize(2); //ustawienie rozmiaru tekstu tft.setCursor(355, 25); //ustawienie pozycji kursora tft.print("X"); //wyświetlenie tekstu tft.setCursor(255, 25); //ustawienie pozycji kursora tft.print(ustawgramy_A); //wyświetlenie tekstu tft.print("g"); //wyświetlenie tekstu tft.setCursor(180, 25); //ustawienie pozycji kursora tft.print("0"); //wyświetlenie tekstu //drugi wiersz tft.setTextSize(1); //ustawienie rozmiaru tekstu tft.setCursor(345, 130); //ustawienie pozycji kursora tft.print("TARUJ"); //wyświetlenie tekstu tft.setCursor(250, 130); //ustawienie pozycji kursora tft.print("USTAW WAGE"); //wyświetlenie tekstu tft.setTextColor(WHITE); //ustawienie koloru tekstu tft.setCursor(159, 130); //ustawienie pozycji kursora tft.print("AKT. WAGA"); //wyświetlenie tekstu tft.setTextSize(2); //ustawienie rozmiaru tekstu tft.setCursor(355, 100); //ustawienie pozycji kursora tft.print("X"); //wyświetlenie tekstu tft.setCursor(255, 100); //ustawienie pozycji kursora tft.print(ustawgramy_B); //wyświetlenie tekstu tft.print("g"); //wyświetlenie tekstu tft.setCursor(180, 100); //ustawienie pozycji kursora tft.print("0"); //wyświetlenie tekstu }
Funkcja klawiatura, wyświetla całą klawiaturę wraz z ustawionymi gramami. Przyjmuje ona jeden argument i wyświetla aktualnie ustawione gramy.
void klawiatura(int g) { tft.fillScreen(BLACK); //wypełnij wyświetlacz czarnym kolorem tft.setTextColor(WHITE); //ustaw kolor tekstu na biały tft.setTextSize(3); //ustawienie rozmiaru tekstu tft.setCursor(22, 30); //ustawienie pozycji kursora tft.print(g); //wyświetlenie tekstu tft.setCursor(112, 30); //ustawienie pozycji kursora tft.print("g"); //wyświetlenie tekstu tft.setCursor(192, 30); //ustawienie pozycji kursora tft.print("1"); //wyświetlenie tekstu tft.setCursor(272, 30); //ustawienie pozycji kursora tft.print("2"); //wyświetlenie tekstu tft.setCursor(352, 30); //ustawienie pozycji kursora tft.print("3"); //wyświetlenie tekstu tft.setCursor(22, 110); //ustawienie pozycji kursora tft.print("GOTOWE"); //wyświetlenie tekstu tft.setCursor(192, 110); //ustawienie pozycji kursora tft.print("4"); //wyświetlenie tekstu tft.setCursor(272, 110); //ustawienie pozycji kursora tft.print("5"); //wyświetlenie tekstu tft.setCursor(352, 110); //ustawienie pozycji kursora tft.print("6"); //wyświetlenie tekstu tft.setCursor(112, 190); //ustawienie pozycji kursora tft.print("0"); //wyświetlenie tekstu tft.setCursor(32, 190); //ustawienie pozycji kursora tft.print("C"); //wyświetlenie tekstu tft.setCursor(192, 190); //ustawienie pozycji kursora tft.print("7"); //wyświetlenie tekstu tft.setCursor(272, 190); //ustawienie pozycji kursora tft.print("8"); //wyświetlenie tekstu tft.setCursor(352, 190); //ustawienie pozycji kursora tft.print("9"); //wyświetlenie tekstu tft.drawFastHLine(0, 0, 400, WHITE); //narysowanie linii poziomej tft.drawFastHLine(0, 80, 400, WHITE); //narysowanie linii poziomej tft.drawFastHLine(0, 160, 400, WHITE); //narysowanie linii poziomej tft.drawFastHLine(0, 239, 400, WHITE); //narysowanie linii poziomej tft.drawFastVLine(0, 0, 400, WHITE); //narysowanie linii pionowej tft.drawFastVLine(80, 160, 400, WHITE); //narysowanie linii pionowej tft.drawFastVLine(160, 0, 400, WHITE); //narysowanie linii pionowej tft.drawFastVLine(240, 0, 400, WHITE); //narysowanie linii pionowej tft.drawFastVLine(320, 0, 400, WHITE); //narysowanie linii pionowej tft.drawFastVLine(399, 0, 400, WHITE); //narysowanie linii pionowej }
Ostatnią i największą funkcją będzie wpiszGramy, odbiera ona wciśnięte przez użytkownika liczby i wysyła do funkcji ustawGramy. Funkcja posiada dwa argumenty, gdzie przyjmuje pozycje ekranu, aby mogła poprawnie działać.
void wpiszGramy(int xpos, int ypos) { if (xpos > 240) // jeżeli składowa x punktu jest większa od 240, czyli znajdujemy się w pierwszym wierszu { if (ypos > 106 && ypos < 154) { Serial.println("1"); //wyświetl w monitorze portu szeregowego ustawGramy(1); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } else if (ypos > 154 && ypos <= 202) { Serial.println("2"); //wyświetl w monitorze portu szeregowego ustawGramy(2); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } else if (ypos > 202 && ypos <= 250) { Serial.println("3"); //wyświetl w monitorze portu szeregowego ustawGramy(3); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } } else if (xpos > 120 && xpos <= 240) // jeżeli składowa x punktu jest większa od 120 i mniejsza od 240, czyli znajdujemy się w drugim wierszu { if (ypos > 0 && ypos < 106) { Serial.println("GOTOWE"); //wyświetl w monitorze portu szeregowego ustaw_wage_A = false; ustaw_wage_B = false; delay(500); //opoźnienie } else if (ypos > 106 && ypos < 154) { Serial.println("4"); //wyświetl w monitorze portu szeregowego ustawGramy(4); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } else if (ypos > 154 && ypos < 202) { Serial.println("5"); //wyświetl w monitorze portu szeregowego ustawGramy(5); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } else if (ypos > 202 && ypos < 250) { Serial.println("6"); //wyświetl w monitorze portu szeregowego ustawGramy(6); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } } else if (xpos < 120) //jeżeli składowa x punktu jest mniejsza od 120, czyli znajdujemy się w trzecim wierszu { if (ypos > 0 && ypos < 48) { Serial.println("C"); tft.setCursor(22, 30); tft.setTextColor(WHITE, BLACK); //ustawienie koloru tekstu i tła, pierwszy parametr kolor tekstu, drugi tła tft.print("0 "); //wyświetlenie 0 ze spacjami, żeby wyczyścić ekran w miejscu wpisywanych liczb if (ustaw_wage_A) //jeżeli jesteśmy w menu wagi A zerujemy wartości { last_number_A = 0; //zerujemy zmienną ustawgramy_A = 0; //zerujemy zmienną num_count_A = 0; //zerujemy zmienną } else if (ustaw_wage_B) //jeżeli jesteśmy w menu wagi B zerujemy wartości { last_number_B = 0; //zerujemy zmienną ustawgramy_B = 0; //zerujemy zmienną num_count_B = 0; //zerujemy zmienną } delay(500); } else if (ypos > 48 && ypos < 106) //zakres zera na wyświetlaczu { Serial.println("0"); //wyświetl w monitorze portu szeregowego ustawGramy(0); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } else if (ypos > 106 && ypos < 154) //zakres siódemki na wyświetlaczu { Serial.println("7"); //wyświetl w monitorze portu szeregowego ustawGramy(7); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } else if (ypos > 154 && ypos < 202) //zakres ósemki na wyświetlaczu { Serial.println("8"); //wyświetl w monitorze portu szeregowego ustawGramy(8); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } else if (ypos > 202 && ypos < 250) //zakres dziewiątki na wyświetlaczu { Serial.println("9"); //wyświetl w monitorze portu szeregowego ustawGramy(9); //wywołanie funkcji ustawGramy delay(500); //opoźnienie } } }