触摸屏

最近几天研究了下触摸屏,发现也并不像感觉中的那么神秘。本人用的触摸屏方案是 4线电阻屏+xpt2046(这个和ADS7843完全一样)。控制过程主要分一下几步:1,读数——这里读出来的是触摸屏控制芯片的AD值,是屏的物理坐标2,滤波——触摸屏类似按键,按下和放开时会有抖动3,转化——把屏的物理坐标转化成逻辑坐标,这里的逻辑坐标在LCD的范围内对应LCD的像素点坐标。4,定位——触摸屏的定位,这个其实应该放到最开始。读数:这里按照控制芯片的时序使用管脚模拟SPI的方式读出来的,用过STM32的SPI,也可以,不过习惯模拟,不用那么复杂的配置了。(程序见后面部分)滤波:这里使用了2种方式的滤波,一种是像按键一样,检测到控制芯片INT引脚变低之后,延时20ms,然后如果在检测还是为低,则是真正的按下。第二种是软件滤波,程序读取了10次触摸屏的物理坐标,然后冒泡排序,最后去掉最前面的和最后面的,只保留中间3个,再对中间3个取平均。(程序见后面部分)转化:这个很简单,在任何一个介绍触摸屏的文章估计都能见到。xp——x的物理坐标 xl—— x的逻辑坐标 LCDXSIZE ——LCD的x方向做大值 xpmin —— 在LCD(0,0)坐标处的x的物理坐标 xpmax LCD最大处x物理坐标yp——y的物理坐标 yl—— y的逻辑坐标 LCDYSIZE ——LCD的y方向最大值 ypmin —— 在LCD(0,0)坐标处的y的物理坐标 ypmax LCD最大处y物理坐标xl = (xp-xpmin)*LCDXSIZE/(xpmax-xpmin)yl = (yp-ypmin)*LCDYSIZE/(ypmax-ypmin)定位:这里定位的作用是求处上面的xpmin,xpmax,ypmin和ypmax,方法就是在屏幕上知道2点,求这两点所在直线上的一点(而且知道要求点的某一个坐标)在屏上分别画出4个点,其实3个点足以,但是一般都用4个点,取得这四个点的物理坐标。假设分别为: | | --x1,y1-------------------x2,y2---- | | --x3,y3-------------------x4,y4---- | |对应的物理坐标为 cx1,cy1 cx2,cy2, cx3,cy3 cx4,cy4利用比例关系 x1/(cx1-xpmin) = x2/(cx2-xpmin) —————————————— 这里x1和x2不相等可以求出xpmin,同样用比例关系 x2/(cx2-xpmin) = LCDXSIZE/(xpmax-xpmin)———————————— 这里最好x2>x1,更准些可以求出xpmax然后用同样的方法求出ypmin和ypmax_____________________________________________________分割线__________________________________________________________________————————————————————————————————————————————————————————————————用中断读控制芯片的INT引脚还是用定时器读?用中断比较节省资源,但是我在做一个画图板的时候,发现滑动坐标没办法求出来,于是就去想定时器读。用定时器读有个好处:延时操作可以在定时器里设置一个标志字,然后如果有按下就置位这个标志,下次再去真正读取。 定时器里可以给触摸屏设置多种不同的状态,这里按照Windows的情况设置了down,move,up还有none4种状态这样用定时器解决了一个消抖和滑动坐标检测的问题,我选择定时器。无图无真相,无码无真相:下面是真相(原文件名:touch.jpg) 头文件::#ifndef __TOUCH_H__#define __TOUCH_H__#include "stm32f10x_lib.h"enum{ TOUCH_NONE=0, // TOUCH_DOWN, TOUCH_MOVE, TOUCH_UP,};#define TOUCH_CLK_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_13)#define TOUCH_CLK_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_13)#define TOUCH_DOUT_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_15)#define TOUCH_DOUT_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_15)#define TOUCH_READ_DIN() GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14)#define TOUCH_CS_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_12) #define TOUCH_CS_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_12)#define TOUCH_READ_INT() GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_7)#define TOUCH_READ_BUSY() GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_8) #define TOUCH_CHX 0x90 //差分方式读取#define TOUCH_CHY 0xD0#define TOUCH_GETTIMES 10extern vu16 TouchX, TouchY;extern vu8 TouchPress,TouchState;extern u8 TouchCalibrated;void Touch_Init(void);u16 Touch_GetX(void);u16 Touch_GetY(void);void Touch_Calibrate(void);void Touch_GetState(void);#endifC文件::#include "Touch.h"#include "systick.h"#include "Graphics.h"vu16 TouchX, TouchY;vu8 TouchPress=0, TouchState=TOUCH_NONE; //state有4种状态,0无按键,1按下,2抬起,3moveu8 TouchCalibrated = 0;u16 TouchXMin, TouchXMax, TouchYMin, TouchYMax;/********************************初始化触摸屏需要的端口芯片--TSC2046********************************/void Touch_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; //EXTI_InitTypeDef EXTI_InitStructure; //NVIC_InitTypeDef NVIC_InitStructure; //SPI_InitTypeDef SPI_InitStructure; /* Enable GPIOB, GPIOC and AFIO clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO, ENABLE); //RCC_APB2Periph_AFIO //RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); //SPI GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); //SPI_MISO GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPIO_InitStructure); /* CS pins configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); /*INI Pin*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOG, &GPIO_InitStructure);/* SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟空闲为低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //上升沿所存 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; SPI_Init(SPI2, &SPI_InitStructure); SPI_Cmd(SPI2,ENABLE); */#if 0 EXTI_ClearITPendingBit(EXTI_Line7); GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource7); /* Configure Button EXTI line */ EXTI_InitStructure.EXTI_Line = EXTI_Line7; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure);#endif}/*=====================================================================*/u16 Touch_AdjY(u16 adx) //240{ u16 sx=0; int r = adx - TouchYMin; r *= 240; sx=r / (TouchYMax - TouchYMin); if (sx>=240) return 0xFFFF; return sx;}u16 Touch_AdjX(u16 ady) //320{ u16 sy=0; int r = ady - TouchXMin; r *= 320; sy=r/(TouchXMax - TouchXMin); if (sy>=320) return 0xFFFF; return sy;}u16 Touch_Read(u8 cmd){ u8 i; u16 pos=0; TOUCH_CLK_LOW(); TOUCH_CS_LOW(); for(i=0; i<8; i++) { if(cmd&0x80) TOUCH_DOUT_HIGH(); else TOUCH_DOUT_LOW(); cmd <<= 1; TOUCH_CLK_HIGH(); TOUCH_CLK_LOW(); } Delay(50); for(i=0; i<12 ;i++) { pos <<= 1; TOUCH_CLK_HIGH(); if(TOUCH_READ_DIN() == Bit_SET) pos |= 0x01; TOUCH_CLK_LOW(); } TOUCH_CS_HIGH(); return pos;}u16 Touch_GetX(void){ u8 count=0, i,j; u16 pos[TOUCH_GETTIMES]={0}; u16 res=0xffff, temp; while((count<TOUCH_GETTIMES)&&(TOUCH_READ_INT() == Bit_RESET)) { count++; //TOUCH_CS_LOW(); //选中器件 //SPI_I2S_SendData(SPI2,TOUCH_CHX); // //while(TOUCH_READ_BUSY() == Bit_SET); //等待busy信号 //pos[count] = (u8 )SPI_I2S_ReceiveData(SPI2); //TOUCH_CS_HIGH(); pos[count] = Touch_Read(TOUCH_CHX); } if(count < TOUCH_GETTIMES) //干扰,丢弃 return res; for(i=0; i<TOUCH_GETTIMES-1; i++) { for(j=0; jpos[j+1]) { temp = pos[j]; pos[j] = pos[j+1]; pos[j+1] = temp; } } } res = (pos[TOUCH_GETTIMES/2-1]+pos[TOUCH_GETTIMES/2]+pos[TOUCH_GETTIMES/2+1])/3; if(TouchCalibrated==1) //已经校准过了,否则这里只输出物理值 res = Touch_AdjX(res); return res; }u16 Touch_GetY(void){ u8 count=0, i,j; u16 pos[TOUCH_GETTIMES]={0}; u16 res = 0xffff, temp; while((count<TOUCH_GETTIMES)&&(TOUCH_READ_INT() == Bit_RESET)) { count++; // TOUCH_CS_LOW(); //选中器件 //SPI_I2S_SendData(SPI2,TOUCH_CHY); // //while(TOUCH_READ_BUSY() == Bit_SET); //等待busy信号 //pos[count] = (u8 )SPI_I2S_ReceiveData(SPI2); //TOUCH_CS_HIGH(); pos[count] = Touch_Read(TOUCH_CHY); } if(count < TOUCH_GETTIMES) //干扰,丢弃 return 0xffff; for(i=0; i<TOUCH_GETTIMES-1; i++) { for(j=0; jpos[j+1]) { temp = pos[j]; pos[j] = pos[j+1]; pos[j+1] = temp; } } } res = (pos[TOUCH_GETTIMES/2-1]+pos[TOUCH_GETTIMES/2]+pos[TOUCH_GETTIMES/2+1])/3; if(TouchCalibrated==1) //已经校准过了,否则这里只输出物理值 res = Touch_AdjY(res); return res; }void Touch_Calibrate(void){ u16 x[4] = {30, 290, 30, 290}; u16 y[4] = {20, 20, 220, 220}; u16 cx[4],cy[4], tempx[2], tempy[2]; u8 i; u16 color; //画出需要的点,然后点击 TouchXMin = 0; TouchYMin = 0; color = GetColor(); SetColor(BLUE); ClearDevice(); while(TRUE) { for(i=0; i<4 i="" 5="" setcolor="" red="" fillcircle="" x="" y="" 3="" while="" touchpress="=0)||(TouchState!=TOUCH_DOWN));" touchpress="0;" cx="TouchX;" cy="TouchY;" setcolor="" blue="" cleardevice="" tempx="" 0="" 290="" cx="" 0="" -30="" cx="" 1="" 260="" tempx="" 1="" 290="" cx="" 2="" -30="" cx="" 3="" 260="" tempy="" 0="" 220="" cy="" 0="" -20="" cy="" 2="" 200="" tempy="" 1="" 220="" cy="" 1="" -20="" cy="" 3="" 200="" if="" tempx="" 0="">tempx[1]-20) && ((tempx[0]tempy[1]-20) && ((tempy[0]<tempy[1]+20))) { TouchYMin = (tempy[0]+tempy[1])/2; } if(TouchXMin != 0 && TouchYMin !=0) { TouchXMax = (cx[1]-TouchXMin)*320/290 + TouchXMin; TouchYMax = (cy[2]-TouchYMin)*240/220 + TouchYMin; break; } } SetColor(color); TouchCalibrated = 1;}void Touch_GetState(void) //定时器里调用{ u16 x, y; static BOOL islow = FALSE; if(TOUCH_READ_INT() != Bit_RESET) //没有按下的情况下,如果之前是按下的,则 { //是抬起 if((TouchState == TOUCH_DOWN)||(TouchState == TOUCH_MOVE)) { TouchState = TOUCH_UP; TouchPress = 1; } else TouchState = TOUCH_NONE; return; } else { if(islow == FALSE) islow = TRUE; else { x = Touch_GetX(); y = Touch_GetY(); if((x != 0xffff) && (x != 0xffff)) //有真的按下 { switch(TouchState) { case TOUCH_NONE: //原来没有按下,现在一定是按下了 TouchState = TOUCH_DOWN; break; case TOUCH_DOWN: //原来按下了,现在一定是move了 TouchState = TOUCH_MOVE; break; case TOUCH_MOVE: //之前是move,现在还是move break; case TOUCH_UP: //之前是up,这种情况应该不会出现 default: TouchState = TOUCH_NONE; break; } TouchX = x; TouchY = y; TouchPress = 1; } islow = FALSE; } } }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值