Last Updated: 12/09/2021
Touch Screens
Components >> Touch Screens
LCD Touch Screens
Oscilloscopev1 contains various examples of using buttons, processing touch and drawing a graph, using downloadable fonts and coding a multiple screen project.
LCD touch screens are great devices for projects, not only for the ability to create a colour output but because you can build great control panels with them having numerous buttons and screens while not adding huge amounts of wiring.
Touch screen come in a number of sizes, the cheapest and probably the easiest to use is the basic Arduino shield type, a 2.4" screen that fits straight onto an Arduino UNO or Mega 2560. There are bigger screens that also come with their own shield system to make life easier
Next come screens from
2.4" up to 7.0+" that do not have a shield, each one getting more expensive and often using more pins, These are easier to fit into control panel type sistuations, but mean you have to think about the wiring diagram. That said they are my preferred type.
There are also screens that use a Serial Interface such as the Nextion range. These have their own software for creating the screen interface and are user friendly but at a price to match.
NOTE: Screen size is measured diagonally across the screen. Also be aware that a bigger screen does not mean a better screen resolution so check the resolution (number of pixels such as 400x240 or 480 x 320) when buying your screen.
Most of the cheaper screens come with an inductive touch screen unlike most phones or tablets that use a capacitative screen. I'm not going to venture into the technical differences, but the basic inductive system works by having a grid of wires across the screen that when pressed touch each other to work out the touch position. This only allows one position to be used at a time so cannot be used to track multiple touch gestures like a phone which is why they need to use a capacitative screen.
In the photo below the top screen is the basic 2.4" shield type while below is a 3.5" breakout board.
5.0" screen as part of a DCC railway controller
7.0" Nextion screen used in an industrial Powder filling machine as a control panel
Circuit Diagram
For these sketches if you have a shield type just attatch the shield to your Arduino UNO or Arduino Mega2560.
If you are using the breakout type board as in first photo the pin out is in the sketch header as well as below
NOTE: NON shield boards tend to be 3.3v power and logic pins. You either need to add some 5v - 3.3v logic level shifters to your circuit or use a 3.3v Arduino such as the Arduino Due that will be used in the example below.
Screen - Arduino
GND - GND
3.3v - 3.3v
CS - A3
X RS - A2
Y WR - A1
RD - A0
RST - A4
LED - GND
DB0 - 8
DB1 - 9
DB2 - 2
DB3 - 3
DB4 - 4
DB5 - 5
DB6 - 6
DB7 - 7
Using 5v on a 3.3v screen will damage the screen
Once I have finished testing I build a connector from an Arduino prototype shield to the screen as shown below.
Tutorial
This code uses various features and functions learnt in the C++ tutorial section, see C++ Lessons for the individual lessons.
I have used an Arduino Due and 3.5" breakuoput board, however the code will work with a few adjustments for your screen resolution if you are using a shield type board with an Arduino UNO or Mega2560.
These examples will use the following libraries that should all be available from the Arduino IDE library manager.
Adafruit GFX library
Adafruit TouchScreen
MCUFriend_kbv
The 5 examples work through setting up your screen through to controlling a simple button and give a foundation for the Oscilloscope project.
Example 1: screensetUptV1.ino
Click to Download code:screensetUptV1.ino
Setting up the screen and getting the correct resolution and orientation
/* 08/09/2021
*
* screensetUpV1 this sketch sets up the display
*
* Touch screen set up
* 3.5" Open Smart 400x240
* ST7793
*
* This script just deals with getting the display set up
*
* Pins
* I am using an Arduino DUE
*
* WARNING The break out boards are 3.3v power and logic on digital pins
* Connecting directly to a 5v Arduino Mega/Nano/UNO will probably kill the screen
* If the board is on a shield it should be 5v compatible but check
*
* I am using a 3.3v Arduino Due
*
* Screen - Arduino
* GND - GND
* 3.3v - 3.3v
* CS - A3
* X RS - A2
* Y WR - A1
* RD - A0
* RST - A4
* LED - GND
* DB0 - 8
* DB1 - 9
* DB2 - 2
* DB3 - 3
* DB4 - 4
* DB5 - 5
* DB6 - 6
* DB7 - 7
*
*
*
*
*/
//Libraries required
#include
//make sure your screen is not commeneted out in MCUFriend_kpv.cpp
//My screen is a ST7793
#include
//Create Touch screen object
MCUFRIEND_kbv tft;
//sets the rotation of the screen
//change the value depending how you want to use the screen, useful if you fit it in an enclosure the wrong way round.
//0 would be portrait...values 0-3 on 90 degree increments
#define TOUCH_ORIENTATION 1 //1 is landscape 400 wide x 240 high on my screen
//define some colours so don't need to remember hex codes
//see https://ee-programming-notepad.blogspot.com/2016/10/16-bit-color-generator-picker.html
//to create custom colours
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
void setup() {
Serial.begin(9600);
Serial.println("screensetUpV1...");
Serial.println(" ");
//Get the screens type
uint16_t ID = tft.readID();
Serial.print("ID = 0x");
Serial.println(ID, HEX);
tft.begin(ID);
tft.setRotation(TOUCH_ORIENTATION);
//make the whole screen black as a back ground
tft.fillScreen(BLACK);
//draw a rectangle starting in the top left corner (0,0) of the screen
//opposite corner is (10,10), 10 wide and 10 pixels down
tft.drawRect(0,0,10,10, WHITE);// draw small box top left
/*
At this point the screen should be Black with a small 10 x 10 pixel rectangle in the top left corner.
If it is not in the top left as you want to use the screen change the
TOUCH_ORIENTATION value
*/
//Uncomment this line and draw a box around the edge of the screen
//my screen is 400x240 so this will be differentd epending on your screen
//ZERO is the first pixel, not 1 so max width for 400 screen is 399
//tft.drawRect(0,0,399,239, RED);// draw red box around screen box
}
void loop() {
// put your main code here, to run repeatedly:
}
Example 2: screensetUptV3.ino
Click to Download code:screensetUptV3.ino
Testing the touch system
/* 08/09/2021
*
* screensetUpV3
* Calibrates touch to our screen dimensions and orientation
*
* Touch screen set up
* 3.5" Open Smart 400x240
* ST7793
*
*
* Pins
* I am using an Arduino DUE
*
* WARNING The break out boards are 3.3v power and logic on digital pins
* Connecting directly to a 5v Arduino Mega/Nano/UNO will probably kill the screen
* If the board is on a shield it should be 5v compatible but check
*
* I am using a 3.3v Arduino Due
*
* Screen - Arduino
* GND - GND
* 3.3v - 3.3v
* CS - A3
* X RS - A2
* Y WR - A1
* RD - A0
* RST - A4
* LED - GND
* DB0 - 8
* DB1 - 9
* DB2 - 2
* DB3 - 3
* DB4 - 4
* DB5 - 5
* DB6 - 6
* DB7 - 7
*
*
*/
//Libraries required
#include
//make sure your screen is not commeneted out in MCUFriend_kpv.cpp
//My screen is a ST7793
#include
//Create Touch screen object
MCUFRIEND_kbv tft;
//sets the rotation of the screen
//change the value depending how you want to use the screen, useful if you fit it in an enclosure the wrong way round.
//0 would be portrait...values 0-3 on 90 degree increments
#define TOUCH_ORIENTATION 1 //1 is landscape 400 wide x 240 high on my screen
//define some colours so don't need to remember hex codes
//see https://ee-programming-notepad.blogspot.com/2016/10/16-bit-color-generator-picker.html
//to create custom colours
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
//Now we know the display is working start on touch
//values below come from running Touch_shield_new.ino
//from the MCUFriend_kbv library examples
//input stuff starts here
int XP = 6, YP = 55, XM = 56, YM = 7; //from calibration test
//Adafruit Touch screen library
#include //
TouchScreen ts(XP, YP, XM, YM, 300); //re-initialised after diagnose
TSPoint tp;//create a touch point object in the library
void setup() {
Serial.begin(9600);
Serial.println("screensetUpV3...");
Serial.println(" ");
//Get the screens type
uint16_t ID = tft.readID();
Serial.print("ID = 0x");
Serial.println(ID, HEX);
tft.begin(ID);//start the screen
tft.setRotation(TOUCH_ORIENTATION);
//make the whole screen black as a back ground
tft.fillScreen(BLACK);
//draw a rectangle starting in the top left corner (0,0) of the screen
//opposite corner is (10,10), 10 wide and 10 pixels down
tft.drawRect(0,0,10,10, WHITE);// button box
/*
At this point the screen should be Black with a small 10 x 10 pixel rectangle in the top left corner.
If it is not in the top left as you want to use the screen change the
TOUCH_ORIENTATION value
*/
//Uncomment this line and draw a box around the edge of the screen
//my screen is 400x240
//ZERO is the first pixel, not 1 so max width for 400 screen is 399
tft.drawRect(0,0,399,239, YELLOW);// button box
}
void loop() {
//see if there is a touch in progress
tp = ts.getPoint();
//reset pins for next time we call the line above
pinMode(YP, OUTPUT); //restore shared pins
pinMode(XM, OUTPUT);
digitalWrite(YP, HIGH); //because TFT control pins
digitalWrite(XM, HIGH);
//This will print out the touch screen pointer location
//tp.x screen x axis
//tp.y screen y axis
//tp.z screen touch pressure
//if the values are changing while you move your finger across the screen the touch system is working
Serial.println("tp.x=" + String(tp.x) + ", tp.y=" + String(tp.y) + ", tp.z =" + String(tp.z));
//The values however do not match up with the pixel dimensions of the screen we are using
//now to change the values to something usable
//moving pointer to far left on my screen (box) gives Y value of 934
//moving pointer to far right on my screen gives Y value of 130
//934 - 134 = 800 points left to right screen is 400 pixels
//moving pointer to top on my screen (box) gives X value of 162
//moving pointer to top on my screen gives X value of 840
//840 - 162 = 678 points top to bottom on a 240 pixel screen
//Done this way to match Adafruit GFX library coordinates system
int xtouch;//true screen x position ZERO far left
int ytouch;//true screen y position ZERO top of screen
xtouch = (800-(tp.y - 130))/2; //800 minus value is because values are reversed, subtract the 130 to start at zero, divide by 2 because 800 touch points on a 400 pixel wide screen
Serial.print("xtouch : ");
Serial.println(xtouch);
//equasion below would normally be (tp.x - 162))/2.8 but by multiplying by 10 we get rid of decimal places
ytouch = (10*(tp.x - 162))/28; //subtract the 162 to start at zero, divide by 2.8 because 678 touch points on a 240 pixel high screen
Serial.print("ytouch : ");
Serial.println(ytouch);
//now we have x and Y coordinates that match the screen resolution
//test by drawing a line to the pointer from top left
tft.drawLine(0, 0, xtouch, ytouch, BLUE);//draws a line to see how accurate the touch point is :-)
delay(100);
}
Example 3: screensetUpV3.ino
Click to Download code:screensetUpV3.ino
Getting the touch x/y coordinates to match the LCD screen
/* 08/09/2021
*
* screensetUpV3
* Calibrates touch to our screen dimensions and orientation
*
* Touch screen set up
* 3.5" Open Smart 400x240
* ST7793
*
*
* Pins
* I am using an Arduino DUE
*
* WARNING The break out boards are 3.3v power and logic on digital pins
* Connecting directly to a 5v Arduino Mega/Nano/UNO will probably kill the screen
* If the board is on a shield it should be 5v compatible but check
*
* I am using a 3.3v Arduino Due
*
* Screen - Arduino
* GND - GND
* 3.3v - 3.3v
* CS - A3
* X RS - A2
* Y WR - A1
* RD - A0
* RST - A4
* LED - GND
* DB0 - 8
* DB1 - 9
* DB2 - 2
* DB3 - 3
* DB4 - 4
* DB5 - 5
* DB6 - 6
* DB7 - 7
*
*
*/
//Libraries required
#include
//make sure your screen is not commeneted out in MCUFriend_kpv.cpp
//My screen is a ST7793
#include
//Create Touch screen object
MCUFRIEND_kbv tft;
//sets the rotation of the screen
//change the value depending how you want to use the screen, useful if you fit it in an enclosure the wrong way round.
//0 would be portrait...values 0-3 on 90 degree increments
#define TOUCH_ORIENTATION 1 //1 is landscape 400 wide x 240 high on my screen
//define some colours so don't need to remember hex codes
//see https://ee-programming-notepad.blogspot.com/2016/10/16-bit-color-generator-picker.html
//to create custom colours
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
//Now we know the display is working start on touch
//values below come from running Touch_shield_new.ino
//from the MCUFriend_kbv library examples
//input stuff starts here
int XP = 6, YP = 55, XM = 56, YM = 7; //from calibration test
//Adafruit Touch screen library
#include //
TouchScreen ts(XP, YP, XM, YM, 300); //re-initialised after diagnose
TSPoint tp;//create a touch point object in the library
void setup() {
Serial.begin(9600);
Serial.println("screensetUpV3...");
Serial.println(" ");
//Get the screens type
uint16_t ID = tft.readID();
Serial.print("ID = 0x");
Serial.println(ID, HEX);
tft.begin(ID);//start the screen
tft.setRotation(TOUCH_ORIENTATION);
//make the whole screen black as a back ground
tft.fillScreen(BLACK);
//draw a rectangle starting in the top left corner (0,0) of the screen
//opposite corner is (10,10), 10 wide and 10 pixels down
tft.drawRect(0,0,10,10, WHITE);// button box
/*
At this point the screen should be Black with a small 10 x 10 pixel rectangle in the top left corner.
If it is not in the top left as you want to use the screen change the
TOUCH_ORIENTATION value
*/
//Uncomment this line and draw a box around the edge of the screen
//my screen is 400x240
//ZERO is the first pixel, not 1 so max width for 400 screen is 399
tft.drawRect(0,0,399,239, YELLOW);// button box
}
void loop() {
//see if there is a touch in progress
tp = ts.getPoint();
//reset pins for next time we call the line above
pinMode(YP, OUTPUT); //restore shared pins
pinMode(XM, OUTPUT);
digitalWrite(YP, HIGH); //because TFT control pins
digitalWrite(XM, HIGH);
//This will print out the touch screen pointer location
//tp.x screen x axis
//tp.y screen y axis
//tp.z screen touch pressure
//if the values are changing while you move your finger across the screen the touch system is working
Serial.println("tp.x=" + String(tp.x) + ", tp.y=" + String(tp.y) + ", tp.z =" + String(tp.z));
//The values however do not match up with the pixel dimensions of the screen we are using
//now to change the values to something usable
//moving pointer to far left on my screen (box) gives Y value of 934
//moving pointer to far right on my screen gives Y value of 130
//934 - 134 = 800 points left to right screen is 400 pixels
//moving pointer to top on my screen (box) gives X value of 162
//moving pointer to top on my screen gives X value of 840
//840 - 162 = 678 points top to bottom on a 240 pixel screen
//Done this way to match Adafruit GFX library coordinates system
int xtouch;//true screen x position ZERO far left
int ytouch;//true screen y position ZERO top of screen
xtouch = (800-(tp.y - 130))/2; //800 minus value is because values are reversed, subtract the 130 to start at zero, divide by 2 because 800 touch points on a 400 pixel wide screen
Serial.print("xtouch : ");
Serial.println(xtouch);
//equasion below would normally be (tp.x - 162))/2.8 but by multiplying by 10 we get rid of decimal places
ytouch = (10*(tp.x - 162))/28; //subtract the 162 to start at zero, divide by 2.8 because 678 touch points on a 240 pixel high screen
Serial.print("ytouch : ");
Serial.println(ytouch);
//now we have x and Y coordinates that match the screen resolution
//test by drawing a line to the pointer from top left
tft.drawLine(0, 0, xtouch, ytouch, BLUE);//draws a line to see how accurate the touch point is :-)
delay(100);
}
Example 4: screensetUptV4.ino
Click to Download code:screensetUptV4.ino
Moving all the code into a function
/* 08/09/2021
screensetUpV4
Creates a touch function
Allows for button debouncing
Removes not touch events
Touch screen set up
3.5" Open Smart 400x240
ST7793
Pins
I am using an Arduino DUE
WARNING The break out boards are 3.3v power and logic on digital pins
Connecting directly to a 5v Arduino Mega/Nano/UNO will probably kill the screen
If the board is on a shield it should be 5v compatible but check
I am using a 3.3v Arduino Due
Screen - Arduino
GND - GND
3.3v - 3.3v
CS - A3
X RS - A2
Y WR - A1
RD - A0
RST - A4
LED - GND
DB0 - 8
DB1 - 9
DB2 - 2
DB3 - 3
DB4 - 4
DB5 - 5
DB6 - 6
DB7 - 7
to draw other shapes and text see the libray detais at
https://learn.adafruit.com/adafruit-gfx-graphics-library/graphics-primitives
*/
//Libraries required
#include
//make sure your screen is not commeneted out in MCUFriend_kpv.cpp
//My screen is a ST7793
#include
//Create Touch screen object
MCUFRIEND_kbv tft;
//sets the rotation of the screen
//change the value depending how you want to use the screen, useful if you fit it in an enclosure the wrong way round.
//0 would be portrait...values 0-3 on 90 degree increments
#define TOUCH_ORIENTATION 1 //1 is landscape 400 wide x 240 high on my screen
//define some colours so don't need to remember hex codes
//see https://ee-programming-notepad.blogspot.com/2016/10/16-bit-color-generator-picker.html
//to create custom colours
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
//Now we know the display is working start on touch
//values below come from running Touch_shield_new.ino
//from the MCUFriend_kbv library examples
//input stuff starts here
int XP = 6, YP = 55, XM = 56, YM = 7; //from calibration test
//Adafruit Touch screen library
#include //
TouchScreen ts(XP, YP, XM, YM, 300); //re-initialised after diagnose
TSPoint tp;//create a touch point object in the library
//Global variables that will contain screen X and X touch points
int xtouch;//true screen x position ZERO far left
int ytouch;//true screen y position ZERO top of screen
unsigned long touchTime;//stores the time in millis of the last touch
//alter this value to change the debounce sensitivity
int debounceSensitivity = 220;// too low gives false positives as will still be touching same point, too high and will become unresponsive
int touchEvent;
void screenPress() {
processTouch();//call the processTouch function to see if there is anything to process
//if there has been a touch event do something
//this is where we would process screen buttons or movements
if (touchEvent > 0) {
Serial.print("xtouch : ");
Serial.println(xtouch);
Serial.print("ytouch : ");
Serial.println(ytouch);
//now we have x and Y coordinates that match the screen resolution
//test by drawing a line to the pointer from top left
tft.drawLine(0, 0, xtouch, ytouch, BLUE);//draws a line to see how accurate the touch point is :-)
}
}
void processTouch() {
touchEvent = 0;//reset touchEvent
if (millis() > touchTime) { //give them some time to move their finger off...saves processing loads of false touches
touchTime = millis() + debounceSensitivity; //reset the timer
//see if there is a touch in progress
tp = ts.getPoint();
//reset pins for next time we call the line above
pinMode(YP, OUTPUT); //restore shared pins
pinMode(XM, OUTPUT);
digitalWrite(YP, HIGH); //because TFT control pins
digitalWrite(XM, HIGH);
//This will print out the touch screen pointer location
//tp.x screen x axis
//tp.y screen y axis
//tp.z screen touch pressure
//if the values are changing while you move your finger across the screen the touch system is working
if (tp.z > 0) {
//Serial.println("tp.x=" + String(tp.x) + ", tp.y=" + String(tp.y) + ", tp.z =" + String(tp.z));
//The values however do not match up with the pixel dimensions of the screen we are using
//now to change the values to something usable
//moving pointer to far left on my screen (box) gives Y value of 934
//moving pointer to far right on my screen gives Y value of 130
//934 - 134 = 800 points left to right screen is 400 pixels
//moving pointer to top on my screen (box) gives X value of 162
//moving pointer to top on my screen gives X value of 840
//840 - 162 = 678 points top to bottom on a 240 pixel screen
//Done this way to match Adafruit GFX library coordinates system
xtouch = (800 - (tp.y - 130)) / 2; //800 minus value is because values are reversed, subtract the 130 to start at zero, divide by 2 because 800 touch points on a 400 pixel wide screen
//equasion below would normally be (tp.x - 162))/2.8 but by multiplying by 10 we get rid of decimal places
ytouch = (10 * (tp.x - 162)) / 28; //subtract the 162 to start at zero, divide by 2.8 because 678 touch points on a 240 pixel high screen
//if the touch is within the limits of our screen
if (xtouch > -1 && xtouch < 400 && ytouch > -1 && ytouch < 240) {
touchEvent = 1;
}
}
}
}
void setup() {
Serial.begin(9600);
Serial.println("screensetUpV4...");
Serial.println(" ");
//Get the screens type
uint16_t ID = tft.readID();
Serial.print("ID = 0x");
Serial.println(ID, HEX);
tft.begin(ID);//start the screen
tft.setRotation(TOUCH_ORIENTATION);
//make the whole screen black as a back ground
tft.fillScreen(BLACK);
//draw a rectangle starting in the top left corner (0,0) of the screen
//opposite corner is (10,10), 10 wide and 10 pixels down
tft.drawRect(0, 0, 10, 10, WHITE); // button box
/*
At this point the screen should be Black with a small 10 x 10 pixel rectangle in the top left corner.
If it is not in the top left as you want to use the screen change the
TOUCH_ORIENTATION value
*/
//Uncomment this line and draw a box around the edge of the screen
//my screen is 400x240
//ZERO is the first pixel, not 1 so max width for 400 screen is 399
tft.drawRect(0, 0, 399, 239, YELLOW); // button box
}
void loop() {
screenPress();
}
Example 5: screensetUptV5.ino
Click to Download code:screensetUptV5.ino
A simple button example of how to use the function
/* 08/09/2021
screensetUpV5
A very simple button example
Touch screen set up
3.5" Open Smart 400x240
ST7793
Pins
I am using an Arduino DUE
WARNING The break out boards are 3.3v power and logic on digital pins
Connecting directly to a 5v Arduino Mega/Nano/UNO will probably kill the screen
If the board is on a shield it should be 5v compatible but check
I am using a 3.3v Arduino Due
Screen - Arduino
GND - GND
3.3v - 3.3v
CS - A3
X RS - A2
Y WR - A1
RD - A0
RST - A4
LED - GND
DB0 - 8
DB1 - 9
DB2 - 2
DB3 - 3
DB4 - 4
DB5 - 5
DB6 - 6
DB7 - 7
*/
//Libraries required
#include
//make sure your screen is not commeneted out in MCUFriend_kpv.cpp
//My screen is a ST7793
#include
//Create Touch screen object
MCUFRIEND_kbv tft;
//sets the rotation of the screen
//change the value depending how you want to use the screen, useful if you fit it in an enclosure the wrong way round.
//0 would be portrait...values 0-3 on 90 degree increments
#define TOUCH_ORIENTATION 1 //1 is landscape 400 wide x 240 high on my screen
//define some colours so don't need to remember hex codes
//see https://ee-programming-notepad.blogspot.com/2016/10/16-bit-color-generator-picker.html
//to create custom colours
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
//Now we know the display is working start on touch
//values below come from running Touch_shield_new.ino
//from the MCUFriend_kbv library examples
//input stuff starts here
int XP = 6, YP = 55, XM = 56, YM = 7; //from calibration test
//Adafruit Touch screen library
#include //
TouchScreen ts(XP, YP, XM, YM, 300); //re-initialised after diagnose
TSPoint tp;//create a touch point object in the library
//Global variables that will contain screen X and X touch points
int xtouch;//true screen x position ZERO far left
int ytouch;//true screen y position ZERO top of screen
unsigned long touchTime;//stores the time in millis of the last touch
//alter this value to change the debounce sensitivity
int debounceSensitivity = 220;// too low gives false positives as will still be touching same point, too high and will become unresponsive
int touchEvent;//keeps track of touch event
int buttonOnState;//keeps track of the buttons state
unsigned long buttonTimer;
void screenPress() {
processTouch();//call the processTouch function to see if there is anything to process
//if there has been a touch event do something if the touch is within the button boundary
if (touchEvent > 0 && buttonOnState < 1 && xtouch >= 150 && xtouch <= 250 && ytouch >= 100 && ytouch <= 200) {
buttonOn();
buttonOnState = 1;
//set the timing for the button to go out...Using Delay() will cause problems with touch screens as the screen cannot be read during the delay period
buttonTimer = millis() + 500;//keep button lit for 0.5 seconds
}
//make sure no touch event reported, the button is already on and the timer has expired
if (touchEvent < 1 && buttonOnState > 0 && millis() > buttonTimer) {
buttonOff();
buttonOnState = 0;
}
}
void processTouch() {
touchEvent = 0;//reset touchEvent
if (millis() > touchTime) { //give them some time to move their finger off...saves processing loads of false touches
touchTime = millis() + debounceSensitivity; //reset the timer
//see if there is a touch in progress
tp = ts.getPoint();
//reset pins for next time we call the line above
pinMode(YP, OUTPUT); //restore shared pins
pinMode(XM, OUTPUT);
digitalWrite(YP, HIGH); //because TFT control pins
digitalWrite(XM, HIGH);
//This will print out the touch screen pointer location
//tp.x screen x axis
//tp.y screen y axis
//tp.z screen touch pressure
//if the values are changing while you move your finger across the screen the touch system is working
if (tp.z > 0) {
//Serial.println("tp.x=" + String(tp.x) + ", tp.y=" + String(tp.y) + ", tp.z =" + String(tp.z));
//The values however do not match up with the pixel dimensions of the screen we are using
//now to change the values to something usable
//moving pointer to far left on my screen (box) gives Y value of 934
//moving pointer to far right on my screen gives Y value of 130
//934 - 134 = 800 points left to right screen is 400 pixels
//moving pointer to top on my screen (box) gives X value of 162
//moving pointer to top on my screen gives X value of 840
//840 - 162 = 678 points top to bottom on a 240 pixel screen
//Done this way to match Adafruit GFX library coordinates system
xtouch = (800 - (tp.y - 130)) / 2; //800 minus value is because values are reversed, subtract the 130 to start at zero, divide by 2 because 800 touch points on a 400 pixel wide screen
//equasion below would normally be (tp.x - 162))/2.8 but by multiplying by 10 we get rid of decimal places
ytouch = (10 * (tp.x - 162)) / 28; //subtract the 162 to start at zero, divide by 2.8 because 678 touch points on a 240 pixel high screen
//if the touch is within the limits of our screen
if (xtouch > -1 && xtouch < 400 && ytouch > -1 && ytouch < 240) {
touchEvent = 1;
}
}
}
}
//function to draw button off
void buttonOff(){
//draw a black box to remove the ON colour
tft.fillRect(150, 100, 100, 100, BLACK); // button box
//now draw the button outline
tft.drawRect(150, 100, 100, 100, WHITE); // button box
}
//function to draw button on
void buttonOn(){
//draw a yellow filled box
tft.fillRect(150, 100, 100, 100, YELLOW); // button box
//now draw the button outline
tft.drawRect(150, 100, 100, 100, WHITE); // button box
}
void setup() {
Serial.begin(9600);
Serial.println("screensetUpV3...");
Serial.println(" ");
//Get the screens type
uint16_t ID = tft.readID();
Serial.print("ID = 0x");
Serial.println(ID, HEX);
tft.begin(ID);//start the screen
tft.setRotation(TOUCH_ORIENTATION);
//make the whole screen black as a back ground
tft.fillScreen(BLACK);
//my screen is 400x240
//ZERO is the first pixel, not 1 so max width for 400 screen is 399
tft.drawRect(0, 0, 399, 239, YELLOW); // button box
buttonOff();
}
void loop() {
screenPress();
}
Example 5: Oscilloscopev1.ino
This code is from the Power Supply Oscilloscope projec. It is shown here as it contains code on how multiple buttons can be checked and processed when a touch
takes place.
The project also has two screens, the voltmeter and Oscilloscope, so it is possible to see how screens are switched between and how button touches are processed without interfering between screens.
The sketch also uses downloadable fonts and shows how to display and refresh text.
This script draws and updates a graph at quite high speeds.
Although not the final Oscilloscope project code it does show in a smaller sketch how some of these things are done.
Click to Download code:Oscilloscopev1.ino
/* 08/09/2021
oscilloscopev1
This versions goal is to see if I can get a graph to display correctly, proof of concept version
3.3v only as no voltage divider yet.
Conclusion and thoughts for v2
works as a proof of concept and usuable
Needs a lot of the floats removed to speed it up
Some external circuitry such as voltage divider and power isolator would improve unit.
Touch screen set up
3.5" Open Smart 400x240
ST7793
Pins
I am using an Arduino DUE
WARNING The break out boards are 3.3v power and logic on digital pins
Connecting directly to a 5v Arduino Mega/Nano/UNO will probably kill the screen
If the board is on a shield it should be 5v compatible but check
I am using a 3.3v Arduino Due
Screen - Arduino
GND - GND
3.3v - 3.3v
CS - A3
X RS - A2
Y WR - A1
RD - A0
RST - A4
LED - GND
DB0 - 8
DB1 - 9
DB2 - 2
DB3 - 3
DB4 - 4
DB5 - 5
DB6 - 6
DB7 - 7
Pins used
3-9 screen
A0-A4 screen
A5 Voltmeter/Oscilloscope
A6 Voltmeter/Oscilloscope
*/
//Libraries required
#include
//fonts
#include
#include
//make sure your screen is not commeneted out in MCUFriend_kpv.cpp
//My screen is a ST7793
#include
//Create Touch screen object
MCUFRIEND_kbv tft;
//sets the rotation of the screen
//change the value depending how you want to use the screen, useful if you fit it in an enclosure the wrong way round.
//0 would be portrait...values 0-3 on 90 degree increments
#define TOUCH_ORIENTATION 1 //1 is landscape 400 wide x 240 high on my screen
//define some colours so don't need to remember hex codes
//see https://ee-programming-notepad.blogspot.com/2016/10/16-bit-color-generator-picker.html
//to create custom colours
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
//Now we know the display is working start on touch
//values below come from running Touch_shield_new.ino
//from the MCUFriend_kbv library examples
//input stuff starts here
int XP = 6, YP = 55, XM = 56, YM = 7; //from calibration test
//Adafruit Touch screen library
#include //
TouchScreen ts(XP, YP, XM, YM, 300); //re-initialised after diagnose
TSPoint tp;//create a touch point object in the library
//Global variables that will contain screen X and X touch points
int xtouch;//true screen x position ZERO far left
int ytouch;//true screen y position ZERO top of screen
unsigned long touchTime;//stores the time in millis of the last touch
//alter this value to change the debounce sensitivity
int debounceSensitivity = 220;// too low gives false positives as will still be touching same point, too high and will become unresponsive
int touchEvent;//keeps track of touch event 1 = event to process
int screenMode = 0;//keeps track of current screen
int voltAnalogPins[2][2] = { //array to hold the analog pins and their current reading
{A5,0}, //pin number...analog read value
{A6,0}
};
float voltageMultiplier = 0.0032;//3.3v board...will need altering depending on voltage divider
float readingsVolts[2][2];//old and new values
unsigned long voltTimer;
unsigned long screenChangeTimer;
int oscFrequency = 100;//Oscillator frequency HZ
int freqStep;//keeps position of next line on oscilloscope
unsigned long hzTimer; //time till next reading
int oscMaxVolt = 5;
//putting the screen boxes in an array like this allows them to be worked through and processed more efficiently
//when looking for what has been touched.
//Also allows you to set text as an offset of the various box dimensions
//Alterations to box size does no effect touch system
int screenboxes[][6] = {//x,y,w,h,screen mode,respond to touch
{0,0,399,239,0,0},//screen 1 boundary box
{2,2,40,40,0,1},//switch mode
{50,120,100,100,0,0},//voltmenter left
{250,120,100,100,0,0},//voltmeter right
{0,0,0,0,0,0},//reserved for upgrades
{0,0,0,0,0,0},//reserved
{0,0,0,0,0,0},//reserved
{0,0,0,0,0,0},//reserved
{0,0,0,0,0,0},//reserved
{0,0,0,0,0,0},////reserved box 9
////////////////screenMode 1 oscilloscope
{0,0,40,40,1,1},//10...switch mode
{0,42,40,40,1,1},//11...V1 on off
{0,84,40,40,1,1},//12...V2 on off
{0,126,40,40,1,1},//13...v1/2 on off
{0,168,40,35,1,1},//14...Auto range
{0,205,40,35,1,1},//15...spare
{42,215,45,24,1,1},//16 <<<
{89,215,45,24,1,1},//17 <<
{134,215,45,24,1,1},//18 <
{261,215,45,24,1,1},//19 >>
{308,215,45,24,1,1},//20 >>
{355,215,45,24,1,1},//21 >
{181,215,78,24,1,0},//22 frequency
{0,0,0,0,1,0},//reserved for upgrades
{0,0,0,0,1,0},//reserved
{0,0,0,0,1,0},//reserved 25
///////////spare
{0,0,0,0,0,0}
};
int numscreenboxes = 26;//number of items in the array above
int buttonState[26];//holds the button states for all buttons 0 off 1 on
//find out if a button has been pressed
void processScreenPress(){
int q;
//loop thourgh the screenboxes array
for(q=0;q= screenboxes[q][0] && xtouch <= screenboxes[q][0]+screenboxes[q][2] && ytouch >= screenboxes[q][1] && ytouch <= screenboxes[q][1]+screenboxes[q][3]){
Serial.println(q);
switchButtonProcess(q);
}
}
}
}
//works out what the response to a button press should be
void switchButtonProcess(int myButton){
int q = myButton;
switch(myButton){
case 1://switch to oscilloscope mode
buildscreen1();//redraw screen in new mode
break;
case 10://switch to voltmeter
buildscreen0();//redraw screen in new mode
break;
case 11:
changeButtonState(myButton);
drawButtonState(q,4,27,"V1",GREEN);
break;
case 12:
changeButtonState(myButton);
drawButtonState(q,4,27,"V2",RED);
break;
case 13:
changeButtonState(myButton);
drawButtonState(q,4,27,"1-2",CYAN);
break;
case 14:
changeButtonState(myButton);
drawButtonState(q,4,23,"R+",GREEN);
if(oscMaxVolt < 21){
oscMaxVolt++;
buildscreen1();
}
break;
case 15:
changeButtonState(myButton);
drawButtonState(q,4,23,"R-",GREEN);
if(oscMaxVolt > 1){
oscMaxVolt--;
buildscreen1();
}
break;
case 16:
oscFrequency = oscFrequency + 1000;
buildscreen1();
break;
case 17:
oscFrequency = oscFrequency + 100;
buildscreen1();
break;
case 18:
oscFrequency = oscFrequency + 1;
buildscreen1();
break;
case 19:
oscFrequency = oscFrequency - 1;
if(oscFrequency < 1){
oscFrequency = 1;
}
buildscreen1();
break;
case 20:
oscFrequency = oscFrequency - 100;
if(oscFrequency < 1){
oscFrequency = 1;
}
buildscreen1();
break;
case 21:
oscFrequency = oscFrequency - 1000;
if(oscFrequency < 1){
oscFrequency = 1;
}
buildscreen1();
break;
default:
break;
}
}
void changeButtonState(int myButton){
if(buttonState[myButton] < 1){
buttonState[myButton] = 1;
}else{
buttonState[myButton] = 0;
}
}
//builds the initial voltmeter screen, switch mode button, should contain 2 voltmeters
void buildscreen0(){
int q;
if(millis() > screenChangeTimer){
screenChangeTimer = millis() + 200;
//make the whole screen black as a back ground
tft.fillScreen(BLACK);
//400 x 240 screen
//using some downloadable fonts as they display better
tft.setFont(&FreeSans12pt7b);
tft.setTextColor(WHITE, BLACK);
tft.drawRect(screenboxes[0][0], screenboxes[0][1], screenboxes[0][2], screenboxes[0][3], WHITE); // Boundary Box
tft.drawRect(screenboxes[1][0], screenboxes[1][1], screenboxes[1][2], screenboxes[1][3], WHITE); // Mode Box
tft.setCursor(screenboxes[1][0]+9,screenboxes[1][1]+27);
tft.println("O");
for(q=2;q<4;q++){
tft.drawRect(screenboxes[q][0], screenboxes[q][1], screenboxes[q][2], screenboxes[q][3], WHITE); // Mode Box
tft.setCursor(screenboxes[q][0]+23,screenboxes[q][1]+75);
tft.println("Volts");
}
screenMode = 0;
//Serial.println(screenMode);
}
}
//Oscilloscope screen
void buildscreen1(){
int q;
buttonState[14] = 0;
buttonState[15] = 0;
if(millis() > screenChangeTimer){
screenChangeTimer = millis() + 200;
//make the whole screen black as a back ground
tft.fillScreen(BLACK);
tft.setFont(&FreeSans12pt7b);
tft.setTextColor(WHITE, BLACK);
q=10;//switch to voltmeter...doesn't have on off state as switches screen
tft.drawRect(screenboxes[q][0], screenboxes[q][1], screenboxes[q][2], screenboxes[q][3], WHITE);
tft.setCursor(screenboxes[1][0]+9,screenboxes[1][1]+27);
tft.println("V");
for(q=11;q<16;q++){
if(buttonState[q] < 1){
buttonState[q] = 1;
}else{
buttonState[q] = 0;
}
switchButtonProcess(q);
}
q=16;
drawButtonState(q,2,16,"<<<",YELLOW);
q=17;
drawButtonState(q,8,16,"<<",YELLOW);
q=18;
drawButtonState(q,11,16,"<",YELLOW);
q=19;
drawButtonState(q,11,16,">",YELLOW);
q=20;
drawButtonState(q,8,16,">>",YELLOW);
q=21;
drawButtonState(q,2,16,">>>",YELLOW);
q=22;
refreshFreqDisp();
drawXYAxis();
screenMode = 1;
Serial.println(screenMode);
}
}
//draws Oscilloscope XY axis with values
void drawXYAxis(){
//oscMaxVolt...max volts
float voltFloat;
tft.drawLine(89, 5, 389, 5, YELLOW);//X Axis
tft.drawLine(89, 55, 389, 55, YELLOW);//X Axis
tft.drawLine(89, 105, 389, 105, YELLOW);//X Axis
tft.drawLine(89, 155, 389, 155, YELLOW);//X Axis
tft.drawLine(89, 205, 389, 205, WHITE);//X Axis baseline
tft.drawLine(88, 0, 88, 205, WHITE);//Y Axis
tft.drawLine(390, 0, 390, 205, WHITE);//Y Axis
tft.setFont(&FreeSans9pt7b);
tft.setTextColor(WHITE, BLACK);
tft.setCursor(44,12);
voltFloat = 1.00*oscMaxVolt;
tft.println(voltFloat);
tft.setCursor(44,62);
voltFloat = 3.00*(oscMaxVolt/4.00);
tft.println(voltFloat);
tft.setCursor(44,112);
voltFloat = 1.00*(oscMaxVolt/2.00);
tft.println(voltFloat);
tft.setCursor(44,162);
voltFloat = 1.00*(oscMaxVolt/4.00);
tft.println(voltFloat);
}
void refreshFreqDisp(){
int q = 22;
tft.fillRect(screenboxes[q][0], screenboxes[q][1], screenboxes[q][2], screenboxes[q][3], BLACK);
tft.setFont(&FreeSans9pt7b);
tft.setCursor(screenboxes[q][0]+2,screenboxes[q][1]+20);
tft.println(oscFrequency);
tft.setCursor(screenboxes[q][0]+54,screenboxes[q][1]+20);
tft.println("Hz");
}
//draws buttons state and puts in text
void drawButtonState(int MyButton,int XOffset,int YOffset,String MyButtonText,int MyButtonColour){
int q = MyButton;//line just allows me to reuse same box code
Serial.println(buttonState[MyButton]);
Serial.println(MyButton);
if(buttonState[MyButton] == 0){//button off
tft.fillRect(screenboxes[q][0], screenboxes[q][1], screenboxes[q][2], screenboxes[q][3], BLACK);
tft.drawRect(screenboxes[q][0], screenboxes[q][1], screenboxes[q][2], screenboxes[q][3], WHITE);
tft.setTextColor(WHITE, BLACK);
}else{//button on
tft.drawRect(screenboxes[q][0], screenboxes[q][1], screenboxes[q][2], screenboxes[q][3], BLACK);
tft.drawRect(screenboxes[q][0], screenboxes[q][1], screenboxes[q][2], screenboxes[q][3], WHITE);
tft.setTextColor(MyButtonColour,BLACK );
}
tft.setFont(&FreeSans12pt7b);
tft.setCursor(screenboxes[q][0]+XOffset,screenboxes[q][1]+YOffset);
tft.println(MyButtonText);
}
//puts the volts into the voltmeter
//The rest of the screen stays constant, this keeps the screen speed fast
void voltmeter(){
int q;
if(millis() > voltTimer){
voltTimer = millis() + 100;//display voltage update every 100 milliseconds
tft.setFont(&FreeSans12pt7b);
tft.setTextColor(WHITE, BLACK);
for(q=0;q<2;q++){
voltAnalogPins[q][1] = analogRead(voltAnalogPins[q][0]);//get the values for the pins and store them in the array
readingsVolts[q][0] = voltAnalogPins[q][1] * voltageMultiplier;
//put a black background in to delete old text
if(readingsVolts[q][0] != readingsVolts[q][1]){//only update screen if something to update
//black box to blank out last value
tft.fillRect(screenboxes[q+2][0]+2, screenboxes[q+2][1]+2, screenboxes[q+2][2]-4, screenboxes[q+2][3]/2, BLACK); // text background
tft.setCursor(screenboxes[q+2][0]+23,screenboxes[q+2][1]+25);
tft.println(readingsVolts[q][0]);
}
readingsVolts[q][1] = readingsVolts[q][0];
}
}
}
//This only redraws a single line at a time on the oscilloscope
void oscilloscope(){
if(micros() > hzTimer){
hzTimer = micros() + (1000000/oscFrequency);
tft.drawLine(freqStep+89,0,freqStep+89,204,BLACK);//blank out previous
tft.drawPixel(freqStep+89,5,YELLOW);
tft.drawPixel(freqStep+89,55,YELLOW);
tft.drawPixel(freqStep+89,105,YELLOW);
tft.drawPixel(freqStep+89,155,YELLOW);
tft.drawPixel(freqStep+89,205,WHITE);
if(buttonState[11] == 1){//V1
voltAnalogPins[0][1] = analogRead(voltAnalogPins[0][0]);//get the values for the pins and store them in the array
readingsVolts[0][0] = voltAnalogPins[0][1] * voltageMultiplier;
//oscMaxVolt
int pixelPos = 205 - (200/oscMaxVolt * readingsVolts[0][0]);
//Serial.print(readingsVolts[0][0]);
//Serial.print(" : ");
//Serial.println(pixelPos);
tft.drawPixel(freqStep+89,pixelPos,GREEN);
}
if(buttonState[12] == 1){//V2
voltAnalogPins[1][1] = analogRead(voltAnalogPins[1][0]);//get the values for the pins and store them in the array
readingsVolts[1][0] = voltAnalogPins[1][1] * voltageMultiplier;
//oscMaxVolt
int pixelPos = 205 - (200/oscMaxVolt * readingsVolts[1][0]);
//Serial.print(readingsVolts[0][0]);
// Serial.print(" : ");
//Serial.println(pixelPos);
tft.drawPixel(freqStep+89,pixelPos,RED);
}
if(buttonState[13] == 1){//1-2
voltAnalogPins[1][1] = analogRead(voltAnalogPins[1][0]);//get the values for the pins and store them in the array
readingsVolts[1][0] = voltAnalogPins[1][1] * voltageMultiplier;
//oscMaxVolt
int pixelPos = 205 - (200/oscMaxVolt * (readingsVolts[0][0] - readingsVolts[1][0]));
if(pixelPos < 0){
pixelPos = 0;
}
//Serial.print(readingsVolts[0][0]);
//Serial.print(" : ");
// Serial.println(pixelPos);
tft.drawPixel(freqStep+89,pixelPos,CYAN);
}
freqStep++;
if(freqStep > 299){
freqStep = 0;//go back to start of display
}
}
}
void screenPress() {
processTouch();//call the processTouch function to see if there is anything to process
//if there has been a touch event do something if the touch is within the button boundary
if (touchEvent > 0) {
processScreenPress();//find out if a button has been pressed
}
}
void processTouch() {
touchEvent = 0;//reset touchEvent
if (millis() > touchTime) { //give them some time to move their finger off...saves processing loads of false touches
touchTime = millis() + debounceSensitivity; //reset the timer
//see if there is a touch in progress
tp = ts.getPoint();
//reset pins for next time we call the line above
pinMode(YP, OUTPUT); //restore shared pins
pinMode(XM, OUTPUT);
digitalWrite(YP, HIGH); //because TFT control pins
digitalWrite(XM, HIGH);
if (tp.z > 0) {
//Serial.println("tp.x=" + String(tp.x) + ", tp.y=" + String(tp.y) + ", tp.z =" + String(tp.z));
//The values however do not match up with the pixel dimensions of the screen we are using
//now to change the values to something usable
//moving pointer to far left on my screen (box) gives Y value of 934
//moving pointer to far right on my screen gives Y value of 130
//934 - 134 = 800 points left to right screen is 400 pixels
//moving pointer to top on my screen (box) gives X value of 162
//moving pointer to top on my screen gives X value of 840
//840 - 162 = 678 points top to bottom on a 240 pixel screen
//Done this way to match Adafruit GFX library coordinates system
xtouch = (800 - (tp.y - 130)) / 2; //800 minus value is because values are reversed, subtract the 130 to start at zero, divide by 2 because 800 touch points on a 400 pixel wide screen
//equasion below would normally be (tp.x - 162))/2.8 but by multiplying by 10 we get rid of decimal places
ytouch = (10 * (tp.x - 162)) / 28; //subtract the 162 to start at zero, divide by 2.8 because 678 touch points on a 240 pixel high screen
//if the touch is within the limits of our screen
if (xtouch > -1 && xtouch < 400 && ytouch > -1 && ytouch < 240) {
touchEvent = 1;
}
}
}
}
void setup() {
Serial.begin(9600);
Serial.println("oscilloscopev1...");
Serial.println(" ");
delay(2000);//experiment for when screen first powers up
//Get the screens type
uint16_t ID = tft.readID();
Serial.print("ID = 0x");
Serial.println(ID, HEX);
delay(1000);
tft.reset();
delay(1000);
tft.begin(ID);//start the screen
tft.setRotation(TOUCH_ORIENTATION);
buildscreen0();//builds the initial screen
}
void loop() {
screenPress();
switch(screenMode){
case 0:
voltmeter();//puts the volts in the display
break;
case 1://oscilloscope...updates the graph only
oscilloscope();
break;
default:
break;
}
}
Additional Resource Links
Adafruit GFX library information on the various drawing functions.
Comments
This site has been designed to be child friendly, this means that comments cannot be added to videos or directly to the site. To add a comment or ask a question please email the address in this image: and use Touch Screens as a reference.