1、简介
XPT2046是一款四线制电阻触摸屏控制芯片,由深圳市矽普特科技有限公司研发生产,内含12位分辨率125KHz转换速率逐步逼近型A/D转换器。XPT2046 支持从1.5V到5.25V的低电压I/O接口。XPT2046能通过执行两次A/D转换查出被按的屏幕位置, 除此之外,还可以测量加在触摸屏上的压力。内部自带2.5V参考电压,可以作为辅助输入、温度测量和电池监测之用, 在2.7V的典型工作状态下,关闭参考电压,功耗可小于0.75mW。其内部框图如下:
左边红框为触控点输入,右边红框为外部SPI通信接口,至少与外部MCU连接CS、CLK、DIN、DOUT这四个通信引脚,使用IRQ中断则MCU需要再提供一个输入引脚。
2、xpt2046触控屏驱动
这里直接使用厂商提供的xpt2046,只需要完成xpt2046触控屏的接线和通信API设置就可以实现触控输入检测。主控MCU为STM32F429,使用CubeMX工具配置SPI硬件外设。SPI4外设通信方式为主机全双工,从机为xpt2046,NSS使用软件片选CS
中断IRQ引脚设为外部下降沿中断、默认上拉
3、程序设计
XPT2046_touch.h
/* * XPT2046_touch.h */ #ifndef XPT2046_TOUCH_H #define XPT2046_TOUCH_H #include "main.h" #include <stdbool.h> /*** Redefine if necessary ***/ //#define SOFTWARE_SPI #define XPT2046_SPI_PORT hspi4 extern SPI_HandleTypeDef XPT2046_TOUCH_SPI_PORT; #define XPT2046_IRQ_Pin T_IRQ_Pin #define XPT2046_IRQ_GPIO_Port T_IRQ_GPIO_Port #define XPT2046_CS_Pin T_CS_Pin #define XPT2046_CS_GPIO_Port T_CS_GPIO_Port #ifdef SOFTWARE_SPI #define XPT2046_MISO_Pin T_MISO_Pin #define XPT2046_MISO_GPIO_Port T_MISO_GPIO_Port #define XPT2046_MOSI_Pin T_MOSI_Pin #define XPT2046_MOSI_GPIO_Port T_MOSI_GPIO_Port #define XPT2046_CLK_Pin T_CLK_Pin #define XPT2046_CLK_GPIO_Port T_CLK_GPIO_Port #else // Warning! Use SPI bus with < 2.5 Mbit speed, better ~650 Kbit to be save. #define XPT2046_SPI_PORT hspi4 extern SPI_HandleTypeDef XPT2046_SPI_PORT; #endif /* SOFTWARE_SPI */ //////#define XPT2046_IRQ_Pin T_PEN_Pin //////#define XPT2046_IRQ_GPIO_Port T_PEN_GPIO_Port //////#define XPT2046_CS_Pin T_CS_Pin //////#define XPT2046_CS_GPIO_Port T_CS_GPIO_Port #define TOUCH_ORIENTATION_PORTRAIT (0U) #define TOUCH_ORIENTATION_LANDSCAPE (1U) #define TOUCH_ORIENTATION_PORTRAIT_MIRROR (2U) #define TOUCH_ORIENTATION_LANDSCAPE_MIRROR (3U) #define ORIENTATION (TOUCH_ORIENTATION_PORTRAIT_MIRROR) // change depending on screen orientation #if (ORIENTATION == 0) #define XPT2046_SCALE_X 240 #define XPT2046_SCALE_Y 320 #elif (ORIENTATION == 1) #define XPT2046_SCALE_X 320 #define XPT2046_SCALE_Y 240 #elif (ORIENTATION == 2) #define XPT2046_SCALE_X 240 #define XPT2046_SCALE_Y 320 #elif (ORIENTATION == 3) #define XPT2046_SCALE_X 320 #define XPT2046_SCALE_Y 240 #endif // to calibrate uncomment UART_Printf line in ili9341_touch.c #define XPT2046_MIN_RAW_X 3400 #define XPT2046_MAX_RAW_X 29000 #define XPT2046_MIN_RAW_Y 3300 #define XPT2046_MAX_RAW_Y 30000 #ifdef __cplusplus extern "C" { #endif // call before initializing any SPI devices extern bool XPT2046_TouchPressed(void); extern bool XPT2046_TouchGetCoordinates(uint16_t* x, uint16_t* y); #ifdef __cplusplus } #endif #endif /* XPT2046_TOUCH_H_ */
XPT2046_touch.c
/* * XPT2046_touch.c */ #include <stdio.h> #include <stdlib.h> #include <XPT2046_touch.h> #if (ORIENTATION == 0) #define READ_X 0xD0 #define READ_Y 0x90 #elif (ORIENTATION == 1) #define READ_Y 0xD0 #define READ_X 0x90 #elif (ORIENTATION == 2) #define READ_X 0xD0 #define READ_Y 0x90 #elif (ORIENTATION == 3) #define READ_Y 0xD0 #define READ_X 0x90 #endif #ifdef SOFTWARE_SPI #define SPI_CLK_L() HAL_GPIO_WritePin(XPT2046_CLK_GPIO_Port, XPT2046_CLK_Pin, GPIO_PIN_RESET) #define SPI_CLK_H() HAL_GPIO_WritePin(XPT2046_CLK_GPIO_Port, XPT2046_CLK_Pin, GPIO_PIN_SET) #define SPI_MOSI_L() HAL_GPIO_WritePin(XPT2046_MOSI_GPIO_Port, XPT2046_MOSI_Pin, GPIO_PIN_RESET) #define SPI_MOSI_H() HAL_GPIO_WritePin(XPT2046_MOSI_GPIO_Port, XPT2046_MOSI_Pin, GPIO_PIN_SET) #define SPI_MISO() HAL_GPIO_ReadPin(XPT2046_MISO_GPIO_Port, XPT2046_MISO_Pin) static void spi_write_byte(uint8_t data) { for(size_t i = 0; i < 8; i++) { if (data & 0x80) { SPI_MOSI_H(); } else { SPI_MOSI_L(); } data = data << 1; SPI_CLK_L(); SPI_CLK_H(); } } static uint8_t spi_read_byte(void) { uint8_t i, ret , value; ret = 0; i = 8; do { i--; SPI_CLK_L(); value = SPI_MISO(); if (value) { //set the bit to 0 no matter what ret |= (1 << i); } SPI_CLK_H(); } while (i > 0); return ret; } #endif /* SOFTWARE_SPI */ static void XPT2046_TouchSelect() { HAL_GPIO_WritePin(XPT2046_CS_GPIO_Port, XPT2046_CS_Pin, GPIO_PIN_RESET); } static void XPT2046_TouchUnselect() { HAL_GPIO_WritePin(XPT2046_CS_GPIO_Port, XPT2046_CS_Pin, GPIO_PIN_SET); } bool XPT2046_TouchPressed(void) { return HAL_GPIO_ReadPin(XPT2046_IRQ_GPIO_Port, XPT2046_IRQ_Pin) == GPIO_PIN_RESET; } bool XPT2046_TouchGetCoordinates(uint16_t* x, uint16_t* y) { #ifndef SOFTWARE_SPI static const uint8_t cmd_read_x[] = { READ_X }; static const uint8_t cmd_read_y[] = { READ_Y }; static const uint8_t zeroes_tx[] = { 0x00, 0x00 }; #endif /* SOFTWARE_SPI */ XPT2046_TouchSelect(); uint32_t avg_x = 0; uint32_t avg_y = 0; uint8_t nsamples = 0; for(uint8_t i = 0; i < 16; i++) { if(!XPT2046_TouchPressed()) break; nsamples++; uint8_t y_raw[2]; uint8_t x_raw[2]; #ifdef SOFTWARE_SPI spi_write_byte(READ_Y); y_raw[0] = spi_read_byte(); y_raw[1] = spi_read_byte(); spi_write_byte(READ_X); x_raw[0] = spi_read_byte(); x_raw[1] = spi_read_byte(); #else HAL_SPI_Transmit(&XPT2046_SPI_PORT, (uint8_t*)cmd_read_y, sizeof(cmd_read_y), HAL_MAX_DELAY); HAL_SPI_TransmitReceive(&XPT2046_SPI_PORT, (uint8_t*)zeroes_tx, y_raw, sizeof(y_raw), HAL_MAX_DELAY); HAL_SPI_Transmit(&XPT2046_SPI_PORT, (uint8_t*)cmd_read_x, sizeof(cmd_read_x), HAL_MAX_DELAY); HAL_SPI_TransmitReceive(&XPT2046_SPI_PORT, (uint8_t*)zeroes_tx, x_raw, sizeof(x_raw), HAL_MAX_DELAY); #endif /* SOFTWARE_SPI */ avg_x += (((uint16_t)x_raw[0]) << 8) | ((uint16_t)x_raw[1]); avg_y += (((uint16_t)y_raw[0]) << 8) | ((uint16_t)y_raw[1]); } XPT2046_TouchUnselect(); if(nsamples < 16) return false; uint32_t raw_x = (avg_x / 16); if(raw_x < XPT2046_MIN_RAW_X) raw_x = XPT2046_MIN_RAW_X; if(raw_x > XPT2046_MAX_RAW_X) raw_x = XPT2046_MAX_RAW_X; uint32_t raw_y = (avg_y / 16); if(raw_y < XPT2046_MIN_RAW_Y) raw_y = XPT2046_MIN_RAW_Y; if(raw_y > XPT2046_MAX_RAW_Y) raw_y = XPT2046_MAX_RAW_Y; // Uncomment this line to calibrate touchscreen: // printf("raw_x = %6d, raw_y = %6d\r\n", (int) raw_x, (int) raw_y); // printf("\x1b[1F"); #if (ORIENTATION == 0) *x = (raw_x - XPT2046_MIN_RAW_X) * XPT2046_SCALE_X / (XPT2046_MAX_RAW_X - XPT2046_MIN_RAW_X); *y = (raw_y - XPT2046_MIN_RAW_Y) * XPT2046_SCALE_Y / (XPT2046_MAX_RAW_Y - XPT2046_MIN_RAW_Y); #elif (ORIENTATION == 1) *x = (raw_x - XPT2046_MIN_RAW_X) * XPT2046_SCALE_X / (XPT2046_MAX_RAW_X - XPT2046_MIN_RAW_X); *y = (raw_y - XPT2046_MIN_RAW_Y) * XPT2046_SCALE_Y / (XPT2046_MAX_RAW_Y - XPT2046_MIN_RAW_Y); #elif (ORIENTATION == 2) *x = (raw_x - XPT2046_MIN_RAW_X) * XPT2046_SCALE_X / (XPT2046_MAX_RAW_X - XPT2046_MIN_RAW_X); *y = XPT2046_SCALE_Y - (raw_y - XPT2046_MIN_RAW_Y) * XPT2046_SCALE_Y / (XPT2046_MAX_RAW_Y - XPT2046_MIN_RAW_Y); #elif (ORIENTATION == 3) *x = XPT2046_SCALE_X - (raw_x - XPT2046_MIN_RAW_X) * XPT2046_SCALE_X / (XPT2046_MAX_RAW_X - XPT2046_MIN_RAW_X); *y = (raw_y - XPT2046_MIN_RAW_Y) * XPT2046_SCALE_Y / (XPT2046_MAX_RAW_Y - XPT2046_MIN_RAW_Y); #endif return true; }
Mian.c文件添加IRQ中断回调函数
void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) { if (GPIO_Pin == T_IRQ_Pin) { if(XPT2046_TouchPressed()) { uint16_t x = 0, y = 0; if(XPT2046_TouchGetCoordinates(&x, &y)) { //lcdFillCircle((lcdGetWidth() - x), y, 2, COLOR_GREENYELLOW); printf("XPT2046 x=%d,y=%d\n",x,y); } } } }
在Xpt.h 头文件中,触控方向设置
#define TOUCH_ORIENTATION_PORTRAIT (0U) #define TOUCH_ORIENTATION_LANDSCAPE (1U) #define TOUCH_ORIENTATION_PORTRAIT_MIRROR (2U) #define TOUCH_ORIENTATION_LANDSCAPE_MIRROR (3U) #define ORIENTATION (TOUCH_ORIENTATION_PORTRAIT_MIRROR)
将TOUCH_ORIENTATION_PORTRAIT_MIRROR为1时,触控原点在屏幕正向左上角
TOUCH_ORIENTATION_PORTRAIT_MIRROR为3时,触控原点在右上角
4、运行效果
模块接线与MCU接线
CS-PB6,PENIRQ-PD11,DCLK-PE2,DIN-MOSI,DOUT-MISO