mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-08-03 12:44:46 +02:00
Update touch, add Button class
Touch reliability improved by using pressure and double sampling. Added Adafruit compatible Button class. Added touchscreen on/off and keypad examples.
This commit is contained in:
247
TFT_eSPI.cpp
247
TFT_eSPI.cpp
@@ -1179,6 +1179,15 @@ uint8_t TFT_eSPI::getRotation(void)
|
|||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: getTextDatum
|
||||||
|
** Description: Return the text datum value (as used by setTextDatum())
|
||||||
|
***************************************************************************************/
|
||||||
|
uint8_t TFT_eSPI::getTextDatum(void)
|
||||||
|
{
|
||||||
|
return textdatum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: width
|
** Function name: width
|
||||||
@@ -3151,7 +3160,7 @@ int16_t TFT_eSPI::drawString(const char *string, int poX, int poY, int font)
|
|||||||
int16_t sumX = 0;
|
int16_t sumX = 0;
|
||||||
uint8_t padding = 1, baseline = 0;
|
uint8_t padding = 1, baseline = 0;
|
||||||
uint16_t cwidth = textWidth(string, font); // Find the pixel width of the string in the font
|
uint16_t cwidth = textWidth(string, font); // Find the pixel width of the string in the font
|
||||||
uint16_t cheight = 8;
|
uint16_t cheight = 8 * textsize;
|
||||||
|
|
||||||
#ifdef LOAD_GFXFF
|
#ifdef LOAD_GFXFF
|
||||||
if (font == 1) {
|
if (font == 1) {
|
||||||
@@ -3643,14 +3652,15 @@ void spiWriteBlock(uint16_t color, uint32_t repeat)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The following touch screen support code added by maxpautsch 1/10/17
|
// The following touch screen support code by maxpautsch was merged 1/10/17
|
||||||
// https://github.com/maxpautsch
|
// https://github.com/maxpautsch
|
||||||
// Define TOUCH_CS is the user setup file to enable this code
|
// Define TOUCH_CS is the user setup file to enable this code
|
||||||
// An example is provided is 480x320 folder
|
// A demo is provided in examples Generic folder
|
||||||
|
// Additions by Bodmer to double sample and use Z value to improve detection reliability
|
||||||
#ifdef TOUCH_CS
|
#ifdef TOUCH_CS
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: getTouchRaw
|
** Function name: getTouchRaw
|
||||||
** Description: read raw position of touchpad if pressed. Return false if not pressed.
|
** Description: read raw touch position. Return false if not pressed.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){
|
uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){
|
||||||
uint16_t tmp;
|
uint16_t tmp;
|
||||||
@@ -3671,13 +3681,6 @@ uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){
|
|||||||
tmp = tmp <<5;
|
tmp = tmp <<5;
|
||||||
tmp |= 0x1f & (SPI.transfer(0)>>3);
|
tmp |= 0x1f & (SPI.transfer(0)>>3);
|
||||||
|
|
||||||
if(tmp == 0 || tmp == 0x3ff){
|
|
||||||
T_CS_H;
|
|
||||||
SPI.setFrequency(SPI_FREQUENCY);
|
|
||||||
spi_end();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*x = tmp;
|
*x = tmp;
|
||||||
|
|
||||||
// Start bit + XP sample request for y position
|
// Start bit + XP sample request for y position
|
||||||
@@ -3692,23 +3695,87 @@ uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){
|
|||||||
SPI.setFrequency(SPI_FREQUENCY);
|
SPI.setFrequency(SPI_FREQUENCY);
|
||||||
spi_end();
|
spi_end();
|
||||||
|
|
||||||
if(tmp == 0 || tmp == 0x3ff){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: getTouch
|
** Function name: getTouchRawZ
|
||||||
** Description: read callibrated position of touchpad if pressed. Return false if not pressed.
|
** Description: read raw pressure on touchpad and return Z value.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
uint16_t TFT_eSPI::getTouchRawZ(void){
|
||||||
|
CS_H;
|
||||||
|
T_CS_L;
|
||||||
|
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
#ifdef SUPPORT_TRANSACTIONS
|
||||||
|
if (locked) {locked = false; SPI.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SPI.setFrequency(SPI_TOUCH_FREQUENCY);
|
||||||
|
|
||||||
|
// Z sample request
|
||||||
|
uint16_t tz = 0xFFF;
|
||||||
|
SPI.transfer(0xb1);
|
||||||
|
tz += SPI.transfer16(0xc1) >> 3;
|
||||||
|
tz -= SPI.transfer16(0x91) >> 3;
|
||||||
|
|
||||||
|
T_CS_H;
|
||||||
|
SPI.setFrequency(SPI_FREQUENCY);
|
||||||
|
spi_end();
|
||||||
|
|
||||||
|
return tz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: validTouch
|
||||||
|
** Description: read validated position. Return false if not pressed.
|
||||||
|
***************************************************************************************/
|
||||||
|
#define _RAWERR 10 // Deadband in position samples
|
||||||
|
uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
|
||||||
|
uint16_t x_tmp, y_tmp, x_tmp2, y_tmp2;
|
||||||
|
|
||||||
|
|
||||||
|
// uint16_t z_tmp = getTouchRawZ(); // Save value for debug message
|
||||||
|
// Debug messages used for tuning
|
||||||
|
// Serial.print("Z = ");Serial.println(z_tmp);
|
||||||
|
|
||||||
|
if (getTouchRawZ() <= threshold) return false;
|
||||||
|
|
||||||
|
delay(2); // Small debounce delay to the next sample
|
||||||
|
getTouchRaw(&x_tmp,&y_tmp);
|
||||||
|
|
||||||
|
// z_tmp = getTouchRawZ();
|
||||||
|
// Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp);
|
||||||
|
// Serial.print(", Z = ");Serial.println(z_tmp);
|
||||||
|
|
||||||
|
delay(2); // Small debounce delay to the next sample
|
||||||
|
if (getTouchRawZ() <= threshold) return false;
|
||||||
|
|
||||||
|
delay(2); // Small debounce delay to the next sample
|
||||||
|
getTouchRaw(&x_tmp2,&y_tmp2);
|
||||||
|
|
||||||
|
// Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2);
|
||||||
|
// Serial.print("Sample difference = ");Serial.print(abs(x_tmp - x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2));
|
||||||
|
|
||||||
|
if (abs(x_tmp - x_tmp2) > _RAWERR) return false;
|
||||||
|
if (abs(y_tmp - y_tmp2) > _RAWERR) return false;
|
||||||
|
|
||||||
|
*x = x_tmp;
|
||||||
|
*y = y_tmp;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: getTouch
|
||||||
|
** Description: read callibrated position. Return false if not pressed.
|
||||||
|
***************************************************************************************/
|
||||||
|
#define Z_THRESHOLD 0x200 // Touch pressure threshold for validating touches
|
||||||
uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y){
|
uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y){
|
||||||
uint8_t retVal;
|
|
||||||
uint16_t x_tmp, y_tmp;
|
uint16_t x_tmp, y_tmp;
|
||||||
|
|
||||||
retVal = getTouchRaw(&x_tmp,&y_tmp);
|
if(!validTouch(&x_tmp, &y_tmp, Z_THRESHOLD)) return false;
|
||||||
if(!retVal)
|
|
||||||
return retVal;
|
|
||||||
|
|
||||||
if(!touchCalibration_rotate){
|
if(!touchCalibration_rotate){
|
||||||
*x=(x_tmp-touchCalibration_x0)*_width/touchCalibration_x1;
|
*x=(x_tmp-touchCalibration_x0)*_width/touchCalibration_x1;
|
||||||
@@ -3726,14 +3793,14 @@ uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y){
|
|||||||
*y = _height - *y;
|
*y = _height - *y;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: calibrateTouch
|
** Function name: calibrateTouch
|
||||||
** Description: generates calibration parameters for touchscreen.
|
** Description: generates calibration parameters for touchscreen.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
uint8_t TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_bg, uint32_t color_fg, uint8_t size){
|
void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t color_bg, uint8_t size){
|
||||||
int16_t values[] = {0,0,0,0,0,0,0,0};
|
int16_t values[] = {0,0,0,0,0,0,0,0};
|
||||||
uint16_t x_tmp, y_tmp;
|
uint16_t x_tmp, y_tmp;
|
||||||
|
|
||||||
@@ -3774,7 +3841,8 @@ uint8_t TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_bg, uint32
|
|||||||
if(i>0) delay(1000);
|
if(i>0) delay(1000);
|
||||||
|
|
||||||
for(uint8_t j= 0; j<8; j++){
|
for(uint8_t j= 0; j<8; j++){
|
||||||
while(!getTouchRaw(&x_tmp, &y_tmp)) delay(100);
|
// Use a lower detect threshold as corners tend to be less sensitive
|
||||||
|
while(!validTouch(&x_tmp, &y_tmp, Z_THRESHOLD/2)) delay(10);
|
||||||
values[i*2 ] += x_tmp;
|
values[i*2 ] += x_tmp;
|
||||||
values[i*2+1] += y_tmp;
|
values[i*2+1] += y_tmp;
|
||||||
}
|
}
|
||||||
@@ -3847,8 +3915,141 @@ void TFT_eSPI::setTouch(uint16_t *parameters){
|
|||||||
touchCalibration_invert_y = parameters[4] & 0x04;
|
touchCalibration_invert_y = parameters[4] & 0x04;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else // TOUCH CS is not defined so generate dummy functions that do nothing
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: getTouchRaw
|
||||||
|
** Description: read raw touch position. Return false if not pressed.
|
||||||
|
***************************************************************************************/
|
||||||
|
uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: getTouchRawZ
|
||||||
|
** Description: read raw pressure on touchpad and return Z value.
|
||||||
|
***************************************************************************************/
|
||||||
|
uint16_t TFT_eSPI::getTouchRawZ(void){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: validTouch
|
||||||
|
** Description: read validated position. Return false if not pressed.
|
||||||
|
***************************************************************************************/
|
||||||
|
uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: getTouch
|
||||||
|
** Description: read callibrated position. Return false if not pressed.
|
||||||
|
***************************************************************************************/
|
||||||
|
uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: calibrateTouch
|
||||||
|
** Description: generates calibration parameters for touchscreen.
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_bg, uint32_t color_fg, uint8_t size){
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: setTouch
|
||||||
|
** Description: imports calibration parameters for touchscreen.
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSPI::setTouch(uint16_t *parameters){
|
||||||
|
}
|
||||||
|
|
||||||
#endif // TOUCH_CS
|
#endif // TOUCH_CS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Code for the GFX button UI element
|
||||||
|
** Grabbed from Adafruit_GFX library and enhanced to handle any label font
|
||||||
|
***************************************************************************************/
|
||||||
|
TFT_eSPI_Button::TFT_eSPI_Button(void) {
|
||||||
|
_gfx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Classic initButton() function: pass center & size
|
||||||
|
void TFT_eSPI_Button::initButton(
|
||||||
|
TFT_eSPI *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
|
||||||
|
uint16_t outline, uint16_t fill, uint16_t textcolor,
|
||||||
|
char *label, uint8_t textsize)
|
||||||
|
{
|
||||||
|
// Tweak arguments and pass to the newer initButtonUL() function...
|
||||||
|
initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill,
|
||||||
|
textcolor, label, textsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Newer function instead accepts upper-left corner & size
|
||||||
|
void TFT_eSPI_Button::initButtonUL(
|
||||||
|
TFT_eSPI *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h,
|
||||||
|
uint16_t outline, uint16_t fill, uint16_t textcolor,
|
||||||
|
char *label, uint8_t textsize)
|
||||||
|
{
|
||||||
|
_x1 = x1;
|
||||||
|
_y1 = y1;
|
||||||
|
_w = w;
|
||||||
|
_h = h;
|
||||||
|
_outlinecolor = outline;
|
||||||
|
_fillcolor = fill;
|
||||||
|
_textcolor = textcolor;
|
||||||
|
_textsize = textsize;
|
||||||
|
_gfx = gfx;
|
||||||
|
strncpy(_label, label, 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TFT_eSPI_Button::drawButton(boolean inverted) {
|
||||||
|
uint16_t fill, outline, text;
|
||||||
|
|
||||||
|
if(!inverted) {
|
||||||
|
fill = _fillcolor;
|
||||||
|
outline = _outlinecolor;
|
||||||
|
text = _textcolor;
|
||||||
|
} else {
|
||||||
|
fill = _textcolor;
|
||||||
|
outline = _outlinecolor;
|
||||||
|
text = _fillcolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t r = min(_w, _h) / 4; // Corner radius
|
||||||
|
_gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill);
|
||||||
|
_gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline);
|
||||||
|
|
||||||
|
_gfx->setTextColor(text);
|
||||||
|
_gfx->setTextSize(_textsize);
|
||||||
|
|
||||||
|
static byte tempdatum = _gfx->getTextDatum();
|
||||||
|
_gfx->setTextDatum(MC_DATUM);
|
||||||
|
_gfx->drawString(_label, _x1 + (_w/2), _y1 + (_h/2));
|
||||||
|
_gfx->setTextDatum(tempdatum);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean TFT_eSPI_Button::contains(int16_t x, int16_t y) {
|
||||||
|
return ((x >= _x1) && (x < (_x1 + _w)) &&
|
||||||
|
(y >= _y1) && (y < (_y1 + _h)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TFT_eSPI_Button::press(boolean p) {
|
||||||
|
laststate = currstate;
|
||||||
|
currstate = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean TFT_eSPI_Button::isPressed() { return currstate; }
|
||||||
|
boolean TFT_eSPI_Button::justPressed() { return (currstate && !laststate); }
|
||||||
|
boolean TFT_eSPI_Button::justReleased() { return (!currstate && laststate); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************
|
/***************************************************
|
||||||
The majority of code in this file is "FunWare", the only condition of use of
|
The majority of code in this file is "FunWare", the only condition of use of
|
||||||
those portions is that users have fun! Most of the effort has been spent on
|
those portions is that users have fun! Most of the effort has been spent on
|
||||||
|
69
TFT_eSPI.h
69
TFT_eSPI.h
@@ -393,7 +393,8 @@ class TFT_eSPI : public Print {
|
|||||||
// Set w and h to 1 to read 1 pixel's colour. The data buffer must be at least w * h * 3 bytes
|
// Set w and h to 1 to read 1 pixel's colour. The data buffer must be at least w * h * 3 bytes
|
||||||
void readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data);
|
void readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data);
|
||||||
|
|
||||||
uint8_t getRotation(void);
|
uint8_t getRotation(void),
|
||||||
|
getTextDatum(void);
|
||||||
|
|
||||||
uint16_t fontsLoaded(void),
|
uint16_t fontsLoaded(void),
|
||||||
color565(uint8_t r, uint8_t g, uint8_t b);
|
color565(uint8_t r, uint8_t g, uint8_t b);
|
||||||
@@ -425,37 +426,38 @@ class TFT_eSPI : public Print {
|
|||||||
textWidth(const String& string),
|
textWidth(const String& string),
|
||||||
fontHeight(int16_t font);
|
fontHeight(int16_t font);
|
||||||
|
|
||||||
void setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye);
|
void setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye);
|
||||||
|
|
||||||
#ifdef TOUCH_CS
|
// These are associated with the Touch Screen handlers
|
||||||
uint8_t getTouch(uint16_t *x, uint16_t *y);
|
uint8_t getTouchRaw(uint16_t *x, uint16_t *y);
|
||||||
uint8_t getTouchRaw(uint16_t *x, uint16_t *y);
|
uint16_t getTouchRawZ(void);
|
||||||
uint8_t calibrateTouch(uint16_t *data, uint32_t color_bg, uint32_t color_fg, uint8_t size);
|
uint8_t getTouch(uint16_t *x, uint16_t *y);
|
||||||
void setTouch(uint16_t *data);
|
|
||||||
#endif
|
void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size);
|
||||||
|
void setTouch(uint16_t *data);
|
||||||
|
|
||||||
virtual size_t write(uint8_t);
|
virtual size_t write(uint8_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
inline void spi_begin() __attribute__((always_inline));
|
inline void spi_begin() __attribute__((always_inline));
|
||||||
inline void spi_end() __attribute__((always_inline));
|
inline void spi_end() __attribute__((always_inline));
|
||||||
|
|
||||||
void readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye);
|
void readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye);
|
||||||
|
|
||||||
uint8_t tabcolor,
|
uint8_t tabcolor,
|
||||||
colstart = 0, rowstart = 0; // some ST7735 displays need this changed
|
colstart = 0, rowstart = 0; // some ST7735 displays need this changed
|
||||||
|
|
||||||
volatile uint32_t *dcport, *csport;//, *mosiport, *clkport, *rsport;
|
volatile uint32_t *dcport, *csport;//, *mosiport, *clkport, *rsport;
|
||||||
|
|
||||||
uint32_t cspinmask, dcpinmask, wrpinmask;//, mosipinmask, clkpinmask;
|
uint32_t cspinmask, dcpinmask, wrpinmask;//, mosipinmask, clkpinmask;
|
||||||
|
|
||||||
uint32_t lastColor = 0xFFFF;
|
uint32_t lastColor = 0xFFFF;
|
||||||
|
|
||||||
#ifdef TOUCH_CS
|
// These are associated with the Touch Screen handlers
|
||||||
|
uint8_t validTouch(uint16_t *x, uint16_t *y, uint16_t threshold);
|
||||||
uint16_t touchCalibration_x0, touchCalibration_x1, touchCalibration_y0, touchCalibration_y1;
|
uint16_t touchCalibration_x0, touchCalibration_x1, touchCalibration_y0, touchCalibration_y1;
|
||||||
uint8_t touchCalibration_rotate, touchCalibration_invert_x, touchCalibration_invert_y;
|
uint8_t touchCalibration_rotate, touchCalibration_invert_x, touchCalibration_invert_y;
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -482,6 +484,45 @@ inline void spi_end() __attribute__((always_inline));
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
// The following button class has been ported over from the Adafruit_GFX library so
|
||||||
|
// should be compatible.
|
||||||
|
// A slightly different implementation in this TFT_eSPI library allows the button
|
||||||
|
// legends to be in any font
|
||||||
|
***************************************************************************************/
|
||||||
|
|
||||||
|
class TFT_eSPI_Button {
|
||||||
|
|
||||||
|
public:
|
||||||
|
TFT_eSPI_Button(void);
|
||||||
|
// "Classic" initButton() uses center & size
|
||||||
|
void initButton(TFT_eSPI *gfx, int16_t x, int16_t y,
|
||||||
|
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
|
||||||
|
uint16_t textcolor, char *label, uint8_t textsize);
|
||||||
|
|
||||||
|
// New/alt initButton() uses upper-left corner & size
|
||||||
|
void initButtonUL(TFT_eSPI *gfx, int16_t x1, int16_t y1,
|
||||||
|
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
|
||||||
|
uint16_t textcolor, char *label, uint8_t textsize);
|
||||||
|
void drawButton(boolean inverted = false);
|
||||||
|
boolean contains(int16_t x, int16_t y);
|
||||||
|
|
||||||
|
void press(boolean p);
|
||||||
|
boolean isPressed();
|
||||||
|
boolean justPressed();
|
||||||
|
boolean justReleased();
|
||||||
|
|
||||||
|
private:
|
||||||
|
TFT_eSPI *_gfx;
|
||||||
|
int16_t _x1, _y1; // Coordinates of top-left corner
|
||||||
|
uint16_t _w, _h;
|
||||||
|
uint8_t _textsize;
|
||||||
|
uint16_t _outlinecolor, _fillcolor, _textcolor;
|
||||||
|
char _label[10];
|
||||||
|
|
||||||
|
boolean currstate, laststate;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/***************************************************
|
/***************************************************
|
||||||
|
10
User_Setup.h
10
User_Setup.h
@@ -152,10 +152,12 @@
|
|||||||
//
|
//
|
||||||
// ##################################################################################
|
// ##################################################################################
|
||||||
|
|
||||||
// Define the SPI clock frequency
|
// Define the SPI clock frequency, this affects the graphics rendering speed. Too
|
||||||
|
// fast and the TFT driver will not keep up and display corruption appears.
|
||||||
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
|
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
|
||||||
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
|
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
|
||||||
// With an ILI9163 display TBD MHz works OK,
|
// With an ILI9163 display 27 MHz works OK.
|
||||||
|
// The RPi typically only works at 20MHz maximum.
|
||||||
|
|
||||||
// #define SPI_FREQUENCY 1000000
|
// #define SPI_FREQUENCY 1000000
|
||||||
// #define SPI_FREQUENCY 5000000
|
// #define SPI_FREQUENCY 5000000
|
||||||
@@ -172,6 +174,10 @@
|
|||||||
// supported. Tranaction support is required if other SPI devices are connected.
|
// supported. Tranaction support is required if other SPI devices are connected.
|
||||||
// When commented out the code size will be smaller and sketches will
|
// When commented out the code size will be smaller and sketches will
|
||||||
// run slightly faster, so leave it commented out unless you need it!
|
// run slightly faster, so leave it commented out unless you need it!
|
||||||
|
|
||||||
// Transaction support is needed to work with SD library but not needed with TFT_SdFat
|
// Transaction support is needed to work with SD library but not needed with TFT_SdFat
|
||||||
|
|
||||||
|
// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
|
||||||
|
// so changing it here has noo effect
|
||||||
|
|
||||||
// #define SUPPORT_TRANSACTIONS
|
// #define SUPPORT_TRANSACTIONS
|
||||||
|
@@ -76,12 +76,13 @@
|
|||||||
|
|
||||||
// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR SETUP ######
|
// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR SETUP ######
|
||||||
|
|
||||||
// ModeMCU
|
// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
|
||||||
#define TFT_CS PIN_D8 // Chip select control pin D8
|
#define TFT_CS PIN_D8 // Chip select control pin D8
|
||||||
#define TFT_DC PIN_D3 // Data Command control pin
|
#define TFT_DC PIN_D3 // Data Command control pin
|
||||||
//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
|
#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
|
||||||
#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
|
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
|
||||||
#define TOUCH_CS D4 // Chip select pin (T_CS) of touch screen controller XPT2046
|
|
||||||
|
#define TOUCH_CS PIN_D1 // Chip select pin (T_CS) of touch screen, also define SPI frequency in Section 5 below
|
||||||
|
|
||||||
//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
|
//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
|
||||||
|
|
||||||
|
284
examples/320 x 240/Keypad_240x320/Keypad_240x320.ino
Normal file
284
examples/320 x 240/Keypad_240x320/Keypad_240x320.ino
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
The TFT_eSPI library incorporates an Adafruit_GFX compatible
|
||||||
|
button handling class, this sketch is based on the Arduin-o-phone
|
||||||
|
example.
|
||||||
|
|
||||||
|
This example diplays a keypad where numbers can be entered and
|
||||||
|
send to the Serial Monitor window.
|
||||||
|
|
||||||
|
The sketch has been tested on the ESP8266 (which supports SPIFFS)
|
||||||
|
|
||||||
|
The minimum screen size is 320 x 240 as that is the keypad size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The SPIFFS (FLASH filing system) is used to hold touch screen
|
||||||
|
// calibration data
|
||||||
|
|
||||||
|
#include "FS.h"
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <TFT_eSPI.h> // Hardware-specific library
|
||||||
|
|
||||||
|
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
|
||||||
|
|
||||||
|
// This is the file name used to store the calibration data
|
||||||
|
// You can change this to create new calibration files.
|
||||||
|
// The SPIFFS file name must start with "/".
|
||||||
|
#define CALIBRATION_FILE "/TouchCalData1"
|
||||||
|
|
||||||
|
// Set REPEAT_CAL to true instead of false to run calibration
|
||||||
|
// again, otherwise it will only be done once.
|
||||||
|
// Repeat calibration if you change the screen rotation.
|
||||||
|
#define REPEAT_CAL false
|
||||||
|
|
||||||
|
// Keypad start position, key sizes and spacing
|
||||||
|
#define KEY_X 40 // Centre of key
|
||||||
|
#define KEY_Y 96
|
||||||
|
#define KEY_W 62 // Width and height
|
||||||
|
#define KEY_H 30
|
||||||
|
#define KEY_SPACING_X 18 // X and Y gap
|
||||||
|
#define KEY_SPACING_Y 20
|
||||||
|
#define KEY_TEXTSIZE 1 // Font size multiplier
|
||||||
|
|
||||||
|
// Using two fonts since numbers are nice when bold
|
||||||
|
#define LABEL1_FONT &FreeSansOblique12pt7b // Key label font 1
|
||||||
|
#define LABEL2_FONT &FreeSansBold12pt7b // Key label font 2
|
||||||
|
|
||||||
|
// Numeric display box size and location
|
||||||
|
#define DISP_X 1
|
||||||
|
#define DISP_Y 10
|
||||||
|
#define DISP_W 238
|
||||||
|
#define DISP_H 50
|
||||||
|
#define DISP_TSIZE 3
|
||||||
|
#define DISP_TCOLOR TFT_CYAN
|
||||||
|
|
||||||
|
// Number length, buffer for storing it and character index
|
||||||
|
#define NUM_LEN 12
|
||||||
|
char numberBuffer[NUM_LEN + 1] = "";
|
||||||
|
uint8_t numberIndex = 0;
|
||||||
|
|
||||||
|
// We have a status line for messages
|
||||||
|
#define STATUS_X 120 // Centred on this
|
||||||
|
#define STATUS_Y 65
|
||||||
|
|
||||||
|
// Create 15 keys for the keypad
|
||||||
|
char keyLabel[15][5] = {"New", "Del", "Send", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "0", "#" };
|
||||||
|
uint16_t keyColor[15] = {TFT_RED, TFT_DARKGREY, TFT_DARKGREEN,
|
||||||
|
TFT_BLUE, TFT_BLUE, TFT_BLUE,
|
||||||
|
TFT_BLUE, TFT_BLUE, TFT_BLUE,
|
||||||
|
TFT_BLUE, TFT_BLUE, TFT_BLUE,
|
||||||
|
TFT_BLUE, TFT_BLUE, TFT_BLUE
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invoke the TFT_eSPI button class and create all the button objects
|
||||||
|
TFT_eSPI_Button key[15];
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Use serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// Initialise the TFT screen
|
||||||
|
tft.init();
|
||||||
|
|
||||||
|
// Set the rotation before we calibrate
|
||||||
|
tft.setRotation(0);
|
||||||
|
|
||||||
|
// Calibrate the touch screen and retrieve the scaling factors
|
||||||
|
touch_calibrate();
|
||||||
|
|
||||||
|
// Clear the screen
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
|
// Draw keypad background
|
||||||
|
tft.fillRect(0, 0, 240, 320, TFT_DARKGREY);
|
||||||
|
|
||||||
|
// Draw number display area and frame
|
||||||
|
tft.fillRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_BLACK);
|
||||||
|
tft.drawRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_WHITE);
|
||||||
|
|
||||||
|
// Draw keypad
|
||||||
|
drawKeypad();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
|
||||||
|
|
||||||
|
// Pressed will be set true is there is a valid touch on the screen
|
||||||
|
boolean pressed = tft.getTouch(&t_x, &t_y);
|
||||||
|
|
||||||
|
// / Check if any key coordinate boxes contain the touch coordinates
|
||||||
|
for (uint8_t b = 0; b < 15; b++) {
|
||||||
|
if (pressed && key[b].contains(t_x, t_y)) {
|
||||||
|
key[b].press(true); // tell the button it is pressed
|
||||||
|
} else {
|
||||||
|
key[b].press(false); // tell the button it is NOT pressed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any key has changed state
|
||||||
|
for (uint8_t b = 0; b < 15; b++) {
|
||||||
|
|
||||||
|
if (b < 3) tft.setFreeFont(LABEL1_FONT);
|
||||||
|
else tft.setFreeFont(LABEL2_FONT);
|
||||||
|
|
||||||
|
if (key[b].justReleased()) key[b].drawButton(); // draw normal
|
||||||
|
|
||||||
|
if (key[b].justPressed()) {
|
||||||
|
key[b].drawButton(true); // draw invert
|
||||||
|
|
||||||
|
// if a numberpad button, append the relevant # to the numberBuffer
|
||||||
|
if (b >= 3) {
|
||||||
|
if (numberIndex < NUM_LEN) {
|
||||||
|
numberBuffer[numberIndex] = keyLabel[b][0];
|
||||||
|
numberIndex++;
|
||||||
|
numberBuffer[numberIndex] = 0; // zero terminate
|
||||||
|
}
|
||||||
|
status(""); // Clear the old status
|
||||||
|
}
|
||||||
|
|
||||||
|
// Del button, so delete last char
|
||||||
|
if (b == 1) {
|
||||||
|
numberBuffer[numberIndex] = 0;
|
||||||
|
if (numberIndex > 0) {
|
||||||
|
numberIndex--;
|
||||||
|
numberBuffer[numberIndex] = 0;//' ';
|
||||||
|
}
|
||||||
|
status(""); // Clear the old status
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b == 2) {
|
||||||
|
status("Sent value to serial port");
|
||||||
|
Serial.println(numberBuffer);
|
||||||
|
}
|
||||||
|
// we dont really check that the text field makes sense
|
||||||
|
// just try to call
|
||||||
|
if (b == 0) {
|
||||||
|
status("Value cleared");
|
||||||
|
numberIndex = 0; // Reset index to 0
|
||||||
|
numberBuffer[numberIndex] = 0; // Place null in buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the number display field
|
||||||
|
tft.setTextDatum(TL_DATUM); // Use top left corner as text coord datum
|
||||||
|
tft.setFreeFont(&FreeSans18pt7b); // Choose a nicefont that fits box
|
||||||
|
tft.setTextColor(DISP_TCOLOR); // Set the font colour
|
||||||
|
|
||||||
|
// Draw the string, the value returned is the width in pixels
|
||||||
|
int xwidth = tft.drawString(numberBuffer, DISP_X + 4, DISP_Y + 12);
|
||||||
|
|
||||||
|
// Now cover up the rest of the line up by drawing a black rectangle. No flicker this way
|
||||||
|
// but it will not work with italic or oblique fonts due to character overlap.
|
||||||
|
tft.fillRect(DISP_X + 4 + xwidth, DISP_Y + 1, DISP_W - xwidth - 5, DISP_H - 2, TFT_BLACK);
|
||||||
|
|
||||||
|
delay(10); // UI debouncing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void drawKeypad()
|
||||||
|
{
|
||||||
|
// Draw the keys
|
||||||
|
for (uint8_t row = 0; row < 5; row++) {
|
||||||
|
for (uint8_t col = 0; col < 3; col++) {
|
||||||
|
uint8_t b = col + row * 3;
|
||||||
|
|
||||||
|
if (b < 3) tft.setFreeFont(LABEL1_FONT);
|
||||||
|
else tft.setFreeFont(LABEL2_FONT);
|
||||||
|
|
||||||
|
key[b].initButton(&tft, KEY_X + col * (KEY_W + KEY_SPACING_X),
|
||||||
|
KEY_Y + row * (KEY_H + KEY_SPACING_Y), // x, y, w, h, outline, fill, text
|
||||||
|
KEY_W, KEY_H, TFT_WHITE, keyColor[b], TFT_WHITE,
|
||||||
|
keyLabel[b], KEY_TEXTSIZE);
|
||||||
|
key[b].drawButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void touch_calibrate()
|
||||||
|
{
|
||||||
|
uint16_t calData[5];
|
||||||
|
uint8_t calDataOK = 0;
|
||||||
|
|
||||||
|
// check file system exists
|
||||||
|
if (!SPIFFS.begin()) {
|
||||||
|
Serial.println("Formating file system");
|
||||||
|
SPIFFS.format();
|
||||||
|
SPIFFS.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if calibration file exists and size is correct
|
||||||
|
if (SPIFFS.exists(CALIBRATION_FILE)) {
|
||||||
|
if (REPEAT_CAL)
|
||||||
|
{
|
||||||
|
// Delete if we want to re-calibrate
|
||||||
|
SPIFFS.remove(CALIBRATION_FILE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
File f = SPIFFS.open(CALIBRATION_FILE, "r");
|
||||||
|
if (f) {
|
||||||
|
if (f.readBytes((char *)calData, 14) == 14)
|
||||||
|
calDataOK = 1;
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (calDataOK && !REPEAT_CAL) {
|
||||||
|
// calibration data valid
|
||||||
|
tft.setTouch(calData);
|
||||||
|
} else {
|
||||||
|
// data not valid so recalibrate
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
tft.setCursor(20, 0);
|
||||||
|
tft.setTextFont(2);
|
||||||
|
tft.setTextSize(1);
|
||||||
|
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||||
|
|
||||||
|
tft.println("Touch corners as indicated");
|
||||||
|
|
||||||
|
tft.setTextFont(1);
|
||||||
|
tft.println();
|
||||||
|
|
||||||
|
if (REPEAT_CAL) {
|
||||||
|
tft.setTextColor(TFT_RED, TFT_BLACK);
|
||||||
|
tft.println("Set REPEAT_CAL to false to stop this running again!");
|
||||||
|
}
|
||||||
|
|
||||||
|
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
|
||||||
|
|
||||||
|
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||||
|
tft.println("Calibration complete!");
|
||||||
|
|
||||||
|
// store data
|
||||||
|
File f = SPIFFS.open(CALIBRATION_FILE, "w");
|
||||||
|
if (f) {
|
||||||
|
f.write((const unsigned char *)calData, 14);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Print something in the mini status bar
|
||||||
|
void status(const char *msg) {
|
||||||
|
tft.setTextPadding(240);
|
||||||
|
//tft.setCursor(STATUS_X, STATUS_Y);
|
||||||
|
tft.setTextColor(TFT_WHITE, TFT_DARKGREY);
|
||||||
|
tft.setTextFont(0);
|
||||||
|
tft.setTextDatum(TC_DATUM);
|
||||||
|
tft.setTextSize(1);
|
||||||
|
tft.drawString(msg, STATUS_X, STATUS_Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
287
examples/480 x 320/Keypad_480x320/Keypad_480x320.ino
Normal file
287
examples/480 x 320/Keypad_480x320/Keypad_480x320.ino
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
The TFT_eSPI library incorporates an Adafruit_GFX compatible
|
||||||
|
button handling class, this sketch is based on the Arduin-o-phone
|
||||||
|
example.
|
||||||
|
|
||||||
|
This example diplays a keypad where numbers can be entered and
|
||||||
|
send to the Serial Monitor window.
|
||||||
|
|
||||||
|
The sketch has been tested on the ESP8266 (which supports SPIFFS)
|
||||||
|
|
||||||
|
The minimum screen size is 320 x 240 as that is the keypad size.
|
||||||
|
|
||||||
|
TOUCH_CS and SPI_TOUCH_FREQUENCY must be defined in the User_Setup.h file
|
||||||
|
for the touch functions to do anything.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The SPIFFS (FLASH filing system) is used to hold touch screen
|
||||||
|
// calibration data
|
||||||
|
|
||||||
|
#include "FS.h"
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <TFT_eSPI.h> // Hardware-specific library
|
||||||
|
|
||||||
|
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
|
||||||
|
|
||||||
|
// This is the file name used to store the calibration data
|
||||||
|
// You can change this to create new calibration files.
|
||||||
|
// The SPIFFS file name must start with "/".
|
||||||
|
#define CALIBRATION_FILE "/TouchCalData2"
|
||||||
|
|
||||||
|
// Set REPEAT_CAL to true instead of false to run calibration
|
||||||
|
// again, otherwise it will only be done once.
|
||||||
|
// Repeat calibration if you change the screen rotation.
|
||||||
|
#define REPEAT_CAL false
|
||||||
|
|
||||||
|
// Keypad start position, key sizes and spacing
|
||||||
|
#define KEY_X 40 // Centre of key
|
||||||
|
#define KEY_Y 96
|
||||||
|
#define KEY_W 62 // Width and height
|
||||||
|
#define KEY_H 30
|
||||||
|
#define KEY_SPACING_X 18 // X and Y gap
|
||||||
|
#define KEY_SPACING_Y 20
|
||||||
|
#define KEY_TEXTSIZE 1 // Font size multiplier
|
||||||
|
|
||||||
|
// Using two fonts since numbers are nice when bold
|
||||||
|
#define LABEL1_FONT &FreeSansOblique12pt7b // Key label font 1
|
||||||
|
#define LABEL2_FONT &FreeSansBold12pt7b // Key label font 2
|
||||||
|
|
||||||
|
// Numeric display box size and location
|
||||||
|
#define DISP_X 1
|
||||||
|
#define DISP_Y 10
|
||||||
|
#define DISP_W 238
|
||||||
|
#define DISP_H 50
|
||||||
|
#define DISP_TSIZE 3
|
||||||
|
#define DISP_TCOLOR TFT_CYAN
|
||||||
|
|
||||||
|
// Number length, buffer for storing it and character index
|
||||||
|
#define NUM_LEN 12
|
||||||
|
char numberBuffer[NUM_LEN + 1] = "";
|
||||||
|
uint8_t numberIndex = 0;
|
||||||
|
|
||||||
|
// We have a status line for messages
|
||||||
|
#define STATUS_X 120 // Centred on this
|
||||||
|
#define STATUS_Y 65
|
||||||
|
|
||||||
|
// Create 15 keys for the keypad
|
||||||
|
char keyLabel[15][5] = {"New", "Del", "Send", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "0", "#" };
|
||||||
|
uint16_t keyColor[15] = {TFT_RED, TFT_DARKGREY, TFT_DARKGREEN,
|
||||||
|
TFT_BLUE, TFT_BLUE, TFT_BLUE,
|
||||||
|
TFT_BLUE, TFT_BLUE, TFT_BLUE,
|
||||||
|
TFT_BLUE, TFT_BLUE, TFT_BLUE,
|
||||||
|
TFT_BLUE, TFT_BLUE, TFT_BLUE
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invoke the TFT_eSPI button class and create all the button objects
|
||||||
|
TFT_eSPI_Button key[15];
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Use serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// Initialise the TFT screen
|
||||||
|
tft.init();
|
||||||
|
|
||||||
|
// Set the rotation before we calibrate
|
||||||
|
tft.setRotation(1);
|
||||||
|
|
||||||
|
// Calibrate the touch screen and retrieve the scaling factors
|
||||||
|
touch_calibrate();
|
||||||
|
|
||||||
|
// Clear the screen
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
|
// Draw keypad background
|
||||||
|
tft.fillRect(0, 0, 240, 320, TFT_DARKGREY);
|
||||||
|
|
||||||
|
// Draw number display area and frame
|
||||||
|
tft.fillRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_BLACK);
|
||||||
|
tft.drawRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_WHITE);
|
||||||
|
|
||||||
|
// Draw keypad
|
||||||
|
drawKeypad();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
|
||||||
|
|
||||||
|
// Pressed will be set true is there is a valid touch on the screen
|
||||||
|
boolean pressed = tft.getTouch(&t_x, &t_y);
|
||||||
|
|
||||||
|
// / Check if any key coordinate boxes contain the touch coordinates
|
||||||
|
for (uint8_t b = 0; b < 15; b++) {
|
||||||
|
if (pressed && key[b].contains(t_x, t_y)) {
|
||||||
|
key[b].press(true); // tell the button it is pressed
|
||||||
|
} else {
|
||||||
|
key[b].press(false); // tell the button it is NOT pressed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any key has changed state
|
||||||
|
for (uint8_t b = 0; b < 15; b++) {
|
||||||
|
|
||||||
|
if (b < 3) tft.setFreeFont(LABEL1_FONT);
|
||||||
|
else tft.setFreeFont(LABEL2_FONT);
|
||||||
|
|
||||||
|
if (key[b].justReleased()) key[b].drawButton(); // draw normal
|
||||||
|
|
||||||
|
if (key[b].justPressed()) {
|
||||||
|
key[b].drawButton(true); // draw invert
|
||||||
|
|
||||||
|
// if a numberpad button, append the relevant # to the numberBuffer
|
||||||
|
if (b >= 3) {
|
||||||
|
if (numberIndex < NUM_LEN) {
|
||||||
|
numberBuffer[numberIndex] = keyLabel[b][0];
|
||||||
|
numberIndex++;
|
||||||
|
numberBuffer[numberIndex] = 0; // zero terminate
|
||||||
|
}
|
||||||
|
status(""); // Clear the old status
|
||||||
|
}
|
||||||
|
|
||||||
|
// Del button, so delete last char
|
||||||
|
if (b == 1) {
|
||||||
|
numberBuffer[numberIndex] = 0;
|
||||||
|
if (numberIndex > 0) {
|
||||||
|
numberIndex--;
|
||||||
|
numberBuffer[numberIndex] = 0;//' ';
|
||||||
|
}
|
||||||
|
status(""); // Clear the old status
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b == 2) {
|
||||||
|
status("Sent value to serial port");
|
||||||
|
Serial.println(numberBuffer);
|
||||||
|
}
|
||||||
|
// we dont really check that the text field makes sense
|
||||||
|
// just try to call
|
||||||
|
if (b == 0) {
|
||||||
|
status("Value cleared");
|
||||||
|
numberIndex = 0; // Reset index to 0
|
||||||
|
numberBuffer[numberIndex] = 0; // Place null in buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the number display field
|
||||||
|
tft.setTextDatum(TL_DATUM); // Use top left corner as text coord datum
|
||||||
|
tft.setFreeFont(&FreeSans18pt7b); // Choose a nicefont that fits box
|
||||||
|
tft.setTextColor(DISP_TCOLOR); // Set the font colour
|
||||||
|
|
||||||
|
// Draw the string, the value returned is the width in pixels
|
||||||
|
int xwidth = tft.drawString(numberBuffer, DISP_X + 4, DISP_Y + 12);
|
||||||
|
|
||||||
|
// Now cover up the rest of the line up by drawing a black rectangle. No flicker this way
|
||||||
|
// but it will not work with italic or oblique fonts due to character overlap.
|
||||||
|
tft.fillRect(DISP_X + 4 + xwidth, DISP_Y + 1, DISP_W - xwidth - 5, DISP_H - 2, TFT_BLACK);
|
||||||
|
|
||||||
|
delay(10); // UI debouncing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void drawKeypad()
|
||||||
|
{
|
||||||
|
// Draw the keys
|
||||||
|
for (uint8_t row = 0; row < 5; row++) {
|
||||||
|
for (uint8_t col = 0; col < 3; col++) {
|
||||||
|
uint8_t b = col + row * 3;
|
||||||
|
|
||||||
|
if (b < 3) tft.setFreeFont(LABEL1_FONT);
|
||||||
|
else tft.setFreeFont(LABEL2_FONT);
|
||||||
|
|
||||||
|
key[b].initButton(&tft, KEY_X + col * (KEY_W + KEY_SPACING_X),
|
||||||
|
KEY_Y + row * (KEY_H + KEY_SPACING_Y), // x, y, w, h, outline, fill, text
|
||||||
|
KEY_W, KEY_H, TFT_WHITE, keyColor[b], TFT_WHITE,
|
||||||
|
keyLabel[b], KEY_TEXTSIZE);
|
||||||
|
key[b].drawButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void touch_calibrate()
|
||||||
|
{
|
||||||
|
uint16_t calData[5];
|
||||||
|
uint8_t calDataOK = 0;
|
||||||
|
|
||||||
|
// check file system exists
|
||||||
|
if (!SPIFFS.begin()) {
|
||||||
|
Serial.println("Formating file system");
|
||||||
|
SPIFFS.format();
|
||||||
|
SPIFFS.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if calibration file exists and size is correct
|
||||||
|
if (SPIFFS.exists(CALIBRATION_FILE)) {
|
||||||
|
if (REPEAT_CAL)
|
||||||
|
{
|
||||||
|
// Delete if we want to re-calibrate
|
||||||
|
SPIFFS.remove(CALIBRATION_FILE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
File f = SPIFFS.open(CALIBRATION_FILE, "r");
|
||||||
|
if (f) {
|
||||||
|
if (f.readBytes((char *)calData, 14) == 14)
|
||||||
|
calDataOK = 1;
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (calDataOK && !REPEAT_CAL) {
|
||||||
|
// calibration data valid
|
||||||
|
tft.setTouch(calData);
|
||||||
|
} else {
|
||||||
|
// data not valid so recalibrate
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
tft.setCursor(20, 0);
|
||||||
|
tft.setTextFont(2);
|
||||||
|
tft.setTextSize(1);
|
||||||
|
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||||
|
|
||||||
|
tft.println("Touch corners as indicated");
|
||||||
|
|
||||||
|
tft.setTextFont(1);
|
||||||
|
tft.println();
|
||||||
|
|
||||||
|
if (REPEAT_CAL) {
|
||||||
|
tft.setTextColor(TFT_RED, TFT_BLACK);
|
||||||
|
tft.println("Set REPEAT_CAL to false to stop this running again!");
|
||||||
|
}
|
||||||
|
|
||||||
|
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
|
||||||
|
|
||||||
|
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||||
|
tft.println("Calibration complete!");
|
||||||
|
|
||||||
|
// store data
|
||||||
|
File f = SPIFFS.open(CALIBRATION_FILE, "w");
|
||||||
|
if (f) {
|
||||||
|
f.write((const unsigned char *)calData, 14);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Print something in the mini status bar
|
||||||
|
void status(const char *msg) {
|
||||||
|
tft.setTextPadding(240);
|
||||||
|
//tft.setCursor(STATUS_X, STATUS_Y);
|
||||||
|
tft.setTextColor(TFT_WHITE, TFT_DARKGREY);
|
||||||
|
tft.setTextFont(0);
|
||||||
|
tft.setTextDatum(TC_DATUM);
|
||||||
|
tft.setTextSize(1);
|
||||||
|
tft.drawString(msg, STATUS_X, STATUS_Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
206
examples/Generic/On_Off_Button/On_Off_Button.ino
Normal file
206
examples/Generic/On_Off_Button/On_Off_Button.ino
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
// Example of drawing a graphical "switch" and using
|
||||||
|
// the touch screen to change it's state.
|
||||||
|
|
||||||
|
// This sketch does not use the libraries button drawing
|
||||||
|
// and handling functions.
|
||||||
|
|
||||||
|
// Based on Adafruit_GFX library onoffbutton example.
|
||||||
|
|
||||||
|
// Touch handling for XPT2046 based screens is handled by
|
||||||
|
// the TFT_eSPI library.
|
||||||
|
|
||||||
|
// Calibration data is stored in SPIFFS so we need to include it
|
||||||
|
#include "FS.h"
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
#include <TFT_eSPI.h> // Hardware-specific library
|
||||||
|
|
||||||
|
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
|
||||||
|
|
||||||
|
// This is the file name used to store the touch coordinate
|
||||||
|
// calibration data. Cahnge the name to start a new calibration.
|
||||||
|
#define CALIBRATION_FILE "/TouchCalData3"
|
||||||
|
|
||||||
|
// Set REPEAT_CAL to true instead of false to run calibration
|
||||||
|
// again, otherwise it will only be done once.
|
||||||
|
// Repeat calibration if you change the screen rotation.
|
||||||
|
#define REPEAT_CAL false
|
||||||
|
|
||||||
|
boolean SwitchOn = false;
|
||||||
|
|
||||||
|
// Comment out to stop drawing black spots
|
||||||
|
#define BLACK_SPOT
|
||||||
|
|
||||||
|
// Switch position and size
|
||||||
|
#define FRAME_X 100
|
||||||
|
#define FRAME_Y 64
|
||||||
|
#define FRAME_W 120
|
||||||
|
#define FRAME_H 50
|
||||||
|
|
||||||
|
// Red zone size
|
||||||
|
#define REDBUTTON_X FRAME_X
|
||||||
|
#define REDBUTTON_Y FRAME_Y
|
||||||
|
#define REDBUTTON_W (FRAME_W/2)
|
||||||
|
#define REDBUTTON_H FRAME_H
|
||||||
|
|
||||||
|
// Green zone size
|
||||||
|
#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
|
||||||
|
#define GREENBUTTON_Y FRAME_Y
|
||||||
|
#define GREENBUTTON_W (FRAME_W/2)
|
||||||
|
#define GREENBUTTON_H FRAME_H
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
Serial.begin(9600);
|
||||||
|
tft.init();
|
||||||
|
|
||||||
|
// Set the rotation before we calibrate
|
||||||
|
tft.setRotation(1);
|
||||||
|
|
||||||
|
// call screen calibration
|
||||||
|
touch_calibrate();
|
||||||
|
|
||||||
|
// clear screen
|
||||||
|
tft.fillScreen(TFT_BLUE);
|
||||||
|
|
||||||
|
// Draw button (this example does not use library Button class)
|
||||||
|
redBtn();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
uint16_t x, y;
|
||||||
|
|
||||||
|
// See if there's any touch data for us
|
||||||
|
if (tft.getTouch(&x, &y))
|
||||||
|
{
|
||||||
|
// Draw a block spot to show where touch was calculated to be
|
||||||
|
#ifdef BLACK_SPOT
|
||||||
|
tft.fillCircle(x, y, 2, TFT_BLACK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (SwitchOn)
|
||||||
|
{
|
||||||
|
if ((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) {
|
||||||
|
if ((y > REDBUTTON_Y) && (y <= (REDBUTTON_Y + REDBUTTON_H))) {
|
||||||
|
Serial.println("Red btn hit");
|
||||||
|
redBtn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //Record is off (SwitchOn == false)
|
||||||
|
{
|
||||||
|
if ((x > GREENBUTTON_X) && (x < (GREENBUTTON_X + GREENBUTTON_W))) {
|
||||||
|
if ((y > GREENBUTTON_Y) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) {
|
||||||
|
Serial.println("Green btn hit");
|
||||||
|
greenBtn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(SwitchOn);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void touch_calibrate()
|
||||||
|
{
|
||||||
|
uint16_t calData[5];
|
||||||
|
uint8_t calDataOK = 0;
|
||||||
|
|
||||||
|
// check file system exists
|
||||||
|
if (!SPIFFS.begin()) {
|
||||||
|
Serial.println("Formating file system");
|
||||||
|
SPIFFS.format();
|
||||||
|
SPIFFS.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if calibration file exists and size is correct
|
||||||
|
if (SPIFFS.exists(CALIBRATION_FILE)) {
|
||||||
|
if (REPEAT_CAL)
|
||||||
|
{
|
||||||
|
// Delete if we want to re-calibrate
|
||||||
|
SPIFFS.remove(CALIBRATION_FILE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
File f = SPIFFS.open(CALIBRATION_FILE, "r");
|
||||||
|
if (f) {
|
||||||
|
if (f.readBytes((char *)calData, 14) == 14)
|
||||||
|
calDataOK = 1;
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (calDataOK && !REPEAT_CAL) {
|
||||||
|
// calibration data valid
|
||||||
|
tft.setTouch(calData);
|
||||||
|
} else {
|
||||||
|
// data not valid so recalibrate
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
tft.setCursor(20, 0);
|
||||||
|
tft.setTextFont(2);
|
||||||
|
tft.setTextSize(1);
|
||||||
|
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||||
|
|
||||||
|
tft.println("Touch corners as indicated");
|
||||||
|
|
||||||
|
tft.setTextFont(1);
|
||||||
|
tft.println();
|
||||||
|
|
||||||
|
if (REPEAT_CAL) {
|
||||||
|
tft.setTextColor(TFT_RED, TFT_BLACK);
|
||||||
|
tft.println("Set REPEAT_CAL to false to stop this running again!");
|
||||||
|
}
|
||||||
|
|
||||||
|
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
|
||||||
|
|
||||||
|
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||||
|
tft.println("Calibration complete!");
|
||||||
|
|
||||||
|
// store data
|
||||||
|
File f = SPIFFS.open(CALIBRATION_FILE, "w");
|
||||||
|
if (f) {
|
||||||
|
f.write((const unsigned char *)calData, 14);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawFrame()
|
||||||
|
{
|
||||||
|
tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, TFT_BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a red button
|
||||||
|
void redBtn()
|
||||||
|
{
|
||||||
|
tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, TFT_RED);
|
||||||
|
tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, TFT_DARKGREY);
|
||||||
|
drawFrame();
|
||||||
|
tft.setTextColor(TFT_WHITE);
|
||||||
|
tft.setTextSize(2);
|
||||||
|
tft.setTextDatum(MC_DATUM);
|
||||||
|
tft.drawString("ON", GREENBUTTON_X + (GREENBUTTON_W / 2), GREENBUTTON_Y + (GREENBUTTON_H / 2));
|
||||||
|
SwitchOn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a green button
|
||||||
|
void greenBtn()
|
||||||
|
{
|
||||||
|
tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, TFT_GREEN);
|
||||||
|
tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, TFT_DARKGREY);
|
||||||
|
drawFrame();
|
||||||
|
tft.setTextColor(TFT_WHITE);
|
||||||
|
tft.setTextSize(2);
|
||||||
|
tft.setTextDatum(MC_DATUM);
|
||||||
|
tft.drawString("OFF", REDBUTTON_X + (REDBUTTON_W / 2) + 1, REDBUTTON_Y + (REDBUTTON_H / 2));
|
||||||
|
SwitchOn = true;
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user