Last active
July 13, 2024 09:40
-
-
Save maxistar/b79a8485f7d28cf95c2d2f791fb23d5f to your computer and use it in GitHub Desktop.
Keyboard Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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. | |
#define TFT_CS PIN_D8 // Chip select control pin D8 | |
#define TFT_DC PIN_D3 // Data Command control pin | |
#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next l> | |
#define TFT_CS D5 // Chip select control pin to TFT CS | |
#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select) | |
#define TFT_RST D7 // Reset pin to TFT RST (or RESET) | |
#define TOUCH_CS D4 | |
#define SPI_FREQUENCY 27000000 // 27MHz SPI clock | |
#define SPI_READ_FREQUENCY 15000000 // Reads need a slower SPI clock, probably ends up at 13.75MHz (CPU clock/16) | |
#define SPI_TOUCH_FREQUENCY 2500000 // Must be very slow | |
*/ | |
// 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 true | |
// 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 | |
bool 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); | |
} | |
//------------------------------------------------------------------------------------------ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment