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


我要赚赏金
