Files

210 lines
5.9 KiB
Arduino

/*
This example demonstrates how to automatically apply the correct touch
calibration data for all four display rotations using the TFT_eSPI library.
The sketch shows how to:
- Store four sets of touch calibration data (one for each rotation)
- Automatically load the correct calibration when tft.setRotation() changes
- Keep touch alignment consistent with the display orientation
The display rotates automatically every 10 seconds (0→1→2→3).
Touch input is immediately available in the new orientation.
Calibration data is stored in SPIFFS for persistence across power cycles.
This example is based on the TFT_Button_Label_Datum example and works with
ESP32 modules using the XPT2046 touch controller.
Tested on:
- ESP32-32E with ST7796 display (HSPI)
- XPT2046 touch controller
*/
#include "FS.h"
#include <SPI.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
TFT_eSPI_Button key;
// 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 "/TouchCalData"
// 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
// Touch calibration data for each of the 4 rotations
// Obtain these values using the Touch_calibrate example
uint16_t calData0[5] = { 219, 3560, 230, 3662, 4 }; // rotation 0
uint16_t calData1[5] = { 206, 3677, 204, 3544, 7 }; // rotation 1
uint16_t calData2[5] = { 215, 3566, 229, 3674, 2 }; // rotation 2
uint16_t calData3[5] = { 239, 3651, 218, 3553, 1 }; // rotation 3
// Pointer table for easy access to calibration data sets
uint16_t* calDataSets[4] = { calData0, calData1, calData2, calData3 };
uint8_t currentRotation = 1; // Start in landscape mode
bool touchscreen_calibrated = false;
//---------------------------------------------------------------------------
void setup(void)
{
Serial.begin(115200);
tft.init();
// Set the rotation before we calibrate
tft.setRotation(currentRotation);
// call screen calibration
touch_calibrate();
// Display initial UI
drawUI();
Serial.println("\nAutoTouchRotation Example - TFT_eSPI");
Serial.println("Display rotates every 10 seconds");
Serial.printf("Current rotation: %d\n", currentRotation);
}
//---------------------------------------------------------------------------
void loop()
{
static unsigned long lastChange = 0;
uint16_t t_x = 0, t_y = 0;
bool pressed = false;
// Check for touch input
if (touchscreen_calibrated && tft.getTouch(&t_x, &t_y)) {
pressed = true;
}
// Handle button press/release
if (pressed && key.contains(t_x, t_y)) {
key.press(true);
} else {
key.press(false);
}
// Handle button just pressed
if (key.justPressed()) {
key.drawButton(true);
tft.fillRect(10, 30, 200, 20, TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.drawString("Button Pressed!", 10, 30);
Serial.printf("Pressed @ rotation %d\n", currentRotation);
}
// Handle button just released
if (key.justReleased()) {
key.drawButton();
}
// Demo: change rotation every 10 seconds
if (millis() - lastChange > 10000) {
currentRotation = (currentRotation + 1) % 4;
setRotationAndTouch(currentRotation);
drawUI();
lastChange = millis();
}
delay(20);
}
//---------------------------------------------------------------------------
// Set display rotation and apply matching touch calibration data
//---------------------------------------------------------------------------
void setRotationAndTouch(uint8_t rot)
{
if (rot > 3) rot = 0;
tft.setRotation(rot);
tft.setTouch(calDataSets[rot]);
touchscreen_calibrated = true;
Serial.printf("Rotation: %d, Touch cal data: { %d, %d, %d, %d, %d }\n",
rot,
calDataSets[rot][0], calDataSets[rot][1],
calDataSets[rot][2], calDataSets[rot][3],
calDataSets[rot][4]);
}
//---------------------------------------------------------------------------
// Redraw user interface elements
//---------------------------------------------------------------------------
void drawUI(void)
{
tft.fillScreen(TFT_BLACK);
key.initButtonUL(&tft, 60, 100, 120, 60, TFT_WHITE, TFT_BLUE, TFT_WHITE, "PRESS", 2);
key.drawButton();
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.drawString("Rotation: " + String(currentRotation), 10, 10);
}
//---------------------------------------------------------------------------
// Touch screen calibration routine
//---------------------------------------------------------------------------
void touch_calibrate(void)
{
uint16_t calData[5];
uint8_t calDataOK = 0;
// Calibration data is stored in SPIFFS
if (SPIFFS.begin()) {
if (SPIFFS.exists(CALIBRATION_FILE)) {
File f = SPIFFS.open(CALIBRATION_FILE, "r");
if (f) {
if (f.readBytes((char *)calData, 14) == 14)
calDataOK = 1;
f.close();
}
}
}
if (!calDataOK) {
// data not valid so run calibration again
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.println("Set REPEAT_CAL to false to skip this next time");
}
// conduct calibration
delay(2000);
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
// (Re)set the calibration data
tft.setTouch(calData);
// Store calibration data
if (SPIFFS.begin()) {
File f = SPIFFS.open(CALIBRATION_FILE, "w");
if (f) {
f.write((const unsigned char *)calData, 14);
f.close();
}
SPIFFS.end();
}
} else {
// Use stored calibration data
tft.setTouch(calData);
}
touchscreen_calibrated = true;
}