一、触摸屏原理:

    可以参考相关资料,本人参考的是阿南的<<>入门与实践>>中有关触摸屏的内容。

二、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、  参考了阿南的<<>入门与实践>>中触摸屏部分以及网络资源。