一.触摸屏的分类:
1、触摸屏种类、分别应用在哪里、屏和OS怎么配合使用?.
电容屏---静电感应;电阻屏---压力感应;
红外线式和感应电容式触摸屏能够支持多点触控。多点触控带来了更多的选择,抓取、拖曳、缩放、旋转。
屏要和系统搭配才能体现优势。IPHONE和android系统支持多点触控。Windows mobiles不支持多点触控。
2,触摸屏实现原理,功能实现出来(点一下触摸屏得到对应点的像素值)。总结实现原理。
触摸屏的坐标值和LCD的像素不是一比一的关系。且原点可能不是同一个角。
触摸屏校验2种方式:第一是4点式(2点式)。第二种三点式。
二.下面是SONY(320*240)的屏.
从图中我们可以看出,1(Y) 2(X)接的是低电平,3(Y)4(X)接的是高电平,本来四根线是没有交集的,但是当人触摸屏的时候,四根线就有交叉了,这样的话就连通了,就能找到相应的点的坐标了。
三.驱动设计.
从S3C2440规格书中我们可以看到:A/D转换最大的速率可达到500KSPS,转换的最大时钟频率为2.5MHZ。
在本程序中我们使转换的时钟频率为1MHZ,在S3C2440的规格书中我们可以看到这样的一个公式:
A/D converter freq = PCLK/(prescaler value+1). 因为PCLK=50MHZ,我们可以设prescaler value的值为49,这样的话,A/D转换的频率就可以设为1MHZ了,符合规格书中最大值为2.5MHZ的范围。
这样,我们可以算出:conversion time = 1/(1MHZ/5cycles)=1/200KHZ=5us.
从下图可以知道:
在触摸笔点下或者触摸笔起来的时候,INT_TC中断都会产生,当A/D转换成功后,会产生INT_ADC,所以ADC中断有两个子中断:INT_TC INT_ADC。
四线制的电阻触摸屏驱动实现要点:
1.封装初始化函数:touch_init 配置好等待触笔按下的中断,安装触笔按下中断的服务函数。
2.封装中断处理函数:当有触笔按下的时候,自动调用中断处理函数,在该函数中:
(1)、按下进入中断后设置AD转换启动,等待AD转换OK产生中断,
读取x,y触屏的坐标值,并设置中断标志。
(2)、读取完成后设置成弹起中断,并等待弹起中断产生
(3)、重新设置中断环境,让笔点下能产生中断
MINI2440触摸屏驱动设计的主要代码实现:
/************************************************
NAME : TOUCHSCREEN.C
DESC :
Revision: 2015.8.27 ver 0.0
************************************************/
#include "touchscreen.h"
#include "uart.h"
#include "lcd.h"
#include "image.h"
#include "pwm.h"
#include "iic.h"
unsigned int x_touch,y_touch,xdata_down,ydata_down;
unsigned int Count=0;
int TCx0=0,TCy0=0,TCx1=0,TCy1=0;
float Kx,Ky; // 触摸屏坐标与LCD像素的换算比例
volatile U32 touchedflag=FALSE;
unsigned int xy1[5];
float xscale,yscale,x_offset,y_offset;
//LCD四个校正点
POINT LCDPoint[4]=
{
20 ,20, //左上
20 ,300, //左下
220 ,300, //右下
220 ,20 //右上
};
/***********************************************
Function name : touch_init
Description : 触摸屏初始化
Input parameter : none
Return : none
Others : none
*************************************************/
void touch_init()
{
//1.A/D converter prescaler enable prscvl is 49
rADCCON = (1<<14)|(49<<6);
//2.ADCDLY = 50000;
rADCDLY = 50000;
//3.configure the interrupt enable the INT_TC disable the ADC_INT
rINTMSK &= ~(1<<31);
rINTSUBMSK &= ~(1<<9);
rINTMOD &= ~(1<<31);
rSUBSRCPND |= (1<<9);
rSRCPND |= (1<<31);
rINTPND |= (1<<31);
//4wait for interrupt mode (touch down)
rADCTSC = 0xd3; //从规格书中可以获取到的信息.
//loading the interrupt address
pISR_ADC = (unsigned int)touch_handle;
}
/***********************************************
Function name : touch_handle
Description : 触摸屏中断处理函数
Input parameter : none
Return : none
Others : none
*************************************************/
void __irq touch_handle()
{
//clear the sub_ADC interrupt
rSUBSRCPND |= (1<<10);
rSRCPND |= (1<<31);
rINTPND |= (1<<31);
//Auto sequential measurement of X-position Y-position A/D convertion start,
// mode cleared(No operation Mode)
rADCTSC |= (1<<3)|(1<<2)&(~3);
rADCCON |= (1<<0); //start ADC
//wait for A/D convertion
while(rADCCON & 0x1); //check if the Enable_start is low AD转换后开始位会自动清零
while(!(rADCCON & (1<<15)));
while(!(rSUBSRCPND&(1<<10))); //check if the ADC interrupt is finished
//read the x_touch,y_touch
x_touch = (int)(rADCDAT0 &(0x3ff));
y_touch = (int)(rADCDAT1 &(0x3ff));
touchedflag = TRUE;
//uart_printf("x=%d y=%d\n",x_touch,y_touch);
//Count++;
//touch_correct
//if(Count==1||Count==3||Count==2||Count==4)
//touch_correct();
//printf the coordinate after the touch_correct
//if(Count>=5)
//{
// xdata_down = x_touch*xscale-x_offset;
// ydata_down = y_touch*yscale-y_offset;
// uart_printf("x=%d y=%d\n",xdata_down,ydata_down);
//}
//clear the interrupt
rSUBSRCPND |= (1 <<9);
rSRCPND |= (1 << 31);
rINTPND |= (1 << 31);
//detect stylus Up interrupt
rADCTSC = 0xd3;
rADCTSC |= (1 << 8);
//wait for tc interrupt mode (touch up)
while(!(rSUBSRCPND & (1 << 9)));
//clear the touch up interrupt
rSUBSRCPND |= (1 <<9);
rSRCPND |= (1 << 31);
rINTPND |= (1 << 31);
//wait for interrupt mode (touch down)
rADCTSC = 0xd3;
}
void delay(int n)
{
int i,j;
for(i=0;i<n*1000;i++)
for(j=0;j<n*1000;j++);
}
/***********************************************
Function name : touch_correct
Description : 触摸屏矫正
Input parameter : none
Return : none
Others : none
*************************************************/
void touch_correct()
{
U32 i;
Lcd_clear(0xffffff); //清频
for(i=0;i<4;i++)
{
Draw_Cross(LCDPoint[i].x,LCDPoint[i].y);
while(!touchedflag);
touchedflag=FALSE;
switch(i)
{
case 0:
TCx0+=x_touch; // 记录触点的坐标
TCy0+=y_touch;
break;
case 1:
TCx0+=x_touch;
TCy1+=y_touch;
break;
case 2:
TCx1+=x_touch;
TCy1+=y_touch;
break;
case 3:
TCx1+=x_touch;
TCy0+=y_touch;
break;
default:
break;
}
Lcd_clear(0xffffff);
}
TCx0=TCx0>>1;
TCy0=TCy0>>1;
TCx1=TCx1>>1;
TCy1=TCy1>>1;
Kx =(float)(TCx0-TCx1)/(LCDPoint[2].x-LCDPoint[0].x);
Ky =(float)(TCy1-TCy0)/((LCDPoint[2].y)-LCDPoint[0].y);
Lcd_clear(0xffffff);
lcd_Slow4Paint_Bmp(gImage_apple6);
delay(2);
lcd_Slow3Paint_Bmp(gImage_apple1);
}
void get_touch()
{
float temp;
while(!touchedflag);
touchedflag=FALSE;
// iic_write_float(0xa0,0,Kx);
//iic_write_float(0xa0,4,Ky);
//iic_write_int(0xa0,8,TCx0);
//iic_write_int(0xa0,12,TCy0);
iic_read_float(0xa0,0,&Kx);
iic_read_float(0xa0,4,&Ky);
iic_read_int(0xa0,8,&TCx0);
iic_read_int(0xa0,12,&TCy0);
xdata_down=LCDPoint[0].x+(TCx0-x_touch)/Kx;
ydata_down=LCDPoint[0].y+(y_touch-TCy0)/Ky;
//Draw_Cross(xdata_down,ydata_down);
uart_printf("x=%d,y=%d\n",xdata_down,ydata_down);
}
关于触摸屏的校准:
对于这块sony的触摸屏,可以测试出该触摸屏的原点和LCD的原点不在同一个点,LCD的原点在左上方,而触摸屏的原点在右上方,所以这样我们需要有一个方法将LCD和触摸屏一一对应起来,那就需要校准了.
首先我们在LCD上取四个点:就取四个角上的点。然后用变量TCX0,TCX1,TCY0,TCY1来保存触点的坐标,取出左边上和左下的平均值,再取右上和右下边的平均值,最后就可以算出LCD和触摸屏坐标的转换比例了。
Kx =(float)(TCx0-TCx1)/(LCDPoint[2].x-LCDPoint[0].x);
Ky =(float)(TCy1-TCy0)/((LCDPoint[2].y)-LCDPoint[0].y); 这里要注意结果不要是负的,注意触摸屏的原点位置。
(TCx0>TCx1,TCy1>TCy0).
最后我们可以运用以下的公式来:
xdata_down=LCDpoint[0].x+(TCx0-x_touch)/Kx;
ydata_down=LCDpoint[0].y+(y_touch-TCy0)/Ky;
如下图所示: