Arduino v příkladech - X. díl - Displej - tlačítka a akce
Displej máme zapojený, kalibrovaný, hlavně funguje a známe příkazy. To hlavní máme za sebou a teď se zaměříme na to jak ho využít. Základem je tlačítko, které spustí příkaz. A to je to, na co se zaměříme v tomto článku.
Hlavním popisem tedy bude práce s dotykovou plochou. Pro zapojení nám stačí to, co máme z minulého dílu. Pouze si k pinu 3 připojíme přes odpor diodu. Začneme popisem dotykové plochy.
Dotyková plocha
V úvodním dílu k displejům jste si jistě všimli, že když držíte stisknutou dotykovou plochu, neustále se vrací koordináty stisku a to ve frekvenci, než se provedou další příkazy, které jsou, nakresli kolečko, pošli na Serial koordináty stisku. To je dobré pro kreslení na displej, ale pro práci stiskni a zapni je to naprosto nevhodné. Také funkce kontroly stisku dotykové plochy nevyužívá přerušení, tedy pokud budete mít smyčku, která trvá déle než několik desítek milisekund, může se Vám stát, že stisknete dotykovou plochu a nic se nestane.
Jakou kombinaci možností tedy máme:
Stisknutím dotykové plochy způsobíme, že se stav pinu T_IRQ změní z LOW na HIGH. Dotaz touch.dataAvailable() nám vrací pouze stav pinu.
- Po stisku displeje počkáme, až dojde řada na kontrolu stisku a provedeme akci, to se opakuje ve smyčce. Vhodné pro kreslení na displej.
- Po stisku displeje počkáme, až dojde řada na kontrolu stisku a provedeme akci, pak na určitou dobu vypneme dotyk, aby nedocházelo k opakované akci. Jednoduché, ale pokud používáte delay(), případně máte jiné dlouhé časově náročné funkce, nespolehlivé.
- Po stisku displeje, vyvoláme přerušení a provedeme akci. Složité, ne na všech arduinech funguje korektně. Některé knihovny funkci přerušení vypínají.
Na první pohled se může zdát, že je nejlepší možnost s řerušením. ANO i NE – pokud ho chcete používat, doporučuji si buď na základě přerušení vytvořit značku a příkaz provést až na něj přijde řada, nebo si přerušení do vykonání příkazu vypnout, ale to se vracíme k variantě dva.
Samozřejmě i v průběhu práce s displejem lze využívat kombinaci všech tří možností čtení stisku dotykové plochy. Dokážu si představit, chci nechat vzkaz – režim jedna malujeme, normálně zapínám a vypínám – režim dva nespěchám a neriskuji, potřebuji zastavit otáčení zeměkoule – režim tři přerušení, protože toto nepočká.
V následující části se podíváme jak s tlačítky pracovat. Je to jednoduché – na displej nakreslíme něco, co chceme stisknout a pak když držíme stisknuté toto tlačítko, ověříme koordináty stisku a pokud souhlasí s nakresleným tlačítkem, provedeme akci.
Tlačítko malujeme
Sketch je jednoduchý, pouze kontrolujeme zda jsme stiskli a pokud ano, nakreslíme tečku. Tlačítka použijeme pro vymazání displeje a změnu barvy.
//------------------------------------------------------------------
// 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
byte TFT_rotation = 2; // nastaveni otoceni displeje
byte TOUCH_rotation; // nastaveni orientace dotykove plochy
int colorDraw = TFT_BLACK; // nastaveni vychozi barvy kresleni
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
strHlavni(); // zobrazeni uvodni stranky
}
//------------------------------------------------------------------
void loop() {
//------------------------------------------------------------------
// cteni dotykoveho displeje
if (touch.dataAvailable()) { // kontrola prijatych dat z dotykoveho panelu
dotyk(); // spust program dotyk
}
}
//------------------------------------------------------------------
void dotyk() {
//------------------------------------------------------------------
// cteni hodnot z dotykoveho displeje
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 tlačítek
if (y > 40) {// nakresli tecku
//tft.drawPixel(x, y, colorDraw); // kresli tecku - vidime tenkou caru
tft.fillCircle(x, y, 3, colorDraw); // nakresli kruh - vidime tlustou caru
}
else {
if ((x >= 0 && x <= 39) && (y >= 0 && y <= 40)) { // vyber cerne barvy
colorDraw = TFT_BLACK;
}
else if ((x >= 40 && x <= 79) && (y >= 0 && y <= 40)) { // vyber cervene barvy
colorDraw = TFT_RED;
}
else if ((x >= 80 && x <= 119) && (y >= 0 && y <= 40)) { // vyber modre barvy
colorDraw = TFT_BLUE;
}
else if ((x >= 120 && x <= 159) && (y >= 0 && y <= 40)) { // vyber zelene barvy
colorDraw = TFT_GREEN;
}
else if ((x >= 160 && x <= 239) && (y >= 0 && y <= 40)) { // vymazani displeje
strHlavni();
}
}
}
}
//------------------------------------------------------------------
void strHlavni() {
tft.fillScreen(TFT_WHITE); // nastaveni pozadi
//------------------------------------------------------------------
tft.fillRect(0, 0, 40, 40, TFT_BLACK); // zobrazeni tlacitka
tft.fillRect(40, 0, 40, 40, TFT_RED); // zobrazeni tlacitka
tft.fillRect(80, 0, 40, 40, TFT_BLUE); // zobrazeni tlacitka
tft.fillRect(120, 0, 40, 40, TFT_GREEN); // zobrazeni tlacitka
tft.fillRect(160, 0, 80, 40, TFT_LIGHTGREY); // zobrazeni tlacitka
tft.drawCentreString("RESET", 200, 12, 2);
//------------------------------------------------------------------
}
Tady se na chvíli zastavím. Část pro kreslení je hned v úvodu kontroly co jsme stiskli. Tady narážíme na rychlost Arduina, protože když to dáme nakonec kontroly a budete kreslit rychle, čáry budou přerušované. Prostě chvíli trvá, než Arduino projde všechny podmínky. Na toto je potřeba dávat pozor při tvorbě programu. Že to říkám už poněkolikáté, ANO.
Tlačítko čekáme
K tomuto využijeme režim dva a budeme měnit barvy pozadí, podle stisknutého tlačítka. Do programu jsme si přidali značku vypni dotyk, kterou v case kontrolujeme a pokud uplyne požadovaná doba prodlevy, povolíme reakci na dotyk.
//------------------------------------------------------------------
// 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
//------------------------------------------------------------------
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
strHlavni(TFT_WHITE); // zobrazeni uvodni stranky
}
//------------------------------------------------------------------
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 >= 10 && x <= 110) && (y >= 10 && y <= 60)) { // cervene pozadi
strHlavni(TFT_RED);
}
else if ((x >= 130 && x <= 230) && (y >= 10 && y <= 60)) { // zelene pozadi
strHlavni(TFT_GREEN);
}
else if ((x >= 10 && x <= 110) && (y >= 260 && y <= 310)) { // modre pozadi
strHlavni(TFT_BLUE);
}
else if ((x >= 130 && x <= 230) && (y >= 260 && y <= 310)) { // zlute pozadi
strHlavni(TFT_YELLOW);
}
else if ((x >= 70 && x <= 170) && (y >= 135 && y <= 185)) { // bile pozadi
strHlavni(TFT_WHITE);
}
}
}
}
//------------------------------------------------------------------
void strHlavni(int color) {
tft.fillScreen(color); // nastaveni pozadi
//------------------------------------------------------------------
// tlacitko cervena, vlevo nahore
tft.fillRoundRect(9, 9, 102, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(10, 10, 100, 50, 10, TFT_RED); // zobrazeni tlacitka
tft.drawCentreString("cervena", 60, 25, 2); // zobrazeni textu
//------------------------------------------------------------------
// tlacitko zelena, vpravo nahore
tft.fillRoundRect(129, 9, 102, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(130, 10, 100, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("zelena", 180, 25, 2); // zobrazeni textu
//------------------------------------------------------------------
// tlacitko modra, vlevo dole
tft.fillRoundRect(9, 259, 102, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(10, 260, 100, 50, 10, TFT_BLUE); // zobrazeni tlacitka
tft.drawCentreString("modra", 60, 275, 2); // zobrazeni textu
//------------------------------------------------------------------
// tlacitko zluta, vpravo dole
tft.fillRoundRect(129, 259, 102, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(130, 260, 100, 50, 10, TFT_YELLOW); // zobrazeni tlacitka
tft.drawCentreString("zluta", 180, 275, 2); // zobrazeni textu
//------------------------------------------------------------------
// tlacitko bila, na stredu
tft.fillRoundRect(69, 134, 102, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(70, 135, 100, 50, 10, TFT_WHITE); // zobrazeni tlacitka
tft.drawCentreString("bila", 120, 150, 2); // zobrazeni textu
}
Vidíte, že po stisku tlačítka, když máme provést zobrazení na displeji, nejdříve nakreslíme nové pozadí, čímž smažeme vše z displeje a pak tam tlačítka nakreslíme znovu.
Pokud neměníme pozadí, ale jenom část displeje, nemusíme překreslovat celý displej, ale pouze tu část, kterou měníme. Např. barvu tlačítka viz následující sketch, kde současně rozsvítíme i tu diodu a rovnou si otevřeme vrátka na kreslení ikon. Sluníčko s paprsky je krásné, ne?
//------------------------------------------------------------------
// 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 DIODA 3 // dioda
#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
float sx, sy; // promenne pro kresleni paprsku
int x0, x1, y0, y1; // promenne pro kresleni paprsku
//------------------------------------------------------------------
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 pozadi ktere se nebude menit
tft.fillRoundRect(59, 134, 122, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillCircle(120, 60, 22, TFT_BLACK); // zobrazeni obrysu stavu diody
//------------------------------------------------------------------
// nakreslime zbytek uvodni stranky
tft.fillCircle(120, 60, 20, TFT_LIGHTGREY); // zobrazeni stavu diody
tft.fillRoundRect(60, 135, 120, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("ON", 120, 150, 4); // zobrazeni textu
paprsky(TFT_WHITE); // nakresli paprsky kolem ikony stavu
//------------------------------------------------------------------
pinMode(DIODA, OUTPUT); // vystup vystup pro diodu
}
//------------------------------------------------------------------
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 >= 70 && x <= 170) && (y >= 135 && y <= 185)) { // bile pozadi
if (digitalRead(DIODA)) { // kdyz je dioda rozsvicena
digitalWrite(DIODA, LOW); // vypni diodu
tft.fillCircle(120, 60, 20, TFT_LIGHTGREY); // zobrazeni stavu diody
paprsky(TFT_WHITE); // nakresli paprsky kolem ikony stavu
tft.fillRoundRect(60, 135, 120, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("ON", 120, 150, 4); // zobrazeni textu
}
else { // jinak kdyz je dioda zhasnuta
digitalWrite(DIODA, HIGH); // zapni diodu
tft.fillCircle(120, 60, 20, TFT_YELLOW); // zobrazeni stavu diody
paprsky(TFT_YELLOW); // nakresli paprsky kolem ikony stavu
tft.fillRoundRect(60, 135, 120, 50, 10, TFT_RED); // zobrazeni tlacitka
tft.drawCentreString("OFF", 120, 150, 4); // zobrazeni textu
}
}
}
}
}
//------------------------------------------------------------------
// kresleni paprsku kolem ikony stavu
void paprsky(int color) {
for (int i = 0; i < 360; i += 30) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 35 + 120;
y0 = sy * 35 + 60;
x1 = sx * 25 + 120;
y1 = sy * 25 + 60;
tft.drawLine(x0 - 2, y0 - 2, x1 - 2, y1 - 2, color);
tft.drawLine(x0 - 1, y0 - 1, x1 - 1, y1 - 1, color);
tft.drawLine(x0, y0, x1, y1, color);
tft.drawLine(x0 + 1, y0 + 1, x1 + 1, y1 + 1, color);
tft.drawLine(x0 + 2, y0 + 2, x1 + 2, y1 + 2, color);
}
}
Na "čekáme" se podíváme ještě jednou a pak to porovnáme s přerušením. Vytvoříme si jednoduchou obrazovku a držením tlačítka budeme měnit hodnoty. Současně můžeme nastavit i prodlevu tlačítka, která se hned projeví při dalším stisku. Zkuste nastavit prodlevu rovnající se 0 milisekund. Jde to, chce to trochu trpělivosti. Když se to povede, zjistíte, že jste přestali řídit počet stisků počítadla a po stisku se objevuje náhodná hodnota. Na druhou stranu mít prodlevu dvě sekundy je opravdu otrava, zkuste si to. Hledal jsem ideální hodnotu prodlevy. Ta neexistuje, mě nejlépe vyhovuje prodleva 200 milisekund. V tomto programu je zapotřebí udělat několik změn, které souvisí s převodem textu. drawString umí umístit text na požadované místo s požadovaným zarovnáním, ale pouze text. Čísla pro zobrazení je tedy nejprve nutné převést na text. Třeba další návod, i když trochu nechtěný.
//------------------------------------------------------------------
// 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
unsigned int 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
unsigned int count = 0; // pocitadlo
char charText[5]; // vytvoreni promenne pro zobrazeni textu
//------------------------------------------------------------------
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 uvodni stranku
tft.drawCentreString("POCITADLO", 120, 30, 4); // zobrazeni textu
// leve tlacitko
tft.fillRoundRect(24, 79, 52, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(25, 80, 50, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("UP", 50, 95, 2); // zobrazeni textu
// prave tlacitko
tft.fillRoundRect(164, 79, 52, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(165, 80, 50, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("DOWN", 190, 95, 2); // zobrazeni textu
// nadpis
tft.drawCentreString("PRODLEVA", 120, 160, 4); // zobrazeni textu
// leve tlacitko
tft.fillRoundRect(24, 209, 52, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(25, 210, 50, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("UP", 50, 225, 2); // zobrazeni textu
// prave tlacitko
tft.fillRoundRect(164, 209, 52, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(165, 210, 50, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("DOWN", 190, 225, 2); // zobrazeni textu
// uprav nastaveni zobrazeni textu
tft.setTextColor(TFT_BLACK, TFT_WHITE); // nastaveni barvy pisma
// zobrazeni promennych
itoa(count, charText, 10); // preved cislo na text
tft.drawCentreString(charText, 120, 95, 4); // zobrazeni textu
dtostrf((float)prodlevaDotyk / 1000, 4, 1, charText); // preved float na text
tft.drawCentreString(charText, 120, 225, 4); // zobrazeni textu
}
//------------------------------------------------------------------
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 ...
// tlacitka pocitadla
if ((x >= 25 && x <= 75) && (y >= 80 && y <= 130)) { // pocitadlo nahoru
count++; // pocitadlo +1
count = count % 10; // omez promennou v rozsahu 0-9
itoa(count, charText, 10); // preved cislo na text
tft.drawCentreString(charText, 120, 95, 4); // zobrazeni textu
}
else if ((x >= 165 && x <= 215) && (y >= 80 && y <= 130)) { // pocitadlo dolu
count--; // pocitadlo -1
count = count % 10; // omez promennou v rozsahu 0-9
itoa(count, charText, 10); // preved cislo na text
tft.drawCentreString(charText, 120, 95, 4); // zobrazeni textu
}
// tlacitka prodlevy
else if ((x >= 25 && x <= 75) && (y >= 210 && y <= 260)) { // prodleva nahoru
prodlevaDotyk += 100; // zvyseni prodlevy o 100 millisekund
prodlevaDotyk = prodlevaDotyk % 2100; // omez prodlevu v rozsahu 0-2000 millisekund
dtostrf((float)prodlevaDotyk / 1000, 4, 1, charText); // preved float na text
tft.drawCentreString(charText, 120, 225, 4); // zobrazeni textu
}
else if ((x >= 165 && x <= 215) && (y >= 210 && y <= 260)) { // prodleva dolu
prodlevaDotyk -= 100; // snizeni prodlevy o 100 millisekund
prodlevaDotyk = prodlevaDotyk % 2100; // omez prodlevu v rozsahu 0-2000 millisekund
dtostrf((float)prodlevaDotyk / 1000, 4, 1, charText); // preved float na text
tft.drawCentreString(charText, 120, 225, 4); // zobrazeni textu
}
}
}
}
Tlačítko přerušení
To je poslední dostupný režim. Využijeme předcházející program, odstraníme z něj čekání, tlačítka změny prodlevy a přidáme reakci na přerušení při stisku tlačítka. Hlavní rozdíl v používání je, že pokud chceme znovu stisknout tlačítko, musíme ho nejdříve pustit a stisknout znovu. Čísla se nám nebudou počítat automaticky. Přerušení si nejprve otestujte, jak jsem psal výše – některé knihovny vypínají přerušení a nejde znovu pustit. To kdyby Vám to v jiném hotovém projektu nefungovalo.
POZOR – displej se nechová úplně korektně a proto je zapotřebí použít strukturu programu jak ji vidíte. Výhoda je že vám budou fungovat všechny funkce, které voláním ve funkci přerušení nefungují.
//------------------------------------------------------------------
// 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
byte TFT_rotation = 2; // nastaveni otoceni displeje
byte TOUCH_rotation; // nastaveni orientace dotykove plochy
int x; // radek x displej
int y; // radek y displej
unsigned int count = 0; // pocitadlo
char charText[5]; // vytvoreni promenne pro zobrazeni textu
boolean chekInterrupts = true; // kontrola spusteni preruseni
//------------------------------------------------------------------
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 uvodni stranku
tft.drawCentreString("POCITADLO", 120, 30, 4); // zobrazeni textu
// leve tlacitko
tft.fillRoundRect(24, 79, 52, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(25, 80, 50, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("UP", 50, 95, 2); // zobrazeni textu
// prave tlacitko
tft.fillRoundRect(164, 79, 52, 52, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(165, 80, 50, 50, 10, TFT_GREEN); // zobrazeni tlacitka
tft.drawCentreString("DOWN", 190, 95, 2); // zobrazeni textu
// uprav nastaveni zobrazeni textu
tft.setTextColor(TFT_BLACK, TFT_WHITE); // nastaveni barvy pisma
// zobrazeni promennych
itoa(count, charText, 10); // preved cislo na text
tft.drawCentreString(charText, 120, 95, 4); // zobrazeni textu
}
//------------------------------------------------------------------
void loop() {
//------------------------------------------------------------------
// kontrola zapnuti preruseni
if (chekInterrupts) { // kdyz je povolena kontrola zapnuti preruseni
pinMode(TOUCH_IRQ, INPUT); // at nemusime upravovat knihovnu
if (digitalRead(TOUCH_IRQ)) { // kdyz neni dotyk stisknuty
chekInterrupts = false; // zakaz kontrolu zapnuti preruseni
attachInterrupt(digitalPinToInterrupt(TOUCH_IRQ), dotyk, LOW); // zapni preruseni
}
}
}
//------------------------------------------------------------------
void dotyk() {
detachInterrupt(digitalPinToInterrupt(TOUCH_IRQ)); // vypni preruseni
chekInterrupts = true; // povol kontrolu zapnuti preruseni
//------------------------------------------------------------------
// cteni hodnot z dotykoveho displeje
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 ...
// tlacitka pocitadla
if ((x >= 25 && x <= 75) && (y >= 80 && y <= 130)) { // pocitadlo nahoru
count++; // pocitadlo +1
count = count % 10; // omez promennou v rozsahu 0-9
itoa(count, charText, 10); // preved cislo na text
tft.drawCentreString(charText, 120, 95, 4); // zobrazeni textu
}
else if ((x >= 165 && x <= 215) && (y >= 80 && y <= 130)) { // pocitadlo dolu
count--; // pocitadlo -1
count = count % 10; // omez promennou v rozsahu 0-9
itoa(count, charText, 10); // preved cislo na text
tft.drawCentreString(charText, 120, 95, 4); // zobrazeni textu
}
}
}
Závěr
Každý způsob se hodí pro jiný účel. Samozřejmě lze program napsat tak, aby se při zobrazení konkrétní stránky aktivoval příslušný mód. Osobně s úspěchem používám kombinaci varianty 1, 2 a program optimalizuji tak, aby hlavní smyčka byla opravdu rychlá. To jste si jistě všimli, že loop mívám opravdu krátký.
Příště se ještě vrátíme k tlačítkům, jenom trochu jinak.
JB