stm32(十九)触摸屏XPT2046

1、触摸屏介绍

触摸屏(touch screen)又称为“触控屏”、 “触摸面板”,是一种可接收触头等输入讯号的感应式液晶显示装置,
当接触了屏幕上的图形按钮时,屏幕上的触觉反馈系统可根据预先编程的程式驱动各种连结装置,可用以取代机
械式的按钮面板,并借由液晶显示画面制造出生动的影音效果。触摸屏作为一种最新的电脑输入设备,它是目前
最简单、方便、自然的一种人机交互方式。它赋予了多媒体以崭新的面貌,是极富吸引力的全新多媒体交互设备。
主要应用于公共信息的查询、领导办公、工业控制、军事指挥、电子游戏、点歌点菜、多媒体教学、房地产预售
等。


2、触摸屏的类型

触摸屏常见的类型有电阻式,电容式,红外线式以及表面声波式


2.1. 电阻触摸屏
电阻触摸屏的屏体部分是一块与显示器表面相匹配的多层复合薄膜,由一层玻璃或有机玻璃作为基层,表面
涂有一层透明的导电层,上面再该有一层外表面硬化处理,光滑防刮的塑料层,它的内表面也涂有一层透明到垫
层,在两层导电层之间 有许多细小的透明隔离点把它们隔离绝缘
当手指触摸屏幕时,平常相互绝缘的导电层就在触摸点位置有了一个接触,因其中一面导电层接触 Y 轴方向
的 5V 均匀电压场,使得侦测层的电压由零变为非零,这种接通状态倍控制器侦测后,进行 A/D 转换,并将得到
的电压值与 5V 相比即可得到触摸点的 Y 轴坐标,同理得出 X 轴的坐标,这就是所有电阻技术触摸屏共同的原理。
电阻屏根据引出线数多少,分为四线、五线、六线等多线电阻触摸屏
(1) 四线电阻屏
四线电阻屏模拟量技术的两层透明金属工作时每层均增加 5V 恒定电压,一个竖直方向,一个水平方向,总
共需要四根电缆。特点:高解析度,高速传输反应,表面硬度处理,减少擦伤,刮伤及防化学处理,具有光面及
雾面处理,一次校正,稳定性高,永不漂移。
(2) 五线电阻屏
五线电阻技术触摸屏的基层把两个方向的电压场通过精密电阻网络都加在玻璃的导电工作面上,我们可以简
单的理解为两个方向的电压场分时工作加在同一工作面上,而外层镍金导电层只仅仅用来当作纯导体,有触摸后
分时检测内层 ITO 接触点 X 轴和 Y 轴电压值的方法测得触摸点的位置,五线电阻触摸屏内层 ITO 需四条引线,外
层只作导体仅仅一条,触摸屏的引出线共有 5 条。特点:解析度高,高速传输反应,表面硬度高,减少擦伤,刮
伤及防化学处理,同点接触 3000 万次尚可使用。
2.2. 电容触摸屏
电容式触摸屏的构造主要是在玻璃屏幕上镀一层透明的薄膜体层,再在导体层外上一块保护玻璃,双玻璃设
计能彻底保护导体层及感应器。此外,在附加的触摸屏四边均镀上狭长的电极,在导电体内形成一个低电压交流
电场。
用户触摸屏幕时,由于人体电场,手指与导体层间会形成一个耦合电容,四边电极发出的电流会流向触电,
而其强弱与手指及电极的距离成正比,位于触摸屏后的控制器便会计算电流的比列及强弱,准确算出触摸点的位
置。电容触摸屏的双玻璃不但能保护导体及感应器,更有效地防止外在环境因素给触摸屏造成影响,就算屏幕沾
有污秽,尘埃或油渍,电容式触摸屏依然能准确算出触摸位置


3. 触摸屏的控制器


触摸屏控制器一般有:主控内部自带控制器和外置控制器两种,常见的外置控制器(电阻触摸屏): ADS7843,ADS7846,TSC2046,XPT2046 和 AK4182 等,
3.1. 触摸屏控制器 XPT2046
(1) 特点

  • 采用 SPI 四线控制通信接口
  • SPI 通信支持模式 0 和模式 3
  • SPI 通信速度最快 2.5MHz
  • ADC 分辨率 12 位
  • ADC 转换周期最快 15 个时钟周期
  • 支持命令切换测量方向

3.2、硬件连接

