TQ2440之触摸屏

1.触摸屏原理

S3C2440A内置一个带8个模拟输入通道的10位逐次逼近型(recycling type)CMOS模数转换器。在2.5MHz的模数转换时钟频率下,转换速率可达到500KSPS(Kilo Samples Per Second),并且支持片内采样保持功能和省电模式。S3C2440A还带有触摸屏接口,可以控制/选择触摸屏的XP,XM,YP,YM输入以进行X,Y位置转换。

AD转换器频率=GCLK/(p+1);

AD转换时间=1/(AD转换器频率/5)=5*(p+1)/GCLK;

GCLK是系统主时钟频率,一般为50Mhz,p(0~255)是预分频值,除以5表示每次转换需要5个时钟周期。AD转换器的设计最大时钟频率为2.5MHz,在系统时钟为50Mhz、AD转换器时钟频率为2.5Mhz时,p最大为19;最大转换频率为0.5MHz,所以最大转换速率为0.5M个采样每秒,即500KSPS。

触摸屏有四种转换模式:

  • 普通转换模式:与普通AD转换器的使用一样,通过设置ADCCON来初始化,并以一个读和写ADCDAT0的操作完成。
  • X/Y分别转换模式:分为X位置转换模式和Y位置转换模式,这两种模式下,触摸屏分别把X、Y位置转换数据写入到ADCDAT0和ADCDAT1中之后,向中断控制器发起中断请求。
  • 自动X/Y位置转换:触摸屏依次转换X和Y位置,把转换的结果分别写入到ADCCON0和ADCDAT1中,然后向中断控制器发起中断请求。
  • 等待中断模式:设置ADCTSC为0xD3,当触控笔按下时,想中断控制器发起中断请求。本篇文章主要讲等待中断模式。

触摸屏初始化: 

#define ADCPRS 9
void Init_Touchpanel(void)
{   
    rADCDLY=50000; //ADC转换启动延时值
    rADCCON=(1<<14)+(ADCPRS<<6);   //预分频使能, 预分频值为ADCPRS
    rADCTSC=0xd3;  //等待中断模式

    pISR_ADC = (int)AdcTsAuto;//中断入口函数
    rINTMSK &= ~BIT_ADC;       //使能ADC中断
    rINTSUBMSK &= ~(BIT_SUB_TC);//使能ADC子中断
}

中断服务程序:

void __irq AdcTsAuto(void)
{
    U32 saveAdcdly;

    rADCTSC=(1<<3)|(1<<2);         //XP上拉禁止,自动测量x方向和y方向
    saveAdcdly=rADCDLY;
    rADCDLY=40000;                 //延时
    rADCCON|=0x1;                   //开始ADC转换
    while(rADCCON & 0x1);        //成功启动后此位被清零
    while(!(rADCCON & 0x8000));     //等待ADC转换结束        
    while(!(rSRCPND & (BIT_ADC)));  //等待ADC转换完成中断标志位
    xdata=(rADCDAT0 & 0x3ff);         //读取转换后的值
     ydata=(rADCDAT1 & 0x3ff);
    flagTS=1;//此标志用于触摸屏校准标志
    rSUBSRCPND|=BIT_SUB_TC;//清中断
    ClearPending(BIT_ADC);
    rINTSUBMSK&=~(BIT_SUB_TC);//使能中断
    rINTMSK&=~(BIT_ADC);
    rADCTSC =0xd3;    //再次设置成等待中断模式
    rADCTSC=rADCTSC|(1<<8); //检测笔尖抬起中断
    while(1)        //to check Pen-up state
    {
        if(rSUBSRCPND & (BIT_SUB_TC))    //监测到
        {
            break;//退出循环
        }
    }               

    rADCDLY=saveAdcdly; 
    rADCTSC=rADCTSC&~(1<<8); // 禁止检测笔尖抬起中断
    rSUBSRCPND|=BIT_SUB_TC;//清中断
    rINTSUBMSK&=~(BIT_SUB_TC);
    ClearPending(BIT_ADC);
}

2.触摸屏校准

我们在点击触摸屏时,实际上得到的是该点的电压值,而不是该点的位置坐标,需要一定的计算才能得到该点的实际坐标。

 这里介绍一下三点法校准。

设LCD上每个点PD的坐标为[XD,YD],触摸屏上每个点PT的坐标为[XT,YT]。要实现触摸屏上的坐标转换为LCD上的坐标,需要下列公式进行转换:

XD=A×XT+B×YT+C;YD=D×XT+E×YT+F;

因为其中一共有六个参数(A,B,C,D,E,F),因此只需要三个取样点就可以求得这六个参数。这六个参数一旦确定下来,只要给出任意触摸屏上的坐标点PT,代入这个公式,就可以得到它所对应的LCD上像素点的坐标PD。

