一、触摸屏原理:
可以参考相关资料,本人参考的是阿南的<<>入门与实践>>中有关触摸屏的内容。
二、2440触摸屏的设置
1、ADCON: ADC 控制寄存器
#define ADCPRS 24
rADCCON=(1<<14)+(ADCPRS<<6);
使能读启动操作。
AD转换器的预分频值为24,注意:
AD转换频率=PCLK/(分频值+1),且AD的最高频率为2.5M,这里PCLK=50M,所以AD的转换频率为2M.
2、ADCTSC ADC 触摸屏控制寄存器
rADCTSC=0xd3;
当笔尖落下时触摸屏控制器产生中断 (INT_TC) 信号。
YM输出驱动器使能
YP输出驱动器禁止
XM输出驱动器禁止
XP输出驱动器禁止
等待中断模式
注意:自动x,y方向测量是指当测完x跟y后产生ADC中断。
3、ADCDLY ADC 启动或初始化延时寄存器
rADCDLY=50000;
设置一个适当的便可
4、设置中断服务函数
pISR_ADC = (int)AdcTsAuto; //设置中断函数地址
rINTMSK=~BIT_ADC; //ADC Touch Screen Mask bit clear
rINTSUBMSK=~(BIT_SUB_TC); //触摸屏中断
三、触摸屏检测及校正
1、触摸屏的检测思路类似于按键检测,以下为检测一个点的思路:
(1)、设置等待中断,按下有效
(2)、按下进入中断后读取x,y数据
(3)、读取完成后设置成弹起中断,等待一个动作结束
(4)、结束后进入下一次准备。
程序如下:
void __irq AdcTsAuto(void)
{
//解摸屏按下,产生中断
U32 saveAdcdly;
if(rADCDAT0&0x8000)
rADCTSC&=0xff; // Set stylus down interrupt bit
//关闭XP上拉,启动自动顺序x/y转换
rADCTSC=(1<<3)|(1<<2); //Pull-up disable, Seq. X,Y postion measure.
//设置延时时间
saveAdcdly=rADCDLY;
rADCDLY=40000;
//开始AD转换
rADCCON|=0x1; //start ADC
//AD转换启动后开始位会被清0
while(rADCCON & 0x1); //check if Enable_start is low
//等待转换结束
while(!(rADCCON & 0x8000)); //check if EC(End of Conversion) flag is high, This line is necessary~!!
//查询INT_ADC中断,直到查到结束中断标志
while(!(rSRCPND & (BIT_ADC))); //check if ADC is finished with interrupt bit
//产生中断标志说明x,y已经转换结束,读取数据。
xdata=(rADCDAT0&0x3ff);
ydata=(rADCDAT1&0x3ff);
//按下标志
touchedflag=TRUE;
//check Stylus Up Interrupt.
//清中断,并且重开中断,再次设置等待中断,这一次设置等待弹起中断。
rSUBSRCPND|=BIT_SUB_TC;
ClearPending(BIT_ADC);
rINTSUBMSK=~(BIT_SUB_TC);
rINTMSK=~(BIT_ADC);
rADCTSC =0xd3; //Waiting for interrupt
rADCTSC=rADCTSC|(1<<8); // Detect stylus up interrupt signal.
//查询等待弹起中断标志,直到查到弹起。
while(1) //to check Pen-up state
{
if(rSUBSRCPND & (BIT_SUB_TC)) //check if ADC is finished with interrupt bit
{
//Uart_Printf("Stylus Up Interrupt~!\n");
break; //if Stylus is up(1) state
}
}
//此时,一个触摸屏动作检测已经完成,输出坐标信息。
Uart_Printf("count=%03d XP=%d, YP=%d\n", count++, xdata, ydata); //X-position Conversion data
//再次设置成按下中断,等待下一次动作
rADCDLY=saveAdcdly;
rADCTSC=rADCTSC&~(1<<8); // Detect stylus Down interrupt signal.
rSUBSRCPND|=BIT_SUB_TC;
rINTSUBMSK=~(BIT_SUB_TC); // Unmask sub interrupt (TC)
ClearPending(BIT_ADC);
}
2、触摸屏的校正
触摸屏校正的目的是为了把触摸屏上的坐标跟LCD上坐标一一对应起来。
如上图,假设LCD与触摸屏的点是一一对应的,LCD上四个角的点为人为设置的点(实际只需要上左上跟右下两个点就可以了,还有两个点是用来做平均的),触摸屏上四个角的点为LCD上四个点对应转换来的数值。(ax,ay)为正常工作时点击的点,(x,y)为(ax,ay)对应的坐标。
那么LCD与触摸屏的关系为:
x=x0+(x1-x0)*(ax-ax0)/(ax1-ax0)
y=y0+(y1-y0)*(ay-ay0)/(ay1-ay0)
具体步骤:
以320*240的屏举例:
(1)、设置四个LCD点(30,30)、(30,210)、(290,210)、(290,30)
(2)、在屏幕上依次画出这四个点(以四个点为中心点的十字形),并且依次点击这四个点,分别记下四个点转换出来的数值。(ax0,ay0),(ax0,ax1),(ax1,ay1),(ax1,ay0)
(3)、由x=x0+(x1-x0)*(ax-ax0)/(ax1-ax0),可以把(x1-x0)/(ax1-ax0)转换成常量系数Kx,那么
x=x0+(ax-ax0)*Kx,Kx=(x1-x0)/(ax1-ax0) ,这样只需记下x0,ax0,Kx三个值便可。
同样的:
y=y0+(y1-y0)*(ay-ay0)/(ay1-ay0), y=y0+(ay-ay0)*Ky, Ky=(y1-y0)/(ay1-ay0),只需记下y0,ay0,Ky便可.
(4)、校正完成,正常工作时当点击触摸屏时产生(ax,ay),则
x=x0+(ax-ax0)*Kx
y=y0+(ay-ay0)*Ky
便可以很容易求出实际坐标。
校正程序如下:
//触摸屏校正
//x=x0+(x1-x0)*(ax-ax0)/(ax1-ax0)
//x=x0+(ax-ax0)*Kx
//Kx=(x1-x0)/(ax1-ax0)
//x0,ax0,Kx
//同理
//y=y0+(y1-y0)*(ay-ay0)/(ay1-ay0)
//y=y0+(ay-ay0)*Ky
//Ky=(y1-y0)/(ay1-ay0)
//y0,ay0,Ky
volatile U32 touchedflag=FALSE;
//必要的参数
typedef struct cali
{
int x0;
int ax0;
float Kx;
int y0;
int ay0;
float Ky;
}TCpara;
typedef struct Point
{
int x;
int y;
}POINT;
//LCD四个校正点
POINT LCDPoint[4]=
{
30 ,30, //左上
30 ,210, //左下
290 ,210, //右下
290 ,30 //右上
};
TCpara TCcal;
void touchsrc_calibration()
{
U32 i;
//int x=30,y=30;
//int LCDx1=30,LCDy1=30,LCDx2=30,LCDy2=150,LCDx3=290,LCDy3=210;
//TCx3=0,TCy3=0,TCx4=0,TCy4=0;
//float A,B,C,D,E,F,K;
//float K
Lcd_ClearScr(0);
for(i=0;i<4;i++)
{
//分别画出四个点 Glib_Line(LCDPoint[i].x-10,LCDPoint[i].y,LCDPoint[i].x+10,LCDPoint[i].y,(U32)(255<<11));
Glib_Line(LCDPoint[i].x,LCDPoint[i].y-10,LCDPoint[i].x,LCDPoint[i].y+10,(U32)(255<<11));
//等待按下
while(!touchedflag);
touchedflag=FALSE;
//分别记下LCD四个点对应的触摸屏的值,因为TQ2440触摸屏的x,接到了控制器的y上,y接到了x上,所以这里反过来记。
switch(i)
{
case 0:
TCx0+=ydata;
TCy0+=xdata;
break;
case 1:
TCx0+=ydata;
TCy1+=xdata;
break;
case 2:
TCx1+=ydata;
TCy1+=xdata;
break;
case 3:
TCx1+=ydata;
TCy0+=xdata;
break;
default:
break;
}
Lcd_ClearScr(0);
}
//得出左上与右下两个点的AD值,注意,其余两个点是为左上与右下两个点服务的。
TCx0=TCx0>>1;
TCx1=TCx1>>1;
TCy0=TCy0>>1;
TCy1=TCy1>>1;
//记下LCD初始点
TCcal.x0 =LCDPoint[0].x;
TCcal.y0 =LCDPoint[0].y;
//记下触摸屏初始点
TCcal.ax0=TCx0;
TCcal.ay0=TCy0;
//算出Kx,Ky
TCcal.Kx =(float)(LCDPoint[2].x-LCDPoint[0].x)/(TCx1-TCx0);
TCcal.Ky =(float)((LCDPoint[2].y)-LCDPoint[0].y)/(TCy1-TCy0);//(TCy0-TCy1);
Uart_Printf("TCcal.x0=%d,TCcal.y0=%d\n",TCcal.x0,TCcal.y0);
Uart_Printf("TCcal.ax0=%d,TCcal.ay0=%d\n",TCcal.ax0,TCcal.ay0);
Uart_Printf("TCcal.Kx=%d,TCcal.Ky=%d\n",TCcal.Kx,TCcal.Ky);
}
//打印坐标
void PrintTouchSrcPoint()
{
int TCx,TCy,x,y;
//等待按下
while(!touchedflag);
touchedflag=FALSE;
TCx=ydata;
TCy=xdata;
//算出x,y坐标
x=TCcal.x0+(TCx-TCcal.ax0)*TCcal.Kx;
y=TCcal.y0+(TCy-TCcal.ay0)*TCcal.Ky;
if((x>=0 && x<320) && (y>=0 && y<240))
{
//y=239-y;
Glib_Rectangle(x-1,y-1,x+1,y+1,(U32)(255<<11));
Glib_FilledRectangle(x-1,y-1,x+1,y+1,(U32)(255<<11));
}
Uart_Printf("x=%d,y=%d\n",x,y);
}
小结:
1、 通过本章学习,理解了四线电阻式触摸屏的原理。并且完成触摸屏检测与校正的实验。
2、 参考了阿南的<<>入门与实践>>中触摸屏部分以及网络资源。
上一篇:ucos II+ucGUI+s3c2410+LCD+触摸屏整合
下一篇:s3c2440硬件篇之八:ADC和触摸屏接口
推荐阅读最新更新时间:2024-03-16 15:22
- 热门资源推荐
- 热门放大器推荐