stm32(十九)触摸屏XPT2046_第1张图片

3.3. XPT2046 管脚说明

stm32(十九)触摸屏XPT2046_第2张图片

3.4、XPT2046 时序

stm32(十九)触摸屏XPT2046_第3张图片

3.5、控制位命令

3.6、差分模式输入配置

stm32(十九)触摸屏XPT2046_第4张图片

3.7、控制字节各位描述

stm32(十九)触摸屏XPT2046_第5张图片

3.8、掉电和内部参考电压选择

stm32(十九)触摸屏XPT2046_第6张图片

3.8、触摸屏校准

校准:使得触膜和LCD屏建立联系。当按下触膜的某一个AD坐标点时,获知当前AD坐标点所对应的LCD像素点。

stm32(十九)触摸屏XPT2046_第7张图片

建立触膜和LCD屏建立联系,需要有两条公式:

Xlcd = Xtouch*(320/4096);

Ylcd = Ytouch*(480/4096);

如果触摸和LCD可以100%工整贴合,则换算公式就是上面的公式。

但是,实际上,不可能100%工整贴合。此时我们需要校准。

校准的过程如下图所示,目的是为了求得“比例系数”和“像素点偏移”

stm32(十九)触摸屏XPT2046_第8张图片

 

4、软件设计

功能:校准:使得触膜和LCD屏建立联系。当按下触膜的某一个AD坐标点时,获知当前AD坐标点所对应的LCD像素点。

寄存器就配置不一样,不弄了,懒了,但是寄存器配置也在代码里,屏蔽了,其他就只有管脚拉低拉高

#include "stm32f4xx.h"
#include "stdio.h"
#include "math.h"
typedef struct
{
	u16 x;
	u16 y;
}TOUCH_XY_TYPEDEF;

typedef struct
{
	float kx;      //比例系数
	s16 offset_x;   //偏移量
	float ky;
	s16 offset_y;
}TOUCH_ADJ_TYPEDEF;

TOUCH_ADJ_TYPEDEF touch_adj;

void Touch_Init(void);
void Touch_Adj_Init(void);
u16 Touch_Get_ADC(u8 common);
TOUCH_XY_TYPEDEF Touch_Get_XY(void);
TOUCH_XY_TYPEDEF Get_Touch_Lcd(void);
TOUCH_XY_TYPEDEF Touch_Scanf(void);
TOUCH_XY_TYPEDEF Get_Touch_Lcd_XY(void);

void Delay_ms(u16 ms)
{
	SysTick->CTRL &=~(1<<2);//选择时钟源为21MHZ
	SysTick->CTRL &=~(1<<1);//禁止滴答中断
	SysTick->LOAD = 21000*ms; //设置重装载寄存器的值
	SysTick->CTRL |= (1<<0);//使能滴答定时器
	while(!(SysTick->CTRL&(1<<16)));//阻塞判断定时时间是否到达,判断SysTick->CTRL的位
}

void Delay_us(u16 us)
{
	SysTick->CTRL &=~(1<<2);//选择时钟源为21MHZ
	SysTick->CTRL &=~(1<<1);//禁止滴答中断
	SysTick->LOAD = 21*us; //设置重装载寄存器的值
	SysTick->CTRL |= (1<<0);//使能滴答定时器
	while(!(SysTick->CTRL&(1<<16)));//阻塞判断定时时间是否到达,判断SysTick->CTRL的位
}
void usart_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructe;
	USART_InitTypeDef USART_InitStructe;
	NVIC_InitTypeDef NVIC_InitStructe;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);  //使能A端口
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);  //使能串口端口
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIO端口映射到USART
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIO端口映射到USART

