Arduino v příkladech - XI. díl - Displej - tlačítka trochu jinak
Kreslení tlačítek mě osobně vůbec nebaví. A když otočím displej, celé se to rozpadne. Řešení je přitom jednoduché. Tak pojďme počítat, použít definici pole typu struct, pak bombónek a na závěr kreslení barevných obrázků.
Kreslení vypočítaných tlačítek
Abychom stále nemuseli psát několikrák za sebou ttlačítko tady, tlačítko tamhle, spočítek pozici a ono to ještě není ono a ten text není zarovnaný na středu, vytvořil jsem pro Vás příklad, kde se tlačítka vypočítají podle pár zadaných hodnot a sami se přizpůsobí orientaci displeje. Za pomoci funkce drawButton(int place, int y, int height, int color, char* text, byte font) to bude mnohem jednodušší. Parametry: place – umístění (LEFT, CENTER, RIGHT), y – umístění na výšku, height – výška tlačítka, color – barva tlačítka, text – text tlačítka a font – typ písma.
I zpětná vazba pro dotykovou plochu je jednoduchá. Hodnoty x se pro dané umístění nemění, stačí zkopírovat z programu, pouze určujete pozici y.
//------------------------------------------------------------------
// inicializace zakladnich knihoven
#include <SPI.h> // knihovna pro komunikacni rozhrani SP
#include <TFT_ILI9341.h> // knihovna displeje
#include <UTouch.h> // knihovna dotykové části
//------------------------------------------------------------------
// nastaveni pinu displej
//#define sclk 13 // Don't change, this is the hardware SPI SCLK line
//#define miso 12 // Don't change, this is the hardware SPI MISO line
//#define mosi 11 // Don't change, this is the hardware SPI MOSI line
#define TFT_CS 10 // Chip select for TFT display, don't change when using F_AS_T
#define TFT_DC 9 // Data/command line, don't change when using F_AS_T
//#define TFT_RST 8 // Reset, you could connect this to the Arduino reset pin
#define TOUCH_CLK 7 // Touch SCLK
#define TOUCH_CS 6 // Touch chip select
#define TOUCH_DIN 5 // Touch MOSI
#define TOUCH_DOUT 4 // Touch MISO
#define TOUCH_IRQ 2 // Touch IRQ
//------------------------------------------------------------------
// Promenne pro urceni umisteni tlacitka
#define LEFT 0 // promenna pro urceni zobrazeni tlacitka
#define CENTER 1 // promenna pro urceni zobrazeni tlacitka
#define RIGHT 2 // promenna pro urceni zobrazeni tlacitka
//------------------------------------------------------------------
// Promenne a nastaveni vstupu displej
TFT_ILI9341 tft = TFT_ILI9341(TFT_CS, TFT_DC);
// UTouch(byte clk, cs, din, dout, irq)
UTouch touch(TOUCH_CLK, TOUCH_CS, TOUCH_DIN, TOUCH_DOUT, TOUCH_IRQ);
//------------------------------------------------------------------
// Promenne displej
unsigned long casProdlevyDotyk; // cas posledniho dotyku
const byte prodlevaDotyk = 200; // nastaveni prodlevy mezi dotykem
boolean vypniDotyk = true; // povoleni
byte TFT_rotation = 2; // nastaveni otoceni displeje
byte TOUCH_rotation; // nastaveni orientace dotykove plochy
int x; // radek x displej
int y; // radek y displej
//------------------------------------------------------------------
void setup() {
tft.init(); // inicializace TFT displeje
tft.setRotation(TFT_rotation); // nastaveni orientace displeje
tft.setTextColor(TFT_BLACK); // nastaveni barvy pisma
//------------------------------------------------------------------
if (TFT_rotation == 0 || TFT_rotation == 2) TOUCH_rotation = PORTRAIT; // nastaveni otoceni dotykove plochy
else if (TFT_rotation == 1 || TFT_rotation == 3) TOUCH_rotation = LANDSCAPE; // nastaveni otoceni dotykove plochy
touch.InitTouch(TOUCH_rotation); // inicializuje dotykovou plochu
touch.setPrecision(PREC_MEDIUM); // nastavi citlivost dotykove plochy
//------------------------------------------------------------------
// zobrazeni uvodni stranky
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
//------------------------------------------------------------------
// nakreslime prvni tlacitka
drawButton(CENTER, 60, 50, TFT_RED, "ON", 2); // nakresli tlacitko
drawButton(RIGHT, 230, 50, TFT_RED, "ON", 4); // nakresli tlacitko
drawButton(LEFT, 230, 50, TFT_RED, "ON", 1); // nakresli tlacitko
}
//------------------------------------------------------------------
void loop() {
//------------------------------------------------------------------
// cteni dotykoveho displeje
if (touch.dataAvailable()) { // kontrola prijatych dat z dotykoveho panelu
dotyk(); // spust program dotyk
}
}
//------------------------------------------------------------------
void dotyk() {
//------------------------------------------------------------------
// omezeni opakovaneho stisku tlacitka
if (!vypniDotyk) { // kdyz je dotyk vypnuty
if ((unsigned long)(millis() - casProdlevyDotyk) >= prodlevaDotyk) { // pokud uplynula stanovena doba
vypniDotyk = true; // zapni dotyk
}
}
//------------------------------------------------------------------
// cteni hodnot z dotykoveho displeje
if (vypniDotyk) { // kdyz je dotyk zapnuty
casProdlevyDotyk = millis(); // nastav novy cas pro vypocet prodlevy
vypniDotyk = false; // vypni docasne dotyk
touch.read(); // pokud jsou data precte je a ulozi do promenych
x = touch.getX();
y = touch.getY();
//------------------------------------------------------------------
// overeni stisku tlacitka a spusteni souvisejici akce
if ((x != -1) && (y != -1)) { // a když není x a y menší než 0 ...
if ((x >= 60 && x <= 180) && (y >= 60 && y <= 110)) { // tlacitko na stredu
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
drawButton(LEFT, 230, 50, TFT_RED, "ON", 1); // nakresli tlacitko
}
else if ((x >= 10 && x <= 110) && (y >= 230 && y <= 280)) { // tlacitko vlevo
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
drawButton(RIGHT, 230, 50, TFT_RED, "ON", 4); // nakresli tlacitko
}
else if ((x >= 130 && x <= 230) && (y >= 230 && y <= 280)) { // tlacitko vpravo
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
drawButton(CENTER, 60, 50, TFT_RED, "ON", 2); // nakresli tlacitko
}
}
}
}
//------------------------------------------------------------------
// funkce kresleni tlacitka
void drawButton(int place, int y, int height, int color, char* text, byte font) {
int x = tft.width(); // zjisteni sirky displeje
int width = 100; // sirka tlacitka pro umisteni vlevo a vpravo
//------------------------------------------------------------------
if (place == 0) x = (x / 2) - (x / 4); // urceni x pro tlacitko vlevo
else if (place == 1) { // tlacitko uprostred
x = x / 2; // urceni x pro tlacitko uprostred
width = 120; // urceni sirky pro tlacitko uprostred
}
else if (place == 2) x = (x / 2) + (x / 4); // urceni x pro tlacitko vpravo
//------------------------------------------------------------------
tft.fillRoundRect((x - (width / 2)) - 1, y - 1, width + 2, height + 2, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(x - (width / 2), y, width, height, 10, color); // zobrazeni tlacitka
//------------------------------------------------------------------
if (font == 4 ) y = (y + (height / 2)) - 10; // urceni pozice y pro font 4
else if (font == 2 ) y = (y + (height / 2)) - 8; // urceni pozice y pro font 2
else y = (y + (height / 2)) - 3; // urceni pozice y pro font 1
//------------------------------------------------------------------
tft.drawCentreString(text, x, y, font); // zobrazeni textu
}
Tlačítka definované polem struct
Existuje přehlednější řešení za pomoci pole struct. Pro začátečníky to bude novinka, ale snařil jsem se to napsat opravdu jednoduše. Jak na to. V hlavičce pole jsme definovali pole struct a pak jednotlivá tlačítka jako globální proměnné. Pak už je pouze voláme v jednotlivých funkcích. Pouze se nesmí zapomenout předpona např. drawButton(button1); Tak tlačítka nejen kreslíme, ale dotazujeme se i na stisknuté tlačítko. Pro ukázku jsme využili předchozí program, který se nám poněkud prodloužil, úložiště mi snad odpustí, ale výrazně se zjednodušilo psaní a čtení programu. Také jsem pro ukázku přidal čtvrté tlačítko, kde uvidíte jak na základě nějaké podmínky měnit barvu a text tlačítka přímo v poli struct a potom opět jenom kreslíme.
//------------------------------------------------------------------
// inicializace zakladnich knihoven
#include <SPI.h> // knihovna pro komunikacni rozhrani SP
#include <TFT_ILI9341.h> // knihovna displeje
#include <UTouch.h> // knihovna dotykové části
//------------------------------------------------------------------
// nastaveni pinu displej
//#define sclk 13 // Don't change, this is the hardware SPI SCLK line
//#define miso 12 // Don't change, this is the hardware SPI MISO line
//#define mosi 11 // Don't change, this is the hardware SPI MOSI line
#define TFT_CS 10 // Chip select for TFT display, don't change when using F_AS_T
#define TFT_DC 9 // Data/command line, don't change when using F_AS_T
//#define TFT_RST 8 // Reset, you could connect this to the Arduino reset pin
#define TOUCH_CLK 7 // Touch SCLK
#define TOUCH_CS 6 // Touch chip select
#define TOUCH_DIN 5 // Touch MOSI
#define TOUCH_DOUT 4 // Touch MISO
#define TOUCH_IRQ 2 // Touch IRQ
//------------------------------------------------------------------
// Promenne pro urceni umisteni tlacitka
#define LEFT 0 // promenna pro urceni zobrazeni tlacitka
#define CENTER 1 // promenna pro urceni zobrazeni tlacitka
#define RIGHT 2 // promenna pro urceni zobrazeni tlacitka
//------------------------------------------------------------------
// Promenne a nastaveni vstupu displej
TFT_ILI9341 tft = TFT_ILI9341(TFT_CS, TFT_DC);
// UTouch(byte clk, cs, din, dout, irq)
UTouch touch(TOUCH_CLK, TOUCH_CS, TOUCH_DIN, TOUCH_DOUT, TOUCH_IRQ);
//------------------------------------------------------------------
// Promenne displej
unsigned long casProdlevyDotyk; // cas posledniho dotyku
const byte prodlevaDotyk = 200; // nastaveni prodlevy mezi dotykem
boolean vypniDotyk = true; // povoleni
byte TFT_rotation = 2; // nastaveni otoceni displeje
byte TOUCH_rotation; // nastaveni orientace dotykove plochy
int x; // radek x displej
int y; // radek y displej
//------------------------------------------------------------------
// Vytvoreni promennych pro tlacitka
struct defineButton {
int place;
int y;
int height;
int color;
char* text;
byte font;
};
//------------------------------------------------------------------
// Vytvoreni jednotlivych tlacitek
defineButton button1 = {CENTER, 60, 50, TFT_RED, "CENTER", 2};
defineButton button2 = {RIGHT, 230, 50, TFT_RED, "RIGHT", 4};
defineButton button3 = {LEFT, 230, 50, TFT_RED, "LEFT", 1};
defineButton button4 = {CENTER, 140, 50, TFT_RED, "OFF", 4};
//------------------------------------------------------------------
void setup() {
tft.init(); // inicializace TFT displeje
tft.setRotation(TFT_rotation); // nastaveni orientace displeje
tft.setTextColor(TFT_BLACK); // nastaveni barvy pisma
//------------------------------------------------------------------
if (TFT_rotation == 0 || TFT_rotation == 2) TOUCH_rotation = PORTRAIT; // nastaveni otoceni dotykove plochy
else if (TFT_rotation == 1 || TFT_rotation == 3) TOUCH_rotation = LANDSCAPE; // nastaveni otoceni dotykove plochy
touch.InitTouch(TOUCH_rotation); // inicializuje dotykovou plochu
touch.setPrecision(PREC_MEDIUM); // nastavi citlivost dotykove plochy
//------------------------------------------------------------------
// zobrazeni uvodni stranky
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
//------------------------------------------------------------------
// nakreslime prvni tlacitka
drawButton(&button1); // nakresli tlacitko
drawButton(&button2); // nakresli tlacitko
drawButton(&button3); // nakresli tlacitko
drawButton(&button4); // nakresli tlacitko
}
//------------------------------------------------------------------
void loop() {
//------------------------------------------------------------------
// cteni dotykoveho displeje
if (touch.dataAvailable()) { // kontrola prijatych dat z dotykoveho panelu
dotyk(); // spust program dotyk
}
}
//------------------------------------------------------------------
void dotyk() {
//------------------------------------------------------------------
// omezeni opakovaneho stisku tlacitka
if (!vypniDotyk) { // kdyz je dotyk vypnuty
if ((unsigned long)(millis() - casProdlevyDotyk) >= prodlevaDotyk) { // pokud uplynula stanovena doba
vypniDotyk = true; // zapni dotyk
}
}
//------------------------------------------------------------------
// cteni hodnot z dotykoveho displeje
if (vypniDotyk) { // kdyz je dotyk zapnuty
casProdlevyDotyk = millis(); // nastav novy cas pro vypocet prodlevy
vypniDotyk = false; // vypni docasne dotyk
touch.read(); // pokud jsou data precte je a ulozi do promenych
x = touch.getX();
y = touch.getY();
//------------------------------------------------------------------
// overeni stisku tlacitka a spusteni souvisejici akce
if ((x != -1) && (y != -1)) { // a když není x a y menší než 0 ...
if (checkTouch(&button1)) { // tlacitko na stredu
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
drawButton(&button3); // nakresli tlacitko
drawButton(&button4); // nakresli tlacitko
}
else if (checkTouch(&button3)) { // tlacitko vlevo
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
drawButton(&button2); // nakresli tlacitko
drawButton(&button4); // nakresli tlacitko
}
else if (checkTouch(&button2)) { // tlacitko vpravo
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
drawButton(&button1); // nakresli tlacitko
drawButton(&button4); // nakresli tlacitko
}
else if (checkTouch(&button4)) { // tlacitko zap/vyp menime barvu
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
drawButton(&button1); // nakresli tlacitko
drawButton(&button2); // nakresli tlacitko
drawButton(&button3); // nakresli tlacitko
//------------------------------------------------------------------
// zkontrolujeme barvu tlacitka a nastavime nove hodnoty
if (button4.color == TFT_RED) { // zkontrolujeme stav tlacitka
button4.color = TFT_GREEN; // nastavime novou barvu
button4.text = "ON"; // nastavime novy text
}
else {
button4.color = TFT_RED; // nastavime novou barvu
button4.text = "OFF"; // nastavime novy text
}
drawButton(&button4); // nakresli tlacitko
}
}
}
}
//------------------------------------------------------------------
// kontrola zda bylo stisknuto tlacitko
boolean checkTouch (struct defineButton *b) {
boolean press = false; // hodnota pro potvrzeni stisku
int xTouch = tft.width(); // zjisteni sirky displeje
int width = 100 / 2; // sirka tlacitka pro umisteni vlevo a vpravo
//------------------------------------------------------------------
if (b->place == 0) xTouch = (xTouch / 2) - (xTouch / 4); // urceni x pro tlacitko vlevo
else if (b->place == 1) { // tlacitko uprostred
xTouch = xTouch / 2; // urceni x pro tlacitko uprostred
width = 120 / 2; // urceni sirky pro tlacitko uprostred
}
else if (b->place == 2) xTouch = (xTouch / 2) + (xTouch / 4); // urceni x pro tlacitko vpravo
if ((x >= (xTouch - (width)) && x <= (xTouch + (width))) && (y >= b->y && y <= (b->y + b->height))) {
press = true; // nastav novou hodnotu
}
return press; // vrat hodnotu
}
//------------------------------------------------------------------
// funkce kresleni tlacitka
void drawButton(struct defineButton *b) {
int xTouch = tft.width(); // zjisteni sirky displeje
int width = 100; // sirka tlacitka pro umisteni vlevo a vpravo
int yText; // pozice textu
//------------------------------------------------------------------
if (b->place == 0) xTouch = (xTouch / 2) - (xTouch / 4); // urceni x pro tlacitko vlevo
else if (b->place == 1) { // tlacitko uprostred
xTouch = xTouch / 2; // urceni x pro tlacitko uprostred
width = 120; // urceni sirky pro tlacitko uprostred
}
else if (b->place == 2) xTouch = (xTouch / 2) + (xTouch / 4); // urceni x pro tlacitko vpravo
//------------------------------------------------------------------
tft.fillRoundRect((xTouch - (width / 2)) - 1, b->y - 1, width + 2, b->height + 2, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(xTouch - (width / 2), b->y, width, b->height, 10, b->color); // zobrazeni tlacitka
//------------------------------------------------------------------
if (b->font == 4 ) yText = (b->y + (b->height / 2)) - 10; // urceni pozice y pro font 4
else if (b->font == 2 ) yText = (b->y + (b->height / 2)) - 8; // urceni pozice y pro font 2
else yText = (b->y + (b->height / 2)) - 3; // urceni pozice y pro font 1
//------------------------------------------------------------------
tft.drawCentreString(b->text, xTouch, yText, b->font); // zobrazeni textu
}
V poli struct můžete definovat celé tlačítko a nic nemusíte počítat. To je jeho velká výhoda.
Zpět k počítání - klávesnice
Tak tohle to může napsat jenom masochista. Vlastně jsem to napsal, aby bylo možné nakreslit jednoduše sadu tlačítek, třeba jako klávesnici. Jenom zadáte hodnoty, řeknete programu na jaké stránce se jaká klávesnice nachází a celé se to jenom počítá. Je tam i popis jak s tím pracovat.
//------------------------------------------------------------------
// inicializace zakladnich knihoven
#include <SPI.h> // knihovna pro komunikacni rozhrani SP
#include <TFT_ILI9341.h> // knihovna displeje
#include <UTouch.h> // knihovna dotykové části
//------------------------------------------------------------------
// nastaveni pinu displej
//#define sclk 13 // Don't change, this is the hardware SPI SCLK line
//#define miso 12 // Don't change, this is the hardware SPI MISO line
//#define mosi 11 // Don't change, this is the hardware SPI MOSI line
#define TFT_CS 10 // Chip select for TFT display, don't change when using F_AS_T
#define TFT_DC 9 // Data/command line, don't change when using F_AS_T
//#define TFT_RST 8 // Reset, you could connect this to the Arduino reset pin
#define TOUCH_CLK 7 // Touch SCLK
#define TOUCH_CS 6 // Touch chip select
#define TOUCH_DIN 5 // Touch MOSI
#define TOUCH_DOUT 4 // Touch MISO
#define TOUCH_IRQ 2 // Touch IRQ
//------------------------------------------------------------------
// Promenne a nastaveni vstupu displej
TFT_ILI9341 tft = TFT_ILI9341(TFT_CS, TFT_DC);
// UTouch(byte clk, cs, din, dout, irq)
UTouch touch(TOUCH_CLK, TOUCH_CS, TOUCH_DIN, TOUCH_DOUT, TOUCH_IRQ);
//------------------------------------------------------------------
// Promenne displej
unsigned long casProdlevyDotyk; // cas posledniho dotyku
const byte prodlevaDotyk = 200; // nastaveni prodlevy mezi dotykem
boolean vypniDotyk = true; // povoleni
byte TFT_rotation = 2; // nastaveni otoceni displeje
byte TOUCH_rotation; // nastaveni orientace dotykove plochy
int x; // radek x displej
int y; // radek y displej
//------------------------------------------------------------------
// promenne ktere je nutne vytvorit na globalni urovni
#define MAX_POCET_TLACITEK 12 // nastaveni maximalniho poctu tlacitek v ramci celeho displeje
//------------------------------------------------------------------
// data klavesnice zobrazeni na displej - nastavuji se u konkretniho zobrazeni
char* textT[MAX_POCET_TLACITEK]; // text jednotlivych tlacitek
byte cisloKlavesnice; // nastavte cislo klavesnice
int ttfs; // sirka vykresleni tlacitek (displeje)
int ttfv; // vyska vykresleni tlacitek spodni hrana (displeje)
byte ptls; // pocet tlacitek do sirky
byte ptlv; // počet tlacitek do vysky
byte tv; // vyska tlacitka
byte ts; // sirka tlacitka - vypoctena
byte ob; // oblouk rohu tlacitka
byte m; // mezera mezi tlacitky
char charText[8]; // promenna pro zobrazeni textu
byte pozice; // promenna pro vypocet umisteni pole
int bx[MAX_POCET_TLACITEK]; // nutno zadat rucne pocet poli = pocet tlacitek, muze byt vice
int by[MAX_POCET_TLACITEK]; // nutno zadat rucne pocet poli = pocet tlacitek, muze byt vice
byte pocitadloS; // promenna sirka pro cyklus for
byte pocitadloV; // promenna vyska pro cyklus for
int poleX; // pozice pole pro zobrazeni hodnot
int poleY; // pozice pole pro zobrazeni hodnot
int poleD; // delka pole pro zobrazeni hodnot
int poleV; // pozice pole pro zobrazeni hodnot
int obPole; // oblouk rohu pole pro zobrazeni hodnot
int barvaT[MAX_POCET_TLACITEK]; // barva jednotlivych tlacitek
int barvaPisma; // barva pisma a pozadi
int barvaPozadi; // barva pozadi
int barvaObrys; // barva obrysu
//------------------------------------------------------------------
// data pro textové pole klavesnice
byte TEXT_MAX; // maximalni pocet znaku pole
String textPole = ""; // promenna pro zobrazeni hodnot na displeji
byte textPole_i = 0; // promenna pro index poli
//------------------------------------------------------------------
void setup(void) {
tft.init(); // inicializace TFT displeje
tft.setRotation(TFT_rotation); // nastaveni orientace displeje
tft.setTextColor(TFT_BLACK); // nastaveni barvy pisma
//------------------------------------------------------------------
if (TFT_rotation == 0 || TFT_rotation == 2) TOUCH_rotation = PORTRAIT; // nastaveni otoceni dotykove plochy
else if (TFT_rotation == 1 || TFT_rotation == 3) TOUCH_rotation = LANDSCAPE; // nastaveni otoceni dotykove plochy
touch.InitTouch(TOUCH_rotation); // inicializuje dotykovou plochu
touch.setPrecision(PREC_MEDIUM); // nastavi citlivost dotykove plochy
//------------------------------------------------------------------
// zobrazeni uvodni stranky
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
//------------------------------------------------------------------
klavesnice(); // zobrazeni klavesnice
}
//------------------------------------------------------------------
void loop() {
//------------------------------------------------------------------
// cteni dotykoveho displeje
if (touch.dataAvailable()) { // kontrola prijatych dat z dotykoveho panelu
dotyk();
}
}
void dotyk () {
//------------------------------------------------------------------
// omezeni opakovaneho stisku tlacitka
if (!vypniDotyk) { // kdyz je dotyk vypnuty
if ((unsigned long)(millis() - casProdlevyDotyk) >= prodlevaDotyk) { // pokud uplynula stanovena doba
vypniDotyk = true; // zapni dotyk
}
}
//------------------------------------------------------------------
// cteni hodnot z dotykoveho displeje
if (vypniDotyk) { // kdyz je dotyk zapnuty
casProdlevyDotyk = millis(); // nastav novy cas pro vypocet prodlevy
vypniDotyk = false; // vypni docasne dotyk
touch.read(); // pokud jsou data precte je a ulozi do promenych
x = touch.getX();
y = touch.getY();
//------------------------------------------------------------------
// zjisteni stavu stranek, overeni stisku tlacitka a spusteni souvisejiciho programu
if ((x != -1) && (y != -1)) { // a když není x a y menší než 0 ...
//------------------------------------------------------------------
// kontrola stisku klavesy
for (pozice = 0; pozice < (ptls * ptlv); pozice++) { // nastav pozici
if ((x >= bx[pozice] && x <= bx[pozice] + ts) && (y >= by[pozice] && y <= by[pozice] + tv)) { // zkontroluj stisknute tlacitko
pole(); // spust reakci na dotyk
break; // kdyz odpovida stisknute tlacitko ukonci cyklus
}
}
}
}
}
//------------------------------------------------------------------
void pole() { //pole zobrazeni hodnot a akce na tlacitka
//------------------------------------------------------------------
tft.setTextColor(barvaPisma, barvaPozadi); // nastav barvu a pozadi textoveho pole
//------------------------------------------------------------------
switch (pozice) {
case 9: // kdyz je stisknuto tlacitko Esc (nutno snizit o 1 - pocita se od 0)
if (textPole != "") { // kdyz pole neni prazdne
textPole_i --; // zmensi index pole o jednu hodnuto
textPole = textPole.substring(0, textPole_i); // zmensi text o jednu hodnotu
textPole.toCharArray(charText, TEXT_MAX + 1); // preved string na char
tft.fillRoundRect(poleX + 1, poleY + 1, poleD - 2, poleV - 2, obPole, barvaPozadi); // vycisti pole
tft.drawCentreString(charText, poleX + (poleD / 2), poleY + (poleV / 2) - 10, 4); // nakresli text
}
else { // jinak se vrat na predchozi stranu
klavesnice(); // navrat na predchozi stranku
}
break;
case 11: // kdyz je stisknuto tlacitko OK (nutno snizit o 1 - pocita se od 0)
klavesnice(); // zobraz dalsi stranku
break;
default: // kdyz neni splnena zadna predchozi podminka
if (textPole_i < TEXT_MAX) { // kdyz je delka retezce mensi nez max povolena
textPole = textPole + String(textT[pozice]);
textPole.toCharArray(charText, TEXT_MAX + 1); // preved string na char
tft.drawCentreString(charText, poleX + (poleD / 2), poleY + (poleV / 2) - 10, 4); // nakresli text
textPole_i ++;
}
break;
}
}
//------------------------------------------------------------------
void tlacitka() { // zobrazeni klavesnice
//------------------------------------------------------------------
// vypocet a doplneni promennych
ts = (ttfs - ((ptls + 1) * m)) / ptls; // sirka tlacitka - vypoctena
y = ttfv - (ptlv * m + ptlv * tv); // vypocet prvni rady tlacitek
//------------------------------------------------------------------
// nastav promenne
textPole = ""; // vycisti pole pro dalsi zpracovani
textPole_i = 0; // vycisti index pole pro dalsi zpracovani
//------------------------------------------------------------------
// nastaveni pro zobrazeni
tft.setTextColor(barvaPisma); // nastaveni barvy pisma
tft.fillScreen(barvaPozadi); // nastaveni pozadi
//------------------------------------------------------------------
// nakresli tlacitka
for (pocitadloV = 1; pocitadloV <= ptlv; pocitadloV++) { // podminka pro kresleni tlacitek do vysky
for (pocitadloS = 1; pocitadloS <= ptls; pocitadloS++) { // podminka pro kresleni tlacitek do sirky
pozice = ((pocitadloV - 1) * ptls) + pocitadloS - 1; // vypocet umisteni pole
tft.fillRoundRect((pocitadloS * m) + ((pocitadloS - 1) * ts), y, ts, tv, ob, barvaObrys); // naktesli obrys
tft.fillRoundRect((pocitadloS * m) + ((pocitadloS - 1) * ts) + 1, y + 1, ts - 2, tv - 2, ob, barvaT[pozice]); // nakresli vypln
tft.drawCentreString(textT [pozice], (pocitadloS * m) + (pocitadloS * ts) - (ts / 2), y + (tv / 2) - 10, 4); // nakresli text
bx [pozice] = (pocitadloS * m) + ((pocitadloS - 1) * ts); // vypln promennou pro dotyk
by [pozice] = y; //vypln promennou pro dotyk
}
y = y + (m + tv); // vypocti novy radek
}
//------------------------------------------------------------------
// pole pro zobrazeni stisknutych hodnot
tft.drawRoundRect(poleX, poleY, poleD, poleV, obPole, barvaObrys); // naktesli obrys
}
//------------------------------------------------------------------
void klavesnice() {
//------------------------------------------------------------------
// klavesnice promenne - nutno zadat
cisloKlavesnice = 0; // nastavte cislo klavesnice
ttfs = 240; // sirka vykresleni tlacitek (displeje)
ttfv = 320; // vyska vykresleni tlacitek spodni hrana (displeje)
ptls = 3; // pocet tlacitek do sirky
ptlv = 4; // počet tlacitek do vysky
ob = 0; // oblouk rohu tlacitka
m = 2; // mezera mezi tlacitky
tv = 55; // vyska tlacitka
poleX = 60; // pozice pole pro zobrazeni hodnot
poleY = 30; // pozice pole pro zobrazeni hodnot
poleD = 120; // delka pole pro zobrazeni hodnot
poleV = 40; // pozice pole pro zobrazeni hodnot
obPole = 0; // oblouk rohu pole pro zobrazeni hodnot
TEXT_MAX = 6; // maximalni pocet znaku pole
char* textTlacitka[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "End", "0", "OK"}; // text tlacitek
int barvaTlacitka[] = {TFT_LIGHTGREY, TFT_LIGHTGREY, TFT_LIGHTGREY, // barva jednotlivych tlacitek
TFT_LIGHTGREY, TFT_LIGHTGREY, TFT_LIGHTGREY,
TFT_LIGHTGREY, TFT_LIGHTGREY, TFT_LIGHTGREY,
TFT_RED, TFT_LIGHTGREY, TFT_GREEN
};
barvaPisma = TFT_BLACK; // barva pisma a pozadi
barvaPozadi = TFT_WHITE; // barva pozadi
barvaObrys = TFT_BLACK; // barva obrysu
//------------------------------------------------------------------
// vypocet a doplneni promennych
int max_i = ptls * ptlv;
int i;
for (i = 0; i < max_i; i++) { // vyplneni textu tlacitek do globalni promenne
textT[i] = textTlacitka[i];
}
for (i = 0; i < max_i; i++) { // vyplneni barvy tlacitek do globalni promenne
barvaT[i] = barvaTlacitka[i];
}
//------------------------------------------------------------------
// zobraz klavesnici
tlacitka();
}
/***************************** KLAVESNICE ******************************
Sketch pro vytvoreni klavesnice, doplneni a ukladani hodnot pro dalsi zpracovani.
JEDNA KLAVESNICE
1) vyplnte prommene void klavesnice()
2) upravte void pole() podle toho co maji tlacitka vykonavat
3) upravte hodnotu #define MAX_POCET_TLACITEK ..
VICE KLAVESNIC
1) vyplnte prommene void klavesnice(), pro kazdou dalsi vytvorte void klavesnice1, 2, ...
2) nastavte promennou byte cisloKlavesnice 1, 2, ...
3) v casti void dotyk zmente pole(); na:
switch (cisloKlavesnice) {
case 0:
pole(); // pro klavesnici 0
break;
case 1; // pro klavesnici 1
pole1();
break;
case 2; // pro klavesnici 2 atd.
pole2();
break;
}
4) pro kazdou klavesnici vytvorte void pole1, 2, ...
nebo upravte konec bloku funkce podle zobrazene stranky
5) upravte hodnotu #define MAX_POCET_TLACITEK ..
Pro dalsi pouziti je urcena promenna textPole
*********** Preji prijemne uzivani bez nesrozumitelnych knihoven **********/
Program není dlouhý, ale když ho teď čtu, vůbec ty výpočty nechápu. Proto žádný smysluplný komentář. Myslím že není důležitý, prostě to funguje jak má, bez zbytečných překvapení. Často se k této klávesnici vracím.
Kreslíme obrázky
Nakreslit kulatá tlačítka se šipkou, sluníčko, měsíček není problém. Ale barevnou ikonu prostě nenakreslíte a když se o to pokusíte, stejně to nebude ono. Rád displeje obohacuji o ikony, které zobrazují stavy a současně jsou uloženy přímo v paměti Arduiona. Ono zobrazovat obrázky z karty SD, nebo jiné externí paměti, je totiž příšerně pomalé a práce s displejem pozbývá na radosti. Jestli nemáte zkušenosti se struct, toto bude složitější disciplína.
Pokud budete kreslit obrázky, začněte tím, že uložíte obrázek ve formátu BMP o 24 bit barevné hloubce a velikosti, kterou budete zobrazovat. V knihovně displeje ve složce Tools, otevřete program ImageConverter565.exe. Otevřete soubor, případně v poli Array Name změňte název. Ostatní pole nechte jak jsou. Stiskněte Save, a uložte kamkoli jinam než je adresář programu. Tím by příprava mohla skončit. Jinak ještě doporučuji otevřít soubor v textovém editoru a obsah souboru překopírovat do nového, který uložíte např. jako icons.h Tady je důležitá ta přípona. Každou další ikonu nakopírujte opět do tohoto souboru. Jenom až budete kopírovat, nechte #include <avr/pgmspace.h> pouze jednou. Doporučuji kopírovat i Hlavičku, pomůže Vám to při hledání a změně ikon.
A teď už vlastní program. Připomínám že používáme Arduino IDE. Do záhlaví programu si vložte #include "icons.h" a můžete i #include <avr/pgmspace.h>, nezapomeňte to ale vymazat ze souboru icons.h. Pak v nabídce Projekt vyberte Přidat soubor a potvrďte výběr, odklikněte případnou hlášku, zavřete a znovu otevřete program. Teď budete mít soubor v samostatné záložce. Pak stačí nahrát a zobrazit na displeji. Další obrázky už můžete vkládat přímo do záložky icons.h.
//------------------------------------------------------------------
// inicializace zakladnich knihoven
#include <SPI.h> // knihovna pro komunikacni rozhrani SP
#include <TFT_ILI9341.h> // knihovna displeje
#include <UTouch.h> // knihovna dotykové části
//------------------------------------------------------------------
// cast pro zobrazeni ikon
#include "icons.h" // soubor s ikonami
#include <avr/pgmspace.h> // knihovna pro zpracovani obrazku (ikon)
#define BUFF_SIZE 20 // nastaveni velikosti bufferu pro zpracovani ikon
//------------------------------------------------------------------
// nastaveni pinu displej
//#define sclk 13 // Don't change, this is the hardware SPI SCLK line
//#define miso 12 // Don't change, this is the hardware SPI MISO line
//#define mosi 11 // Don't change, this is the hardware SPI MOSI line
#define TFT_CS 10 // Chip select for TFT display, don't change when using F_AS_T
#define TFT_DC 9 // Data/command line, don't change when using F_AS_T
//#define TFT_RST 8 // Reset, you could connect this to the Arduino reset pin
#define TOUCH_CLK 7 // Touch SCLK
#define TOUCH_CS 6 // Touch chip select
#define TOUCH_DIN 5 // Touch MOSI
#define TOUCH_DOUT 4 // Touch MISO
#define TOUCH_IRQ 2 // Touch IRQ
//------------------------------------------------------------------
// Promenne a nastaveni vstupu displej
TFT_ILI9341 tft = TFT_ILI9341(TFT_CS, TFT_DC);
// UTouch(byte clk, cs, din, dout, irq)
UTouch touch(TOUCH_CLK, TOUCH_CS, TOUCH_DIN, TOUCH_DOUT, TOUCH_IRQ);
//------------------------------------------------------------------
// Promenne displej
unsigned long casProdlevyDotyk; // cas posledniho dotyku
const byte prodlevaDotyk = 200; // nastaveni prodlevy mezi dotykem
boolean vypniDotyk = true; // povoleni
byte TFT_rotation = 2; // nastaveni otoceni displeje
byte TOUCH_rotation; // nastaveni orientace dotykove plochy
int x; // radek x displej
int y; // radek y displej
//------------------------------------------------------------------
void setup() {
tft.init(); // inicializace TFT displeje
tft.setRotation(TFT_rotation); // nastaveni orientace displeje
tft.setTextColor(TFT_BLACK); // nastaveni barvy pisma
//------------------------------------------------------------------
if (TFT_rotation == 0 || TFT_rotation == 2) TOUCH_rotation = PORTRAIT; // nastaveni otoceni dotykove plochy
else if (TFT_rotation == 1 || TFT_rotation == 3) TOUCH_rotation = LANDSCAPE; // nastaveni otoceni dotykove plochy
touch.InitTouch(TOUCH_rotation); // inicializuje dotykovou plochu
touch.setPrecision(PREC_MEDIUM); // nastavi citlivost dotykove plochy
//------------------------------------------------------------------
// zobrazeni uvodni stranky
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
//------------------------------------------------------------------
// nakreslime ikonu
drawIcon(warning, 96, 136, 48, 48); // zobraz ikonu pozor
}
//------------------------------------------------------------------
void loop() {
// hlavni smycku nechame prazdnou
}
//------------------------------------------------------------------
// funkce pro kresleni ikony
void drawIcon(const unsigned short* icon, int16_t x, int16_t y, int8_t width, int8_t height) {
uint16_t pix_buffer[BUFF_SIZE];
tft.setAddrWindow(x, y, x + width - 1, y + height - 1);
uint16_t nb = ((uint16_t)height * width) / BUFF_SIZE;
// kresleni obrazku
for (int i = 0; i < nb; i++) {
for (int j = 0; j < BUFF_SIZE; j++) {
pix_buffer[j] = pgm_read_word(&icon[i * BUFF_SIZE + j]);
}
tft.pushColors(pix_buffer, BUFF_SIZE);
}
uint16_t np = ((uint16_t)height * width) % BUFF_SIZE;
if (np) {
for (int i = 0; i < np; i++) pix_buffer[i] = pgm_read_word(&icon[nb * BUFF_SIZE + i]);
tft.pushColors(pix_buffer, np);
}
}
Soubor icons.h ke stažení zde.
S obrázky v paměti FLASH pracujte opatrně. Kreslíme pár tlačítek, nic neděláme a stále se pohybujeme nad 50% paměti Flash. Obrázek je co bod to int, tedy 48x48 bodů = 2 304 bodů = 4 608 byt v paměti FLASH. UNO má celkem 32 256 byt. To ubývá opravdu rychle. Proto moje projekty s displejem často končí na Arduino MEGA.
Závěr:
Na Arduinu se mi líbí, že žádná cesta není špatně. Jenom některé z nich jsou kostrbatější. Programovat tlačítka můžete jak se Vám zachce. Počítání je dobré, když se předpokládá, že se displej za provozu bude otáčet. Osobně používám variantu struct, občas v kombinaci s výpočty a když kreslím textové klávesnice, tak variantu klávesnice. Struct má výhodu, že ušetříte spoustu místa a kód je přehledný.
Příště se podíváme na zobrazování teplot. Že je to triviální. Takto uchopený program pro čtení teplot nikde nenajdete.
JB
Přidat komentář
Přehled komentářů
-
TFT 320 QDT
(Peter, 2. 1. 2018 19:54:05)
Odpovědět
Mám tento displej a problém je že po nahratí dema k tomuto TFT my tlačítka fungujú opačne to znamená keď pri Butomteste chcem kliknuť č.1 ktoré v pravo hore tak musím kliknúť v pravo dole . Dá sa s tým niečo urobiť?