简介
XPT2046 是一款 4 导线制触摸屏控制器,内含 12 位分辨率 125KHz转换速率逐步逼近型 A/D转换器。XPT2046支持从 1.5V 到 5.25V 的低电压 I/O 接口。XPT2046 能通过执行两次 A/D转换查出被按的屏幕位置, 除此之外,还可以测量加在触摸屏上的压力。
芯片的封装
功能简介
温度检测
XPT2046 集成温度检测功能,用于温度的检测。XPT2046 的温度测量有两种方法
方法1:
利用二极管的 PN 结温度系数相对稳定的特点,通过测试二极管的 PN 结电压来测量温度,可以预先测试并存储室温下的 PN 结电压(典型值为 600mV 左右),PN 结的温度系数约为-2mV/℃,测试其他温度时的 PN 结电压,就可以得到温度。
这种方法测试出的温度随工艺的变化有较大变化,而且需要校正。
方法2:
这种方法不要求指定测试温度基准,精确度可以达到 2℃。这种方法需要进行二次转换:
第一次,设置“A2A1A0”=“000”,测试 temp0 电流时的 PN 结电压 V0
**第二次,设置“A2A1A0”=“111”,实现 91 倍 temp0 大的电流,测试此时的 PN 结电压 V1。**第二次和第一次转换的电压差可以通过等式(1)表示:
其中:
N——电流比率系数,等于 91;
k——伯尔兹曼常数,等于 1.38054 × 10-23 伏特每开(V· K-1);
q——电荷量,等于 1.602189·10-19C
T——温度值(开尔文)
压力检测
XPT2046 也能对触摸的压力进行处理。为了判断触摸物体是笔还是手指,有必要对触摸压力进行测量。一般而言,这种测量的性能要求不高,所以采用 8 位分辨率模式
方法1:
需要知道 X 面板的电阻,X 位置的测量值,触摸屏两附加面板之间的测量值(Z1 和 Z2)
方法2:
要求测出 X 面板和 Y 面板的电阻,X 和 Y 的位置,和 Z1 的位置。可采用公式(4)计算
触摸电阻
数字接口
XPT2046 数据接口是串行接口,其典型工作时序如图 12 所示,图中展示的信号来自带有基本串行接口的单片机或数据信号处理器。处理器和转换器之间的的通信需要 8 个时钟周期,可采用 SPI、SSI 和 Microwire 等同步串行接口。一次完整的转换需要 24 个串行同步时钟(DCLK)来完成。
引脚定义
控制字节由 DIN 输入的控制字如表 5 所示,它用来启动转换,寻址,设置 ADC 分辨率,配置和对 XPT2046 进行掉电控制
起始位——第一位,即 S 位。控制字的首位必须是 1,即 S=1。在 XPT2046 的 DIN 引脚检测到起始位前,所有的输入将被忽略。
地址——接下来的 3 位(A2、A1 和 A0)选择多路选择器的现行通道(见表 3、表 4 和图 6),触摸屏驱动和参考源输入。
MODE——模式选择位,用于设置 ADC 的分辨率。MODE=0,下一次的转换将是 12 位模式;
MODE=1,下一次的转换将是 8 位模式。
SER/——DFR——SER/——DFR位控制参考源模式,选择
单端模式(SER/——DFR=1),或者差分模式(SER/——DFR=0)。在X坐标、Y坐标和触摸压力测量中,为达到最佳性能,首选差分工作模式。参考电压来自开关驱动器的电压。在单端模式下,转换器的参考电压固定为VREF相对于GND引脚的电
压
数字时序
通信的过程很简单,首先主机向XPT2046写入8个字节的控制字节,然后从XPT2046中读出转换数据即可,读出来的数据有16位,只有高12位是有效数据。控制字节的含义如下
—>此图来源于CSDN XPT2046的使用
代码控制
#include "touch.h"
#include "ili9341.h"
#include "usart.h"
/****************************************************************************
* 名 称 :void Touch_Init(void)
* 功 能 :初始化GPUI管脚
* 入口参数:void
* 出口参数:void
* 说 明 :void
* 作 者 :koko
****************************************************************************/
void Touch_Init(void)
{
GPIO_InitTypeDef Touch_Gpio_Spi_structure;
EXTI_InitTypeDef Touch_Exti_Structure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO ,ENABLE);
Touch_Gpio_Spi_structure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
Touch_Gpio_Spi_structure.GPIO_Speed = GPIO_Speed_50MHz ;
Touch_Gpio_Spi_structure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_3|GPIO_Pin_13;
GPIO_Init(GPIOC,&Touch_Gpio_Spi_structure);
Touch_Gpio_Spi_structure.GPIO_Mode = GPIO_Mode_IPU ; //上拉输入
Touch_Gpio_Spi_structure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2 ;
Touch_Gpio_Spi_structure.GPIO_Speed = GPIO_Speed_50MHz ;
GPIO_Init(GPIOC,&Touch_Gpio_Spi_structure);
Touch_CS = 0 ;
}
/****************************************************************************
* 名 称 :static void Touch_Write_CMD(u8 cmd)
* 功 能 :通过SPI时序写入一个8bit控制位
* 入口参数:u8 cmd
* 出口参数:void
* 说 明 :void
* 作 者 :koko
****************************************************************************/
static void Touch_Write_CMD(u8 cmd)
{
u8 i;
Touch_OUT = 0; //命令 控制位
Touch_CLK = 0;
for( i =0 ;i <8 ; i ++)
{
if(cmd & 0x80)
{
Touch_OUT = 1;
}else
{
Touch_OUT = 0;
}
Touch_CLK = 1;
delay_us(5);
Touch_CLK = 0;
cmd <<= 1;
}
}
/****************************************************************************
* 名 称 :static u16 Touch_Read_Data()
* 功 能 :获取一个12位的数据存储到u16 data内
* 入口参数:void
* 出口参数:u16 data
* 说 明 :null
* 作 者 :koko
****************************************************************************/
static u16 Touch_Read_Data()
{
u8 i;
u16 data;
Touch_OUT = 0;
Touch_CLK = 1;
for( i = 0;i<12;i++)
{
Touch_CLK = 0;
data += Touch_IN ;
data <<= 1;
Touch_CLK = 1;
}
return data;
}
void XPT2046_getSourceValue(u16 *x_AD_AVG, u16 *y_AD_AVG)
{
u16 i,temp;
int j;
u16 x_AD[Touch_SAMPLING_TIMES] = { 0 };
u16 y_AD[Touch_SAMPLING_TIMES] = { 0 };
u16 x_AD_temp = 0;
u16 y_AD_temp = 0;
for (i = 0; i < Touch_SAMPLING_TIMES;) {
if (Touch_IQR == 0) {
Touch_Write_CMD(READ_CHANNEL_Y); //写读取X通道AD指令
x_AD[i] = Touch_Read_Data(); //读取X通道AD值
delay_us(2);
Touch_Write_CMD(READ_CHANNEL_X); //写读取Y通道AD指令
y_AD[i] = Touch_Read_Data(); //读取Y通道AD值
delay_us(2);
i++;
}
}
//冒泡排序
for ( i = 0, temp = 0; i < Touch_SAMPLING_TIMES; i++)
for ( j = 0; j < Touch_SAMPLING_TIMES - i - 1; j++) {
if (x_AD[j] > x_AD[j + 1]) {
temp = x_AD[j];
x_AD[j] = x_AD[j + 1];
x_AD[j + 1] = temp;
}
if (y_AD[j] > y_AD[j + 1]) {
temp = y_AD[j];
y_AD[j] = y_AD[j + 1];
y_AD[j + 1] = temp;
}
}
//去掉一个最大值,去掉一个最小值,取平均值
for ( i = 1; i < Touch_SAMPLING_TIMES - 1; i++) {
x_AD_temp += x_AD[i];
y_AD_temp += y_AD[i];
}
x_AD_temp /= (Touch_SAMPLING_TIMES - 2);
y_AD_temp /= (Touch_SAMPLING_TIMES - 2);
//赋值
*x_AD_AVG = x_AD_temp;
*y_AD_AVG = y_AD_temp;
}
void XPT2046_getPoint(u16 *x, u16 *y)
{
u16 x_AD_AVG = 0;
u16 y_AD_AVG = 0;
if (Touch_IQR == 0) {
XPT2046_getSourceValue(&x_AD_AVG, &y_AD_AVG); //获取原始数据
/*
* 具体计算依据如下,获取触摸屏左上角(800,7700)、右上角(7700,7700)、左下角(800,800)、右下角(7700,800)的AD值
* 发现x,y与对应的AD值成简单的线性关系,x对应的AD值从左到右由800增加到7700,y对应的AD值由7700减少到800,于是可以得到以下计算公式
*/
//计算点坐标
*x =( 360-226 - (x_AD_AVG - 800) * Touch_X / 6900)*2;
*y =( 240-110- (y_AD_AVG - 800) * Touch_X / 6900)*2;
//确保x和y不越界
if (*x > Touch_X - 1)
*x = Touch_X - 1;
if (*y > Touch_Y)
*y = Touch_Y;
}
return;
}
#ifndef _TOUCH_H__
#define _TOUCH_H__
#include "stm32f10x.h" // Device header
#include "sys.h"
#include "delay.h"
//触摸区域
#define Touch_X 320
#define Touch_Y 240
#define Touch_SAMPLING_TIMES 4
//指令宏定义
#define READ_CHANNEL_X 0xD0
#define READ_CHANNEL_Y 0x90
//IO管脚定义
#define Touch_IQR PCin(1) //T_IQR --> PC1 -->中断输入
#define Touch_IN PCin(2) //T_DO --> PC2 -->数据输人
#define Touch_OUT PCout(3) //T_DI --> PC3 -->数据输出
#define Touch_CLK PCout(0) //T_CLK --> PC0 -->时钟线
#define Touch_CS PCout(13) //T_CS --> PC13 -->片选
void Touch_Init(void); //初始化GPIO引脚
void XPT2046_getSourceValue(u16 *x_AD_AVG, u16 *y_AD_AVG);
void XPT2046_getPoint(u16 *x, u16 *y);
#endif