//	USART_DeInit(USART1);    //复位
	
	GPIO_InitStructe.GPIO_Mode =GPIO_Mode_AF;     //配置为输出模式
	GPIO_InitStructe.GPIO_OType =GPIO_OType_PP;    //配置为推挽输出
	GPIO_InitStructe.GPIO_Pin =GPIO_Pin_9|GPIO_Pin_10;   //初始化GPIOA9/10;
	GPIO_InitStructe.GPIO_Speed =GPIO_Speed_50MHz; //速度设置为50MHz
	GPIO_Init(GPIOA,&GPIO_InitStructe);
	
	USART_InitStructe.USART_BaudRate =115200;  //波特率
	USART_InitStructe.USART_HardwareFlowControl =USART_HardwareFlowControl_None;//无硬件流控制
	USART_InitStructe.USART_Mode =USART_Mode_Tx|USART_Mode_Rx;  //接收模式,发送模式使能
	USART_InitStructe.USART_Parity =USART_Parity_No;         //无奇偶校验
	USART_InitStructe.USART_StopBits =USART_StopBits_1;     //一位停止位
	USART_InitStructe.USART_WordLength =USART_WordLength_8b;//8位数据位
  USART_Init(USART1,&USART_InitStructe);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
	NVIC_InitStructe.NVIC_IRQChannel= USART1_IRQn;     //串口1中断
	NVIC_InitStructe.NVIC_IRQChannelCmd =ENABLE;       //串口1使能
	NVIC_InitStructe.NVIC_IRQChannelPreemptionPriority =0;  //抢占优先级设为0
	NVIC_InitStructe.NVIC_IRQChannelSubPriority =0;        //子优先级设为0
	NVIC_Init(&NVIC_InitStructe);
	
  USART_Cmd(USART1,ENABLE); //使能串口
}
int fputc(int data,FILE *file)
{
  USART_SendData(USART1,data);
  while(!USART_GetFlagStatus(USART1,USART_FLAG_TC))
	{
	}
  return data;
}
/******************** LCD引脚初始化函数 *******************
LCD显示屏硬件管脚对应关系:
数据线:
DB0---PD14	DB1---PD15	DB2---PD0	DB3---PD1
DB4---PE7	DB5---PE8	DB6---PE9	DB7---PE10
DB8---PE11	DB9---PE12	DB10---PE13	DB11---PE14
DB12---PE15	DB13---PD8	DB14---PD9	DB15---PD10
控制线:
WR---PD5	RD---PD4	CS---PG12	BL--PB15 ,DC --PF12
**********************************************************/
void LCD_PinInit(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	//使能PD,PE,PF,PG时钟  
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE|\
												 RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOG, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_8|\
															GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_14|GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Speed=GPIO_Fast_Speed;
  GPIO_Init(GPIOD, &GPIO_InitStructure);  
	GPIO_SetBits(GPIOD,GPIO_Pin_4|GPIO_Pin_5);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;//PE7~15,AF OUT
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
  GPIO_Init(GPIOE, &GPIO_InitStructure);  
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
  GPIO_Init(GPIOG, &GPIO_InitStructure);
	GPIO_SetBits(GPIOG,GPIO_Pin_12);
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
  GPIO_Init(GPIOF, &GPIO_InitStructure); 
	GPIO_SetBits(GPIOF,GPIO_Pin_12);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOB,GPIO_Pin_15);
}
/******************* LCD写命令函数 *********************************
参数:需要输入的命令
********************************************************************/
void LCD_ILI9486_CMD(u16 common)
{
	GPIO_ResetBits(GPIOG,GPIO_Pin_12);
	GPIO_ResetBits(GPIOF,GPIO_Pin_12);
	GPIO_ResetBits(GPIOD,GPIO_Pin_5);
	if(common&0x01) GPIO_SetBits(GPIOD,GPIO_Pin_14);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_14);
	if(common&0x02) GPIO_SetBits(GPIOD,GPIO_Pin_15);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_15);
	if(common&0x04) GPIO_SetBits(GPIOD,GPIO_Pin_0);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_0);
	if(common&0x08) GPIO_SetBits(GPIOD,GPIO_Pin_1);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_1);
	if(common&0x10) GPIO_SetBits(GPIOE,GPIO_Pin_7);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_7);
	if(common&0x20) GPIO_SetBits(GPIOE,GPIO_Pin_8);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_8);
	if(common&0x40) GPIO_SetBits(GPIOE,GPIO_Pin_9);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_9);
	if(common&0x80) GPIO_SetBits(GPIOE,GPIO_Pin_10);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_10);
	if(common&0x0100) GPIO_SetBits(GPIOE,GPIO_Pin_11);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_11);
	if(common&0x0200) GPIO_SetBits(GPIOE,GPIO_Pin_12);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_12);
	if(common&0x0400) GPIO_SetBits(GPIOE,GPIO_Pin_13);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_13);
	if(common&0x0800) GPIO_SetBits(GPIOE,GPIO_Pin_14);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_14);
	if(common&0x1000) GPIO_SetBits(GPIOE,GPIO_Pin_15);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_15);
	if(common&0x2000) GPIO_SetBits(GPIOD,GPIO_Pin_8);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_8);
	if(common&0x4000) GPIO_SetBits(GPIOD,GPIO_Pin_9);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_9);
	if(common&0x8000) GPIO_SetBits(GPIOD,GPIO_Pin_10);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_10);
	GPIO_SetBits(GPIOD,GPIO_Pin_5);
	GPIO_SetBits(GPIOG,GPIO_Pin_12);
}