已知LCD上的三个取样点为:PD0,PD1,PD2,它们所对应的触摸屏上的三个点为:PT0,PT1,PT2。A,B,C,D,E,F这六个参数最终的结果都是一个分式,而且都有一个共同的分母,为:K=(XT0-XT2)×(YT1-YT2)-(XT1-XT2)×(YT0-YT2)

那么这六个参数分别为:              

              A=[(XD0-XD2)×(YT1-YT2)-(XD1-XD2)×(YT0-YT2)] / K

              B=[(XT0-XT2)×(XD1-XD2)-(XD0-XD2)×(XT1-XT2)] / K

              C=[YT0×(XT2×XD1-XT1×XD2)+YT1×(XT0×XD2-XT2×XD0)+YT2×(XT1×XD0-XT0×XD1)] / K

              D=[(YD0-YD2)×(YT1-YT2)-(YD1-YD2)×(YT0-YT2)] / K

              E=[(XT0-XT2)×(YD1-YD2)-(YD0-YD2)×(XT1-XT2)] / K

              F=[YT0×(XT2×YD1-XT1×YD2)+YT1×(XT0×YD2-XT2×YD0)+YT2×(XT1×YD0-XT0×YD1)] / K

计算A、B、C、D、E、F的值 :

void TSCal(void)
{
    int i=0;
    int xt[3],yt[3];
    Lcd_ClearScr(0xFFFF);
    drawCross(32,24,0xFF0000);
    drawCross(160,216,0xFF0000);
    drawCross(288,120,0xFF0000);
    //依次读取三个采样点的坐标值
    for(i=0;i<3;i++)
    {     
        while(flagTS==0);
        xt[i]=xdata;
        yt[i]=ydata;
        Uart_Printf("xdata=%d\n",xdata);
        Uart_Printf("ydata=%d\n",ydata);
        flagTS=0;              
    }
    //计算参数
    K=(xt[0]-xt[2])*(yt[1]-yt[2])-(xt[1]-xt[2])*(yt[0]-yt[2]);
    A=(32-288)*(yt[1]-yt[2])-(160-288)*(yt[0]-yt[2]);
    B=(xt[0]-xt[2])*(160-288)-(32-288)*(xt[1]-xt[2]);
    C=yt[0]*(xt[2]*160-xt[1]*288)+yt[1]*(xt[0]*288-xt[2]*32)+yt[2]*(xt[1]*32-xt[0]*160);
    D=(24-120)*(yt[1]-yt[2])-(216-120)*(yt[0]-yt[2]);
    E=(xt[0]-xt[2])*(216-120)-(24-120)*(xt[1]-xt[2]);
    F=yt[0]*(xt[2]*216-xt[1]*120)+yt[1]*(xt[0]*120-xt[2]*24)+yt[2]*(xt[1]*24-xt[0]*216);
}

将计算出来的A、B、C、D、E、F的值存入EEPROM,0x1f地址存放是否存储过的标志位。读取0x1f地址的值赋予iic_buffer[0],如果iic_buffer[0]不等于0x55,证明数据没有存储到EEPROM,则计算A、B、C、D、E、F的值,并写入EEPROM,如果等于0x55证明数据已经写入EEPROM,直接读取即可,这样就不用每次都校验触摸屏了。

void CalcuateTouch(void)
{
    flagTS = 0;
    Rd24C080(0xa0,0x1f,&(iic_buffer[0]));
    if(iic_buffer[0]!=0x55)
    {
        TSCal();
        Wr24C080(0xa0,0x1f,0x55);
        iic_writekey(0xa0,0x20,A);
        iic_writekey(0xa0,0x30,B);
        iic_writekey(0xa0,0x40,C);
        iic_writekey(0xa0,0x50,D);
        iic_writekey(0xa0,0x60,E);
        iic_writekey(0xa0,0x70,F);
        iic_writekey(0xa0,0x80,K);        
    }
    else
    {
        A = iic_readkey(0xa0,0x20);
        B = iic_readkey(0xa0,0x30);
        C = iic_readkey(0xa0,0x40);
        D = iic_readkey(0xa0,0x50);
        E = iic_readkey(0xa0,0x60);
        F = iic_readkey(0xa0,0x70);
        K = iic_readkey(0xa0,0x80);
    }
    Lcd_ClearScr(0xFFFF);        
}

这时A、B、C、D、E、F的值都已经计算出来,将触摸屏ADC值带入公式就可以得到LCD上的物理位置。

posted @ 2013-11-13 00:01  zpehome  阅读(563)  评论(0编辑  收藏  举报