【STM32】XPT2046四导线触摸屏控制器 SPI驱动

简介

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

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值