/******************* LCD写数据函数 *********************************
参数:需要输输入待写到LCD屏的数据
********************************************************************/
void LCD_ILI9486_Parameter(u16 data)
{
	GPIO_ResetBits(GPIOG,GPIO_Pin_12);
	GPIO_SetBits(GPIOF,GPIO_Pin_12);
	GPIO_ResetBits(GPIOD,GPIO_Pin_5);
	//发送 16 位数据
	if(data&0x01) GPIO_SetBits(GPIOD,GPIO_Pin_14);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_14);
	if(data&0x02) GPIO_SetBits(GPIOD,GPIO_Pin_15);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_15);
	if(data&0x04) GPIO_SetBits(GPIOD,GPIO_Pin_0);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_0);
	if(data&0x08) GPIO_SetBits(GPIOD,GPIO_Pin_1);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_1);
	if(data&0x10) GPIO_SetBits(GPIOE,GPIO_Pin_7);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_7);
	if(data&0x20) GPIO_SetBits(GPIOE,GPIO_Pin_8);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_8);
	if(data&0x40) GPIO_SetBits(GPIOE,GPIO_Pin_9);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_9);
	if(data&0x80) GPIO_SetBits(GPIOE,GPIO_Pin_10);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_10);
	if(data&0x0100) GPIO_SetBits(GPIOE,GPIO_Pin_11);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_11);
	if(data&0x0200) GPIO_SetBits(GPIOE,GPIO_Pin_12);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_12);
	if(data&0x0400) GPIO_SetBits(GPIOE,GPIO_Pin_13);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_13);
	if(data&0x0800) GPIO_SetBits(GPIOE,GPIO_Pin_14);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_14);
	if(data&0x1000) GPIO_SetBits(GPIOE,GPIO_Pin_15);
	else GPIO_ResetBits(GPIOE,GPIO_Pin_15);
	if(data&0x2000) GPIO_SetBits(GPIOD,GPIO_Pin_8);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_8);
	if(data&0x4000) GPIO_SetBits(GPIOD,GPIO_Pin_9);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_9);
	if(data&0x8000) GPIO_SetBits(GPIOD,GPIO_Pin_10);
	else GPIO_ResetBits(GPIOD,GPIO_Pin_10);
	GPIO_SetBits(GPIOD,GPIO_Pin_5);
	GPIO_SetBits(GPIOG,GPIO_Pin_12);
}
//以某个颜色清除整个LCD屏
void LCD_ClearTotalLCD(u16 color)
{
	u32 i;
	LCD_ILI9486_CMD(0x2A);           //设置列地址
	LCD_ILI9486_Parameter(0>>8);      
	LCD_ILI9486_Parameter(0&(0xFF));
	LCD_ILI9486_Parameter(319>>8);      
	LCD_ILI9486_Parameter(319&(0xFF));
	
	LCD_ILI9486_CMD(0x2B);          //设置行地址
	LCD_ILI9486_Parameter(0>>8);      
	LCD_ILI9486_Parameter(0&(0xFF));
	LCD_ILI9486_Parameter(479>>8);      
	LCD_ILI9486_Parameter(479&(0xFF));
	
	
	LCD_ILI9486_CMD(0x2C);         //写显存的命令
	for(i=0;i<(320*480);i++)
	{
		LCD_ILI9486_Parameter(color); 
	}
}


void LCD_ShowPoint(u16 x,u16 y,u16 color)
{
	//2A  确定横坐标 x的范围
	LCD_ILI9486_CMD(0X2a); 
	LCD_ILI9486_Parameter (x>>8);//起始横坐标
	LCD_ILI9486_Parameter (x);
	LCD_ILI9486_Parameter (x>>8);//终止横坐标
	LCD_ILI9486_Parameter (x);
	
	//2b  确定纵坐标 y的范围
	LCD_ILI9486_CMD(0X2b); 
	LCD_ILI9486_Parameter (y>>8);//起始纵坐标
	LCD_ILI9486_Parameter (y);
	LCD_ILI9486_Parameter (y>>8);//终止纵坐标
	LCD_ILI9486_Parameter (y);
	
	//2c 填充颜色
	LCD_ILI9486_CMD(0X2c);
	LCD_ILI9486_Parameter (color);
	
}

