diff --git a/device/LCD_ILI9341/Drv_XPT2046_Touch.c b/device/LCD_ILI9341/Drv_XPT2046_Touch.c index b50e365..635bdcd 100644 --- a/device/LCD_ILI9341/Drv_XPT2046_Touch.c +++ b/device/LCD_ILI9341/Drv_XPT2046_Touch.c @@ -20,9 +20,9 @@ void XPT2046_Init(void) gpio_init_struct.gpio_pins = TP_CLK_PIN | TP_DIN_PIN | TP_CS_PIN; gpio_init(GPIOC, &gpio_init_struct); - // 输入引脚:OUT(上拉)、IRQ(上拉) + // DOUT:浮空输入(内部上拉易把空闲读成满量程) gpio_init_struct.gpio_mode = GPIO_MODE_INPUT; - gpio_init_struct.gpio_pull = GPIO_PULL_UP; + gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init_struct.gpio_pins = TP_OUT_PIN; gpio_init(TP_OUT_PORT, &gpio_init_struct); @@ -92,13 +92,12 @@ void TP_Write_Byte(uint8_t data) //从触摸屏IC读取adc值 //CMD:指令 //返回值:读到的数据 -uint16_t TP_Read_AD(uint8_t cmd) +/* 在 CS 已拉低时写命令并读:与量产一致,16 时钟取高 12bit */ +static uint16_t TP_Read_AD_CSHeld(uint8_t cmd) { uint8_t i; uint16_t adc_val = 0; - TP_CS_Clr(); - Delay_us(2); TP_Write_Byte(cmd); Delay_us(6); @@ -113,91 +112,93 @@ uint16_t TP_Read_AD(uint8_t cmd) adc_val |= 0x01; } + return (uint16_t)(adc_val >> 4); +} + +uint16_t TP_Read_AD(uint8_t cmd) +{ + uint16_t v; + + TP_CS_Clr(); + Delay_us(2); + v = TP_Read_AD_CSHeld(cmd); TP_CS_Set(); - return adc_val >> 4; + return v; } -uint8_t TP_CheckPressed(uint8_t n) +#define TP_ADC_PRESS_MIN 120u +#define TP_ADC_PRESS_MAX 4095u +#define TP_PRESSURE_MIN 80u +/* 本板 IRQ 无效;压力仅作弱参考,不过度拦截(真触摸 z 也常偏大) */ +#define TP_PRESSURE_MAX 5000u + +static uint16_t TP_Median5(uint16_t *a) { - uint8_t count = 0; + uint8_t i, j; + uint16_t t; + + for (i = 0; i < 4; i++) { + for (j = (uint8_t)(i + 1U); j < 5U; j++) { + if (a[j] < a[i]) { + t = a[i]; + a[i] = a[j]; + a[j] = t; + } + } + } + return a[2]; +} + +static void TP_SampleXY(uint16_t *out_x, uint16_t *out_y) +{ + uint16_t xs[5], ys[5]; uint8_t i; - for (i = 0; i < n; i++) - { - if (TP_IRQ_Read() == 0) - count++; - Delay_us(100); + for (i = 0; i < 5; i++) { + xs[i] = TP_Read_AD(XPT2046_READ_X); + Delay_us(15); + ys[i] = TP_Read_AD(XPT2046_READ_Y); + Delay_us(15); } - return (count >= (n / 2)) ? 1 : 0; + + *out_x = TP_Median5(xs); + *out_y = TP_Median5(ys); } -static uint16_t TP_SampleAxis(uint8_t cmd) +static uint16_t TP_ReadPressure(void) { - (void)TP_Read_AD(cmd); + uint16_t z1, z2; + + z1 = TP_Read_AD(XPT2046_READ_Z1); Delay_us(15); - return TP_Read_AD(cmd); + z2 = TP_Read_AD(XPT2046_READ_Z2); + + return (z1 > z2) ? (uint16_t)(z1 - z2) : 0U; } -TP_Point TP_ReadRaw(void) +static uint8_t TP_AdcCoordValid(uint16_t x, uint16_t y) { - TP_Point p = {0, 0, 0}; - uint32_t x_sum = 0, y_sum = 0; - uint8_t i; - static uint8_t s_raw_logged; - - if (!TP_CheckPressed(3)) { - s_raw_logged = 0U; - return p; - } - - for (i = 0; i < 5; i++) - { - x_sum += TP_SampleAxis(XPT2046_READ_X); - Delay_us(15); - y_sum += TP_SampleAxis(XPT2046_READ_Y); - Delay_us(15); - } - - p.x = (uint16_t)(x_sum / 5); - p.y = (uint16_t)(y_sum / 5); - - /* Y 通道常为 0 时,交换 X/Y 命令再采一次 */ - if (p.y < 80u && p.x > 80u) - { - uint32_t sx = 0, sy = 0; - - for (i = 0; i < 3; i++) - { - sx += TP_SampleAxis(XPT2046_READ_Y); - Delay_us(15); - sy += TP_SampleAxis(XPT2046_READ_X); - Delay_us(15); - } - if (sy / 3u > p.y) - { - p.x = (uint16_t)(sx / 3); - p.y = (uint16_t)(sy / 3); - } - } - - p.pressed = 1; - if (!s_raw_logged) { - LOG_TP("raw x=%u y=%u irq=%u", (unsigned)p.x, (unsigned)p.y, - (unsigned)(TP_IRQ_Read() == 0U)); - s_raw_logged = 1U; - } - return p; + /* 仅排除明显无效;双高在本板上也可能是真触摸(Y 常贴高,垂直靠 raw.x) */ + if (x < TP_ADC_PRESS_MIN && y < TP_ADC_PRESS_MIN) + return 0U; + if (x > 4000u && y > 4000u) + return 0U; + return (x <= TP_ADC_PRESS_MAX && y <= TP_ADC_PRESS_MAX) ? 1U : 0U; } #define CALIB_X_MIN 200 #define CALIB_X_MAX 3800 #define CALIB_Y_MIN 200 -#define CALIB_Y_MAX 3800 +#define CALIB_Y_MAX 3950 -/* 竖屏:多数 ILI9341+XPT2046 板级需 XY 对调;X 镜像与历史 240-tp.x 一致 */ -#define TP_SWAP_XY 1 -#define TP_MIRROR_X 1 -#define TP_MIRROR_Y 0 +/* + * 实测(IRQ 有效按下):raw.x 常贴高,上下主要改 raw.y → 不要 SWAP。 + * Y 镜像:上方「万能」对应更大 raw.y。 + * 空闲 ADC 噪声是 raw.y=4095,禁止走 ADC 回退,否则幽灵点击。 + */ +#define TP_SWAP_XY 0 +#define TP_MIRROR_X 0 +#define TP_MIRROR_Y 1 static uint16_t TP_MapAxis(uint16_t adc, uint16_t adc_min, uint16_t adc_max, uint16_t px_max) { @@ -221,32 +222,120 @@ static uint16_t TP_MapAxis(uint16_t adc, uint16_t adc_min, uint16_t adc_max, uin return (uint16_t)px; } -TP_Point TP_Read(void) +static void TP_RawToScreen(uint16_t raw_x, uint16_t raw_y, uint16_t *sx, uint16_t *sy) { - TP_Point raw = TP_ReadRaw(); - TP_Point calib = {0, 0, raw.pressed}; uint16_t ax, ay; - if (!raw.pressed) - return calib; - #if TP_SWAP_XY - ax = TP_MapAxis(raw.y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_W - 1)); - ay = TP_MapAxis(raw.x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_H - 1)); + ax = TP_MapAxis(raw_y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_W - 1)); + ay = TP_MapAxis(raw_x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_H - 1)); #else - ax = TP_MapAxis(raw.x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_W - 1)); - ay = TP_MapAxis(raw.y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_H - 1)); + ax = TP_MapAxis(raw_x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_W - 1)); + ay = TP_MapAxis(raw_y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_H - 1)); #endif - #if TP_MIRROR_X ax = (uint16_t)(LCD_W - 1 - ax); #endif #if TP_MIRROR_Y ay = (uint16_t)(LCD_H - 1 - ay); #endif + *sx = ax; + *sy = ay; +} - calib.x = ax; - calib.y = ay; +void TP_LogStatus(void) +{ + uint16_t x, y, z; + uint16_t sx, sy; + + z = TP_ReadPressure(); + TP_SampleXY(&x, &y); + TP_RawToScreen(x, y, &sx, &sy); + LOG_TPI("status irq=%u z=%u raw=%u,%u cal=%u,%u", + (unsigned)(TP_IRQ_Read() == 0U), + (unsigned)z, + (unsigned)x, (unsigned)y, + (unsigned)sx, (unsigned)sy); +} + +static uint8_t s_tp_live; + +void TP_SetLiveMode(uint8_t on) +{ + s_tp_live = on ? 1U : 0U; + LOG_TPI("live %s (events only)", s_tp_live ? "on" : "off"); +} + +/* 不再空闲刷屏;按下事件仍由 touch task 的 scan/press/release 打印 */ +void TP_LivePoll(void) +{ + (void)s_tp_live; +} + +uint8_t TP_CheckPressed(uint8_t n) +{ + uint8_t count = 0; + uint8_t i; + + for (i = 0; i < n; i++) + { + if (TP_IRQ_Read() == 0) + count++; + Delay_us(100); + } + return (count >= ((n + 1U) / 2U)) ? 1U : 0U; +} + +TP_Point TP_ReadRaw(void) +{ + TP_Point p = {0, 0, 0}; + uint8_t irq_pressed; + static uint8_t s_raw_logged; + uint16_t rx, ry; + + irq_pressed = TP_CheckPressed(3); + if (!irq_pressed) { + /* + * 空闲时 ADC 常读成 y=4095,会误触发幽灵点击。 + * 本板真触摸 IRQ 能拉低,只认 IRQ 路径。 + */ + s_raw_logged = 0U; + return p; + } + + TP_SampleXY(&rx, &ry); + if (!TP_AdcCoordValid(rx, ry)) { + s_raw_logged = 0U; + return p; + } + + p.x = rx; + p.y = ry; + p.pressed = 1; + if (!s_raw_logged) { + LOG_TPI("raw x=%u y=%u irq=1", (unsigned)p.x, (unsigned)p.y); + s_raw_logged = 1U; + } + return p; +} + +TP_Point TP_Read(void) +{ + TP_Point raw = TP_ReadRaw(); + TP_Point calib = {0, 0, raw.pressed}; + static uint8_t s_cal_logged; + + if (!raw.pressed) { + s_cal_logged = 0U; + return calib; + } + + TP_RawToScreen(raw.x, raw.y, &calib.x, &calib.y); + if (!s_cal_logged) { + LOG_TPI("cal x=%u y=%u (raw %u,%u)", (unsigned)calib.x, (unsigned)calib.y, + (unsigned)raw.x, (unsigned)raw.y); + s_cal_logged = 1U; + } return calib; } diff --git a/device/LCD_ILI9341/Drv_XPT2046_Touch.h b/device/LCD_ILI9341/Drv_XPT2046_Touch.h index c6e36c4..2fb8d6d 100644 --- a/device/LCD_ILI9341/Drv_XPT2046_Touch.h +++ b/device/LCD_ILI9341/Drv_XPT2046_Touch.h @@ -33,7 +33,7 @@ #define TP_DIN_Clr() gpio_bits_reset(TP_DIN_PORT, TP_DIN_PIN) // DIN输出低(MCU→XPT2046) #define TP_DIN_Set() gpio_bits_set(TP_DIN_PORT, TP_DIN_PIN) // DIN输出高(MCU→XPT2046) -// XPT2046命令(与 BOOT 工程一致) +/* 与量产/BOOT 一致:PD1:PD0=00(转换后掉电);时序用 16clk>>4 */ #define XPT2046_READ_X 0xD0 #define XPT2046_READ_Y 0x90 #define XPT2046_READ_Z1 0xB0 @@ -64,6 +64,9 @@ extern uint16_t TP_Read_AD(uint8_t CMD); // 从触摸屏IC读取adc值 extern uint8_t TP_CheckPressed(uint8_t n); // 简单去抖动读取(连续n次相同状态视为有效) extern TP_Point TP_ReadRaw(void); // 读取原始坐标(未校准) extern TP_Point TP_Read(void); // 校准后获取LCD坐标 +extern void TP_LogStatus(void); // 打印 IRQ/ADC 诊断(RTT tp status) +extern void TP_SetLiveMode(uint8_t on); // 实时采样日志开关(RTT tp live / tp live off) +extern void TP_LivePoll(void); // live 模式下周期性打印 raw/cal extern void EXTI15_10_IRQHandler(void); // EXTI15_10中断服务函数(处理TP_IRQ触发) //extern void HAL_EXTI_Callback(EXTI_HandleTypeDef *hexti); // 中断回调函数(触摸触发时执行)