#include "touch.h" #include "pins.h" #include /** * SoftSPI XPT2046 * BL↔TR 是矩形主对角线镜像(XY 对调),不是 180°(180° 会搞成 TL↔BR)。 * 先按 rot2 得到旧 UI,再做对角修正,反变换喂给 LVGL 270。 */ int16_t g_dbg_phys_x = -1; int16_t g_dbg_phys_y = -1; int16_t g_dbg_logic_x = -1; int16_t g_dbg_logic_y = -1; bool g_dbg_touch_down = false; static void soft_write(uint8_t data) { for (int i = 7; i >= 0; --i) { digitalWrite(CYD_TOUCH_MOSI, (data >> i) & 1); digitalWrite(CYD_TOUCH_CLK, HIGH); delayMicroseconds(2); digitalWrite(CYD_TOUCH_CLK, LOW); delayMicroseconds(2); } } static uint16_t soft_read12() { uint16_t v = 0; digitalWrite(CYD_TOUCH_CLK, HIGH); delayMicroseconds(2); digitalWrite(CYD_TOUCH_CLK, LOW); delayMicroseconds(2); for (int i = 0; i < 12; ++i) { digitalWrite(CYD_TOUCH_CLK, HIGH); delayMicroseconds(2); v = (uint16_t)((v << 1) | (digitalRead(CYD_TOUCH_MISO) ? 1u : 0u)); digitalWrite(CYD_TOUCH_CLK, LOW); delayMicroseconds(2); } return v; } static uint16_t xpt_read(uint8_t cmd) { digitalWrite(CYD_TOUCH_CS, LOW); soft_write(cmd); uint16_t v = soft_read12(); digitalWrite(CYD_TOUCH_CS, HIGH); return v; } static int16_t clampi(int32_t v, int32_t lo, int32_t hi) { if (v < lo) { return (int16_t)lo; } if (v > hi) { return (int16_t)hi; } return (int16_t)v; } void touch_init() { pinMode(CYD_TOUCH_CS, OUTPUT); pinMode(CYD_TOUCH_CLK, OUTPUT); pinMode(CYD_TOUCH_MOSI, OUTPUT); pinMode(CYD_TOUCH_MISO, INPUT); pinMode(CYD_TOUCH_IRQ, INPUT); digitalWrite(CYD_TOUCH_CS, HIGH); digitalWrite(CYD_TOUCH_CLK, LOW); Serial.println("Touch: SoftSPI + diagonal fix (BL/TR)"); } void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) { uint16_t adc_x = xpt_read(0x90); uint16_t adc_y = xpt_read(0xD0); adc_x = (uint16_t)((adc_x + xpt_read(0x90)) / 2); adc_y = (uint16_t)((adc_y + xpt_read(0xD0)) / 2); const bool irq = (digitalRead(CYD_TOUCH_IRQ) == LOW); const bool in_range = (adc_x > 80 && adc_x < 4000 && adc_y > 80 && adc_y < 4000); if (!in_range || (!irq && (adc_x < 200 || adc_y < 200))) { data->state = LV_INDEV_STATE_RELEASED; g_dbg_touch_down = false; return; } const int16_t p_x = (int16_t)adc_x; const int16_t p_y = (int16_t)(4095 - adc_y); int16_t x = map(p_x, 200, 3700, 1, SCREEN_WIDTH); int16_t y = map(p_y, 240, 3800, 1, SCREEN_HEIGHT); x = clampi(x, 0, SCREEN_WIDTH - 1); y = clampi(y, 0, SCREEN_HEIGHT - 1); // 旧 UI(LVGL270):(y, 239-x) — 该空间里 BL↔TR,做主对角线镜像 // (ux,uy) -> (uy*(319/239), ux*(239/319)) const int32_t old_ux = y; const int32_t old_uy = (SCREEN_WIDTH - 1) - x; int16_t ui_x = clampi((old_uy * (UI_HOR_RES - 1)) / (UI_VER_RES - 1), 0, UI_HOR_RES - 1); int16_t ui_y = clampi((old_ux * (UI_VER_RES - 1)) / (UI_HOR_RES - 1), 0, UI_VER_RES - 1); // 反变换喂 LVGL,使最终落在 (ui_x, ui_y) const int16_t feed_x = (int16_t)((SCREEN_WIDTH - 1) - ui_y); const int16_t feed_y = ui_x; g_dbg_phys_x = x; g_dbg_phys_y = y; g_dbg_logic_x = ui_x; g_dbg_logic_y = ui_y; g_dbg_touch_down = true; static uint32_t last_log = 0; if (millis() - last_log > 80) { last_log = millis(); Serial.printf("Touch UI(%d,%d)\n", ui_x, ui_y); } data->point.x = feed_x; data->point.y = feed_y; data->state = LV_INDEV_STATE_PRESSED; }