//显示十字
void LCD_Draw_SZ(u16 x, u16 y, u16 color)
{
	u16 i;
	for(i=x-10; iODR |= 1 << 15;          //开LCD背光灯
	
//	GPIO_SetBits(GPIOB,GPIO_Pin_15);          //开LCD背光灯
}


/*
硬件连接
XTP2046    LCD屏     MCU
CLK       T_CLK      PB0       输出
CS        T_CS       PC13      输出
DIN       T_MOSI     PF11      输出
DOUT      T_MISO     PB2       输入
PEN       T_PEN      PB1       输入
*/
#define T_PEN          (!!(GPIOB->IDR &(1<<1)))
#define T_CS_LOW       (GPIOC->ODR &=~(1<<13))
#define T_CS_HIGH      (GPIOC->ODR |=(1<<13))
#define T_MOSI_HIGH 	(GPIOF->ODR |=(1<<11))
#define T_MOSI_LOW  	(GPIOF->ODR &=~(1<<11))
#define T_CLK_HIGH     (GPIOB->ODR |=(1<<0))
#define T_CLK_LOW      (GPIOB->ODR &=~(1<<0))
#define T_MISO         (GPIOB->IDR &(1<<2))
void Touch_Init()
{
  GPIO_InitTypeDef TOUCH_InitTypeDef;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);  //使能F端口
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);  //使能C端口
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);  //使能F端口
	
	/*PB0  输出**/
	TOUCH_InitTypeDef.GPIO_Mode =GPIO_Mode_OUT;     //配置为输出模式
	TOUCH_InitTypeDef.GPIO_OType =GPIO_OType_PP;    //配置为推挽输出
	TOUCH_InitTypeDef.GPIO_Pin =GPIO_Pin_0;         //初始化GPIOB0;
	TOUCH_InitTypeDef.GPIO_PuPd =GPIO_PuPd_NOPULL;  //配置为无上下拉状态
	TOUCH_InitTypeDef.GPIO_Speed =GPIO_Speed_2MHz; //速度设置为2MHz
	GPIO_Init(GPIOB,&TOUCH_InitTypeDef);
	
	/*PC13 输出*/
	TOUCH_InitTypeDef.GPIO_Mode =GPIO_Mode_OUT;     //配置为输出模式
	TOUCH_InitTypeDef.GPIO_OType =GPIO_OType_PP;    //配置为推挽输出
	TOUCH_InitTypeDef.GPIO_Pin =GPIO_Pin_13;         //初始化GPIOC0;
	TOUCH_InitTypeDef.GPIO_PuPd =GPIO_PuPd_NOPULL;  //配置为无上下拉状态
	TOUCH_InitTypeDef.GPIO_Speed =GPIO_Speed_2MHz; //速度设置为2MHz
	GPIO_Init(GPIOC,&TOUCH_InitTypeDef);                              

	/*PF11 输出*/
	TOUCH_InitTypeDef.GPIO_Mode =GPIO_Mode_OUT;     //配置为输出模式
	TOUCH_InitTypeDef.GPIO_OType =GPIO_OType_PP;    //配置为推挽输出
	TOUCH_InitTypeDef.GPIO_Pin =GPIO_Pin_11;         //初始化GPIOF11;
	TOUCH_InitTypeDef.GPIO_PuPd =GPIO_PuPd_NOPULL;  //配置为无上下拉状态
	TOUCH_InitTypeDef.GPIO_Speed =GPIO_Speed_2MHz; //速度设置为2MHz
	GPIO_Init(GPIOF,&TOUCH_InitTypeDef);                              

	/*PB2 输入*/
	TOUCH_InitTypeDef.GPIO_Mode =GPIO_Mode_IN;     //配置为输出模式
	TOUCH_InitTypeDef.GPIO_Pin =GPIO_Pin_2;         //初始化GPIOF11;
	TOUCH_InitTypeDef.GPIO_PuPd =GPIO_PuPd_NOPULL;  //配置为无上下拉状态
	GPIO_Init(GPIOB,&TOUCH_InitTypeDef); 
	
	/*PB1 输入*/
	TOUCH_InitTypeDef.GPIO_Mode =GPIO_Mode_IN;     //配置为输出模式
	TOUCH_InitTypeDef.GPIO_Pin =GPIO_Pin_1;         //初始化GPIOF11;
	TOUCH_InitTypeDef.GPIO_PuPd =GPIO_PuPd_NOPULL;  //配置为无上下拉状态
	GPIO_Init(GPIOB,&TOUCH_InitTypeDef); 

	GPIO_SetBits(GPIOF,GPIO_Pin_11);      //DIN空闲状态为高电平
  GPIO_SetBits(GPIOC,GPIO_Pin_13);	//CS拉高
	GPIO_ResetBits(GPIOB,GPIO_Pin_0); 
