feat(touch): implementar doble clic para cambiar pantalla, clic simple para pantalla completa y clic largo para configuracion con inmunidad a toques fantasma

This commit is contained in:
Sebastián Nieto 2026-09-21 23:46:22 -03:00
parent 26b0cd2ab3
commit 9e7b749404
3 changed files with 77 additions and 89 deletions

View file

@ -22,8 +22,8 @@
#include "XPT2046_TouchscreenSOFTSPI.h" #include "XPT2046_TouchscreenSOFTSPI.h"
#define Z_THRESHOLD 65 #define Z_THRESHOLD 180
#define Z_THRESHOLD_INT 50 #define Z_THRESHOLD_INT 100
#define MSEC_THRESHOLD 3 #define MSEC_THRESHOLD 3
#define SPI_SETTING SPISettings(2000000, MSBFIRST, SPI_MODE0) #define SPI_SETTING SPISettings(2000000, MSBFIRST, SPI_MODE0)

View file

@ -573,9 +573,10 @@ void loop() {
} }
// SCAN TOUCHSCREEN & BUTTON // SCAN TOUCHSCREEN & BUTTON
// - Single tap on a quadrant in 4-quadrant view: switches to full screen for that quadrant // - Double click: switch screen page (Page 0 <-> Page 1) with slide animation
// - Single tap anywhere in full screen view: returns to 4-quadrant view // - Single click: toggle fullscreen for tapped quadrant (or refresh sensors on Tri-Temp)
// - Long press (> 1s) on screen OR holding selector button: opens configuration menu // - Long press (> 1s): open configuration menu
// - Physical selector button: open configuration menu
uint16_t touchX = 0, touchY = 0; uint16_t touchX = 0, touchY = 0;
bool isTouched = getTouch(&touchX, &touchY); bool isTouched = getTouch(&touchX, &touchY);
bool btnPressed = (digitalRead(SELECTOR_PIN) == LOW); bool btnPressed = (digitalRead(SELECTOR_PIN) == LOW);
@ -590,9 +591,15 @@ void loop() {
static uint16_t lastTouchX = 0, lastTouchY = 0; static uint16_t lastTouchX = 0, lastTouchY = 0;
static bool longPressHandled = false; static bool longPressHandled = false;
// Double-tap state machine
static bool waitingForDoubleTap = false;
static uint32_t firstTapReleaseTime = 0;
static uint16_t firstTapX = 0, firstTapY = 0;
if (btnPressed) { if (btnPressed) {
delay(50); delay(50);
if (digitalRead(SELECTOR_PIN) == LOW) { if (digitalRead(SELECTOR_PIN) == LOW) {
waitingForDoubleTap = false;
touchBeep(); touchBeep();
configMenu(); configMenu();
waitForTouchRelease(); waitForTouchRelease();
@ -608,113 +615,94 @@ void loop() {
lastTouchX = touchX; lastTouchX = touchX;
lastTouchY = touchY; lastTouchY = touchY;
longPressHandled = false; longPressHandled = false;
touchBeep(); // Crisp acoustic feedback on touch screen press!
} else { } else {
// Keep tracking coordinates while held to ensure stable swipe/quadrant detection
lastTouchX = touchX; lastTouchX = touchX;
lastTouchY = touchY; lastTouchY = touchY;
int16_t liveDeltaX = (int16_t)lastTouchX - (int16_t)touchStartX; // Long press check: finger held stationary for > 1000ms
int16_t liveDeltaY = (int16_t)lastTouchY - (int16_t)touchStartY; int16_t currentDistX = abs((int16_t)lastTouchX - (int16_t)touchStartX);
int16_t currentDistY = abs((int16_t)lastTouchY - (int16_t)touchStartY);
// FAST LIVE SWIPE DETECTION: if (!longPressHandled && (millis() - touchStartTime > 1000) && currentDistX < 35 && currentDistY < 35) {
// Trigger immediately as soon as finger moves >= 28px horizontally (no need to lift or press hard) longPressHandled = true;
if (!longPressHandled) { waitingForDoubleTap = false;
if (liveDeltaX < -28 && abs(liveDeltaY) < 85) { touchBeep(); // Confirmation chirp
// SWIPE LEFT: Page 0 -> Page 1 (Tri-Temperature Screen) configMenu();
longPressHandled = true; waitForTouchRelease();
if (fullScreenCell != -1) { lastActivityTime = millis();
fullScreenCell = -1; initScreen();
} isTouching = false;
if (currentScreenPage == 0) {
animateSlideTransition(true);
currentScreenPage = 1;
initScreen();
}
waitForTouchRelease();
isTouching = false;
lastActivityTime = millis();
} else if (liveDeltaX > 28 && abs(liveDeltaY) < 85) {
// SWIPE RIGHT: Page 1 -> Page 0 (4 Quadrants)
longPressHandled = true;
if (fullScreenCell != -1) {
fullScreenCell = -1;
}
if (currentScreenPage == 1) {
animateSlideTransition(false);
currentScreenPage = 0;
initScreen();
}
waitForTouchRelease();
isTouching = false;
lastActivityTime = millis();
} else if ((millis() - touchStartTime > 1000) && abs(liveDeltaX) < 20 && abs(liveDeltaY) < 20) {
// Long press (> 1s) held stationary: Open Config Menu immediately!
longPressHandled = true;
touchBeep(); // Confirmation chirp
configMenu();
waitForTouchRelease();
lastActivityTime = millis();
initScreen();
isTouching = false;
}
} }
} }
} else { } else {
// Touch / button released // Touch released
if (isTouching) { if (isTouching) {
isTouching = false; isTouching = false;
uint32_t pressDuration = millis() - touchStartTime;
if (!longPressHandled) { if (!longPressHandled) {
int16_t deltaX = (int16_t)lastTouchX - (int16_t)touchStartX; int16_t deltaX = abs((int16_t)lastTouchX - (int16_t)touchStartX);
int16_t deltaY = (int16_t)lastTouchY - (int16_t)touchStartY; int16_t deltaY = abs((int16_t)lastTouchY - (int16_t)touchStartY);
// Quick flick swipe fallback in case finger was lifted very rapidly // Anti-noise: require at least 30ms of contact and displacement < 40px (clean tap)
if (deltaX < -25 && abs(deltaY) < 85) { if (pressDuration >= 30 && deltaX < 40 && deltaY < 40) {
// SWIPE LEFT: Page 0 -> Page 1 (Tri-Temperature Screen) touchBeep(); // Crisp acoustic feedback on confirmed tap!
if (fullScreenCell != -1) {
fullScreenCell = -1; if (waitingForDoubleTap && (millis() - firstTapReleaseTime <= 400)) {
} // DOUBLE CLICK DETECTED: Switch Screen Page!
if (currentScreenPage == 0) { waitingForDoubleTap = false;
animateSlideTransition(true);
currentScreenPage = 1; if (fullScreenCell != -1) {
initScreen();
}
} else if (deltaX > 25 && abs(deltaY) < 85) {
// SWIPE RIGHT: Page 1 -> Page 0 (4 Quadrants)
if (fullScreenCell != -1) {
fullScreenCell = -1;
}
if (currentScreenPage == 1) {
animateSlideTransition(false);
currentScreenPage = 0;
initScreen();
}
} else {
// Valid TAP detected!
if (currentScreenPage == 0) {
if (fullScreenCell == -1) {
// Switch to full screen for tapped quadrant
int quad = (lastTouchX < 160) ? ((lastTouchY < 120) ? 0 : 2) : ((lastTouchY < 120) ? 1 : 3);
fullScreenCell = quad;
} else {
// Return to 4 quadrants view
fullScreenCell = -1; fullScreenCell = -1;
} }
initScreen();
if (currentScreenPage == 0) {
animateSlideTransition(true);
currentScreenPage = 1;
initScreen();
} else {
animateSlideTransition(false);
currentScreenPage = 0;
initScreen();
}
waitForTouchRelease();
lastActivityTime = millis();
} else { } else {
// Tap on Tri-Temp screen: immediate sensor refresh // First tap of a potential double click: start waiting window
updateTriTempSensors(true); waitingForDoubleTap = true;
firstTapReleaseTime = millis();
firstTapX = lastTouchX;
firstTapY = lastTouchY;
} }
} }
waitForTouchRelease(); // Clear mechanical bounce on release
} }
} }
// Check if double-tap timeout has expired -> execute SINGLE CLICK action!
if (waitingForDoubleTap && (millis() - firstTapReleaseTime > 400)) {
waitingForDoubleTap = false;
if (currentScreenPage == 0) {
if (fullScreenCell == -1) {
// Switch to full screen for tapped quadrant
int quad = (firstTapX < 160) ? ((firstTapY < 120) ? 0 : 2) : ((firstTapY < 120) ? 1 : 3);
fullScreenCell = quad;
} else {
// Return to 4 quadrants view
fullScreenCell = -1;
}
initScreen();
} else {
// Tap on Tri-Temp screen: immediate sensor refresh
updateTriTempSensors(true);
}
lastActivityTime = millis();
}
} }
// AUTO-SLEEP BY INACTIVITY // AUTO-SLEEP BY INACTIVITY
// If auto-sleep is enabled, and screen is not being held, and engine is stopped (RPM <= 300) // If auto-sleep is enabled, and screen is not being held, and engine is stopped (RPM <= 300)
if (autoSleepIndex > 0 && !isTouching && !btnPressed && !longPressHandled && currentRpm <= 300.0f) { if (autoSleepIndex > 0 && !isTouching && !btnPressed && !longPressHandled && !waitingForDoubleTap && currentRpm <= 300.0f) {
uint32_t timeoutMs = (uint32_t)AUTO_SLEEP_SEC_TABLE[autoSleepIndex] * 1000UL; uint32_t timeoutMs = (uint32_t)AUTO_SLEEP_SEC_TABLE[autoSleepIndex] * 1000UL;
if (millis() - lastActivityTime >= timeoutMs) { if (millis() - lastActivityTime >= timeoutMs) {
enterLightSleep(); enterLightSleep();

View file

@ -24,7 +24,7 @@ bool getTouch(uint16_t *x, uint16_t *y) {
TS_Point p = ts.getPoint(tsSoftSpi); TS_Point p = ts.getPoint(tsSoftSpi);
// Filter noise: require valid touch pressure and coordinates within active screen // Filter noise: require valid touch pressure and coordinates within active screen
if (p.z < 60) return false; if (p.z < 160) return false;
if (p.x < 150 || p.x > 3850 || p.y < 150 || p.y > 3850) return false; if (p.x < 150 || p.x > 3850 || p.y < 150 || p.y > 3850) return false;
int16_t tx = map(p.x, 200, 3700, 0, 320); int16_t tx = map(p.x, 200, 3700, 0, 320);