Many time we need a real time device to monitor and operate remotely. Mobile or laptop may not be suitable for that purpose because we don’t need much interactions and the device need to work 24*7. We can create such a device by connecting a touch screen with nodemcu. So lets see how can we connect the two and code it for interaction.
Things we need :
- TFT LCD Display Touch Panel SPI (ILI9341)
- Nodemcu
- 20 jumper wires
- Breadboard
- Stylus
Connections
Below is the connection between Touch screen and Nodemcu :
- VCC to 3.3V
- GND to GND
- CS to D8
- RESET to RST
- DC to D4
- SDI (MOSI) to D7
- SCK to D5
- LED to 3.3V
- SDD (MISO) to D6
- T_CLK to D5
- T_CS to D2
- T_DIN to D7
- T_DO to D6
- T_IRQ to D1
(Note for the pins that have same connections we will have to use breadboard)
Next, we need to install libraries. Adafruit_GFX and SPI library can be installed from library Manager. Other library that we need you can download here.
Next, we need to find out the calibration parameter of the touch screen. Calibration is matching the graphics on the display to the output from the touch-screen controller. In other words, converting the display coordinates to touch coordinates. Use the code below to find the calibration parameter :
#include <Arduino.h> #include <SPI.h> #include <Adafruit_ILI9341esp.h> #include <Adafruit_GFX.h> #include <XPT2046.h> // For the Esp connection of touch #define TFT_DC 2 #define TFT_CS 15 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); XPT2046 touch(/*cs=*/ 4, /*irq=*/ 5); static void calibratePoint(uint16_t x, uint16_t y, uint16_t &vi, uint16_t &vj) { // Draw cross tft.drawFastHLine(x - 8, y, 16,0xff); tft.drawFastVLine(x, y - 8, 16,0xff); while (!touch.isTouching()) { delay(10); } touch.getRaw(vi, vj); // Erase by overwriting with black tft.drawFastHLine(x - 8, y, 16, 0); tft.drawFastVLine(x, y - 8, 16, 0); } void calibrate() { uint16_t x1, y1, x2, y2; uint16_t vi1, vj1, vi2, vj2; touch.getCalibrationPoints(x1, y1, x2, y2); calibratePoint(x1, y1, vi1, vj1); delay(1000); calibratePoint(x2, y2, vi2, vj2); touch.setCalibration(vi1, vj1, vi2, vj2); tft.setTextColor(ILI9341_CYAN); tft.setTextSize(2); tft.println("Calibration Params"); tft.println(""); tft.setTextSize(3); tft.println(vi1); tft.println(vj1); tft.println(vi2); tft.println(vj2); } void setup() { delay(1000); SPI.setFrequency(ESP_SPI_FREQ); tft.begin(); touch.begin(tft.width(), tft.height()); // Must be done before setting rotation tft.fillScreen(ILI9341_BLACK); calibrate(); // No rotation!! } void loop() { // Do nothing delay(1000);
After uploading the code touch the cross sign with stylus. Repeat it again with another cross sign you see after that. Now take note down of calibration parameter.
Finally we will upload the code below that creates a simple interface of phone calling UI :
#include <Arduino.h> #include <SPI.h> #include "Adafruit_ILI9341esp.h" #include "Adafruit_GFX.h" #include "XPT2046.h" #define TFT_DC 2 #define TFT_CS 15 /******************* UI details */ #define BUTTON_X 40 #define BUTTON_Y 100 #define BUTTON_W 60 #define BUTTON_H 30 #define BUTTON_SPACING_X 20 #define BUTTON_SPACING_Y 20 #define BUTTON_TEXTSIZE 2 // text box where numbers go #define TEXT_X 10 #define TEXT_Y 10 #define TEXT_W 220 #define TEXT_H 50 #define TEXT_TSIZE 3 #define TEXT_TCOLOR ILI9341_MAGENTA // the data (phone #) we store in the textfield #define TEXT_LEN 12 char textfield[TEXT_LEN+1] = ""; uint8_t textfield_i=0; Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); XPT2046 touch(/*cs=*/ 4, /*irq=*/ 5); /* create 15 buttons, in classic candybar phone style */ char buttonlabels[15][5] = {"Send", "Clr", "End", "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#" }; uint16_t buttoncolors[15] = {ILI9341_DARKGREEN, ILI9341_DARKGREY, ILI9341_RED, ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, ILI9341_BLUE, ILI9341_ORANGE, ILI9341_BLUE, ILI9341_ORANGE}; Adafruit_GFX_Button buttons[15]; void setup() { // put your setup code here, to run once: delay(1000); Serial.begin(115200); SPI.setFrequency(ESP_SPI_FREQ); tft.begin(); touch.begin(tft.width(), tft.height()); // Must be done before setting rotation Serial.print("tftx ="); Serial.print(tft.width()); Serial.print(" tfty ="); Serial.println(tft.height()); tft.fillScreen(ILI9341_BLACK); // Replace these for your screen module touch.setCalibration(1832, 262, 264, 1782); // create buttons for (uint8_t row=0; row<5; row++) { for (uint8_t col=0; col<3; col++) { buttons[col + row*3].initButton(&tft, BUTTON_X+col*(BUTTON_W+BUTTON_SPACING_X), BUTTON_Y+row*(BUTTON_H+BUTTON_SPACING_Y), // x, y, w, h, outline, fill, text BUTTON_W, BUTTON_H, ILI9341_WHITE, buttoncolors[col+row*3], ILI9341_WHITE, buttonlabels[col + row*3], BUTTON_TEXTSIZE); buttons[col + row*3].drawButton(); } } // create 'text field' tft.drawRect(TEXT_X, TEXT_Y, TEXT_W, TEXT_H, ILI9341_WHITE); } void loop() { // put your main code here, to run repeatedly: uint16_t x, y; if (touch.isTouching()) touch.getPosition(x, y); // go thru all the buttons, checking if they were pressed for (uint8_t b=0; b<15; b++) { if (buttons[b].contains(x, y)) { //Serial.print("Pressing: "); Serial.println(b); buttons[b].press(true); // tell the button it is pressed } else { buttons[b].press(false); // tell the button it is NOT pressed } } // now we can ask the buttons if their state has changed for (uint8_t b=0; b<15; b++) { if (buttons[b].justReleased()) { // Serial.print("Released: "); Serial.println(b); buttons[b].drawButton(); // draw normal } if (buttons[b].justPressed()) { buttons[b].drawButton(true); // draw invert! // if a numberpad button, append the relevant # to the textfield if (b >= 3) { if (textfield_i < TEXT_LEN) { textfield[textfield_i] = buttonlabels[b][0]; textfield_i++; textfield[textfield_i] = 0; // zero terminate //fona.playDTMF(buttonlabels[b][0]); } } // clr button! delete char if (b == 1) { textfield[textfield_i] = 0; if (textfield > 0) { textfield_i--; textfield[textfield_i] = ' '; } } // update the current text field Serial.println(textfield); tft.setCursor(TEXT_X + 2, TEXT_Y+10); tft.setTextColor(TEXT_TCOLOR, ILI9341_BLACK); tft.setTextSize(TEXT_TSIZE); tft.print(textfield); // its always OK to just hang up if (b == 2) { //status(F("Hanging up")); //fona.hangUp(); } // we dont really check that the text field makes sense // just try to call if (b == 0) { //status(F("Calling")); //Serial.print("Calling "); Serial.print(textfield); //fona.callPhone(textfield); } delay(100); // UI debouncing } } }