//	RCC->AHB1ENR |= (1<<1)|(1<<2)|(1<<5); //打开PB PC PF时钟
//	
//	//CLK--PB0 通用推挽 50M 
//	GPIOB->MODER &=~(0X3<<0);  //清零
//	GPIOB->MODER |=(0X1<<0);  //配置成通用输出  
//	GPIOB->OTYPER &=~(1<<0);  //配置成输出推挽
//	GPIOB->OSPEEDR &=~(0X3<<0);  //清零
//	GPIOB->OSPEEDR |=(0X2<<0);   //配置成输出速率50M
//	
//	//CS--PC13 通用推挽 50M 
//	GPIOC->MODER &= ~(0X3<<26);  //清零
//	GPIOC->MODER |= (0X1<<26);  //配置成通用输出  
//	GPIOC->OTYPER &= ~(1<<13);  //配置成输出推挽
//	GPIOC->OSPEEDR &=~(0X3<<26);  //清零
//	GPIOC->OSPEEDR |=(0X2<<26);   //配置成输出速率50M
//	
//	//DIN--MOSI PF11 通用推挽 50M 
//	GPIOF->MODER &= ~(0X3<<22);  //清零
//	GPIOF->MODER |= (0X1<<22);  //配置成通用输出  
//	GPIOF->OTYPER &= ~(1<<11);  //配置成输出推挽
//	GPIOF->OSPEEDR &= ~(0X3<<22);  //清零
//	GPIOF->OSPEEDR |= (0X2<<22);   //配置成输出速率50M
//	
//	/* DOUT--T_MISO--PB2 输入 */
//	GPIOB->MODER &= ~(0X3<<4);  //清零
//	GPIOB->MODER |= (0X0<<4);   //配置成输入模式
//	GPIOB->PUPDR &=~(0X3<<4);  //配置成无上下拉-浮空
//	
//	/* PEN--T_PEN--PB1 输入 */
//	GPIOB->MODER &= ~(0X3<<2);  //清零
//	GPIOB->MODER |= (0X0<<2);   //配置成输入模式
//	GPIOB->PUPDR &= ~(0X3<<2);  //配置成无上下拉-浮空
}
/*******************************************************************
* 函数名:     Touch_Get_ADC()
* 功能描述 :   触摸屏数据时序函数
*******************************************************************/
u16 Touch_Get_ADC(u8 common)
{
	u8 i;
	u16 data = 0;
	
	GPIO_ResetBits(GPIOC,GPIO_Pin_13);    //拉低片选

	/* 发送控制字节 */
	for(i = 0; i < 8; i++)
	{
		GPIO_ResetBits(GPIOB,GPIO_Pin_0);    //拉低时钟线,准备数据
		if(common & 0x80)
		{
			GPIO_SetBits(GPIOF,GPIO_Pin_11);    //拉高MOSI数据线,输出1
		}
		else
		{
			GPIO_ResetBits(GPIOF,GPIO_Pin_11);    //拉高MOSI数据线,输出1
		}
		Delay_us(1);
		GPIO_SetBits(GPIOB,GPIO_Pin_0);     //时钟产生上升沿,发出数据
		Delay_us(1);
		common <<= 1;
	}
	
	/* 产生一个空闲时钟 */
	GPIO_SetBits(GPIOB,GPIO_Pin_0);	
	Delay_us(1);	
	GPIO_ResetBits(GPIOB,GPIO_Pin_0);
	Delay_us(1);
	GPIO_SetBits(GPIOB,GPIO_Pin_0);	

	/* 读数据 */
	for(i = 0; i < 12; i++)
	{
		data <<= 1;
		GPIO_ResetBits(GPIOB,GPIO_Pin_0);
		Delay_us(1);
		GPIO_SetBits(GPIOB,GPIO_Pin_0);	
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2))
		{
			data |= 1;
		}
		Delay_us(1);
	}
	
	/* 空闲状态 */
	GPIO_SetBits(GPIOB,GPIO_Pin_0);     //拉低时钟线
	GPIO_SetBits(GPIOB,GPIO_Pin_0);     //拉高片选  
	GPIO_SetBits(GPIOB,GPIO_Pin_0);     //拉低数据线
	
	return data;
}

/*******************************************************************
* 函数名:     Touch_Get_XY()
* 功能描述 :   触摸屏获取坐标参数函数
*******************************************************************/
TOUCH_XY_TYPEDEF Touch_Get_XY(void)
{
	TOUCH_XY_TYPEDEF touch;
	u16 buff[10],temp;
	u8 i,j;
	
	/* 获取X轴坐标AD值 */
	for(i = 0; i < 10; i++)
	{
		buff[i] = Touch_Get_ADC(0xD0);    //读取X轴AD值
	}
	/* 数据排序 */
	for(i = 1; i < 9; i++)
	{
		for(j = i; j < 10; j++)
		{
			if(buff[i] < buff[j])
			{
				temp = buff[i];
				buff[i] = buff[j];
				buff[j] = temp;
			}
		}
	}
	temp = 0;
	for(i = 1; i < 9; i++)
	{
		temp += buff[i];
	}
	touch.x = temp / 8;     /* 求平均数 */
	
	/* 获取Y轴坐标AD值 */
	for(i = 0; i < 10; i++)
	{
		buff[i] = Touch_Get_ADC(0x90);    //读取Y轴AD值
	}
	/* 数据排序 */
	for(i = 1; i < 9; i++)
	{
		for(j = i; j < 10; j++)
		{
			if(buff[i] < buff[j])
			{
				temp = buff[i];
				buff[i] = buff[j];
				buff[j] = temp;
			}
		}
	}
	temp = 0;
	for(i = 1; i < 9; i++)
	{
		temp += buff[i];
	}
	touch.y = temp / 8;   /* 求平均数 */
	
	return touch;
}
TOUCH_XY_TYPEDEF Get_Touch_Lcd(void)
{
	TOUCH_XY_TYPEDEF touch;
	
	touch=Touch_Get_XY( );     //获取触摸屏AD转换值
	
	touch.x = touch_adj.kx * touch.x + touch_adj.offset_x;
	touch.y = (touch_adj.ky * touch.y + touch_adj.offset_y);

	return touch;
}

/*******************************************************************
* 函数名:     Touch_Scanf()
* 功能描述 :  触摸屏坐标扫描函数
*******************************************************************/
TOUCH_XY_TYPEDEF Touch_Scanf(void)
{
	static u8 touch_sta = 1;
	
	TOUCH_XY_TYPEDEF touch_key[2];
	TOUCH_XY_TYPEDEF touchkey = {0xffff,0xffff};
	
	if( (touch_sta==1)&&(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)) )            //允许是被并且触摸屏有按下
	{
		
		Delay_ms(5);                                     //延时去抖
		if( !GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) )
		{
			
			touch_key[0] = Get_Touch_Lcd();
			touch_key[1] = Get_Touch_Lcd();
			
			/* 求绝对值 */
			if( (abs(touch_key[0].x -touch_key[1].x)<5) &&
			    (abs(touch_key[0].y -touch_key[1].y)<5) )       //识别到坐标有效
			{
				touchkey.x=(touch_key[0].x +touch_key[1].x)/2;
				touchkey.y=(touch_key[0].y +touch_key[1].y)/2;    
				
				touch_sta=0;                                     //不允许识别

			}
			else
			{
				touch_key[0].x=0xffff;
				touch_key[0].y=0xffff;
			}
		}
	}
	else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))
	{
		touch_sta = 1;                                   //允许识别
	}
	
	return touchkey;
}
void Touch_Adj_Init(void)
{
	float f1,f2;
	TOUCH_XY_TYPEDEF touch[4];
	
RE_ADJUST:
	//第一个点
	 LCD_Draw_SZ(20, 20, 0xf800);         //画一个十字
	while( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) )      
	{
		/* 等待触摸屏被按下 */
	}
	Delay_ms(10);                 //延时去抖
	touch[0]=Touch_Get_XY( );            //读取触摸屏的XY轴值
	while(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))   
	{
		/* 等待释放触摸屏 */
	}	
	LCD_Draw_SZ(20 ,20,0x07e0);           //清除第一个十字
	
	//第二个点
	LCD_Draw_SZ((320 - 20),20, 0xf800);       //画一个十字
	while( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) )      
	{
		/* 等待触摸屏被按下 */
	}
	Delay_ms(10);                     //延时去抖
	touch[1]=Touch_Get_XY( );                //读取触摸屏的XY轴值
	while(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))  
	{
		/* 等待释放触摸屏 */
	}	
	LCD_Draw_SZ((320 - 20), 20, 0x07e0);         //清除第二个十字
	
	//第三个点
	LCD_Draw_SZ(20, (480 - 20), 0xf800);         //画一个十字
	while( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) )      
	{
		/* 等待触摸屏被按下 */
	}
	Delay_ms(10);                       //延时去抖
	touch[2]=Touch_Get_XY( );                  //读取触摸屏的XY轴值
	while(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))  
	{
		/* 等待释放触摸屏 */
	}	
	LCD_Draw_SZ(20,(480 - 20), 0x07e0);           //清除第三个十字
	
	//第四个点
	LCD_Draw_SZ((320- 20), (480 - 20), 0xf800);     //画一个十字
	while( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) )      
	{
		/* 等待触摸屏被按下 */
	}
	Delay_ms(10);                         //延时去抖
	touch[3]=Touch_Get_XY( );                    //读取触摸屏的XY轴值
	while(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))  
	{
		/* 等待释放触摸屏 */
	}	
	LCD_Draw_SZ((320- 20), (480 - 20), 0x07e0);     //清除第四个十字
	
	//第 1 2点间的距离的平方
	f1=(touch[1].x-touch[0].x)*(touch[1].x-touch[0].x) +
	   (touch[1].y-touch[0].y)*(touch[1].y-touch[0].y);
	
	//第3 4点间的距离的平方
	f2=(touch[3].x-touch[2].x)*(touch[3].x-touch[2].x) +
	   (touch[3].y-touch[2].y)*(touch[3].y-touch[2].y);
	
	if(f1 / f2 > 1.1 || f1 / f2 < 0.9)
	{
		goto RE_ADJUST;
	}
	
	//第 1 3点间的距离的平方
	f1=(touch[2].x-touch[0].x)*(touch[2].x-touch[0].x) +
	   (touch[2].y-touch[0].y)*(touch[2].y-touch[0].y);
	
	//第2 4点间的距离的平方
	f2=(touch[3].x-touch[1].x)*(touch[3].x-touch[1].x) +
	   (touch[3].y-touch[1].y)*(touch[3].y-touch[1].y);
	
	if(f1 / f2 > 1.1 || f1 / f2 < 0.9)
	{
		goto RE_ADJUST;
	}
	
	//第 1 4点间的距离的平方
	f1 = (touch[3].x-touch[0].x)*(touch[3].x-touch[0].x) +
	     (touch[3].y-touch[0].y)*(touch[3].y-touch[0].y);
	
	//第2 3点间的距离的平方
	f2 = (touch[2].x-touch[1].x)*(touch[2].x-touch[1].x) +
	     (touch[2].y-touch[1].y)*(touch[2].y-touch[1].y);
	
	if(f1 / f2 > 1.1 || f1 / f2 < 0.9)
	{
		goto RE_ADJUST;
	}
	
	//求x方向的比例系数和偏移量
	touch_adj.kx =(float)((320 - 20) - 20) / (touch[3].x - touch[0].x);
	touch_adj.offset_x = 20 - touch_adj.kx * touch[0].x;
	//求y方向的比例系数和偏移量
	touch_adj.ky = (float)((480 - 20) - 20) / (touch[3].y - touch[0].y);
	touch_adj.offset_y = 20 - touch_adj.ky * touch[0].y;
}

int main(void)
{
	TOUCH_XY_TYPEDEF touch_lcd;
	usart_Init();
	LCD_Init();
	Touch_Init();
	Touch_Adj_Init();
	
	while(1)
	{
		if(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))
		{
			touch_lcd = Touch_Scanf();
			if(touch_lcd.x != 0xffff)                //正常识别到触摸屏
			{
				printf("x=%d\r\n",touch_lcd.x);
				printf("y=%d\r\n\r\n",touch_lcd.y);
			}
			touch_lcd.x = 0xffff;
		}	
	}
	
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(stm32)