S3C2440 觸摸屏應用
在開始實現觸摸屏功能之前,還需要解決一個問題,那就是觸摸屏的校正。觸摸屏和LCD是兩種不同的物理器件。對于一個分辨率為320×240的LCD,它的寬度為320個像素,高度為240個像素。而觸摸屏處理的數據是點的物理坐標,該坐標是通過觸摸屏控制器采集得到的。要想實現觸摸屏上的物理坐標與LCD上的像素點坐標一一對應上,兩者之間就需要一定的轉換,即校正。而且電阻式觸摸屏由于自身的原因參數會發生變化,因此需要經常性的校正。比較常見的校正方法是三點校正法,它的原理是:
本文引用地址:http://www.104case.com/article/201611/319210.htm設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
下面的程序是實現觸摸屏功能的簡單實例——以觸點為中心,繪制出一個紅色的邊長為10個像素的正方形。觸點的坐標是用下面方法得到的:當觸筆落下時,進入中斷,然后讀取觸點處的坐標,直到觸筆的抬起,才退出該次中斷。由于觸摸屏需要校正,因此在使用之前需要進行校正處理。但并不是每次使用都要校正,只要坐標沒有發生漂移,就不需要再次校正。所以在進行一次校正后,只要把那幾個參數保存起來,下次需要時直接使用上次保存下來的參數即可。在這里,我們利用EEPROM來保存這幾個參數,即A,B,C,D,E,F,K分別保存在以0x20,0x30,0x40,0x50,0x60,0x70,0x80為首地址內存的連續4個字節空間內,另外內存地址0x1F保存一個標識信息,當為0x6A時,表示這幾個參數已計算并保存好了,只需從上述內存地址中讀取參數就行,而當為其他值時,就需要進行校正。校正時,需要三個取樣點,在這里我們選取LCD上的(32,24),(160,216),(288,120)為這三個取樣點,我們在這三個取樣點上畫一個十字(如下圖所示),只需要依次點擊這三個點,即可完成觸摸屏的校正。
以上文字從網上摘錄。覺得寫得不錯,當做筆記記下,我下面貼出的方法為裸奔三部曲中的方法,我驗證了一下,不錯,誤差很小了,不到4個像素點。下面只貼出觸摸屏初始化函數和中斷函數的代碼
- voidTouch_Init(void)
- {
- rADCDLY=50000;//正常轉換模式下延時
- rADCCON=(1<<14)|(ADCPRS<<6);//使能AD轉換預分頻器
- rADCTSC=0xd3;//等待中斷模式,正常AD轉換,XP上拉使能,XP,XM,YP輸出禁止,YM輸出使能
- if(rSRCPND&BIT_ADC)rSRCPND|=BIT_ADC;
- if(rINTPND&BIT_ADC)rINTPND|=BIT_ADC;
- if(rSUBSRCPND&BIT_SUB_TC)rSUBSRCPND|=BIT_SUB_TC;
- if(rSUBSRCPND&BIT_SUB_ADC)rSUBSRCPND|=BIT_SUB_ADC;//清除中斷標志
- rINTMSK&=~BIT_ADC;
- rINTSUBMSK&=~(BIT_SUB_TC);//使能中斷
- pISR_ADC=(unsigned)AdcTsAuto;//中斷服務程序入口
- }
- void__irqAdcTsAuto(void)
- {
- unsignedinti;
- U32PtX[6],PtY[6];
- shorttemp;
- if(rADCDAT0&0x8000)
- {
- rADCTSC&=0xff;//Setstylusdowninterruptbit
- }
- rADCTSC=(1<<3)|(1<<2);//XP上拉禁止,自動順序X,Y測量
- //rADCDLY=50000;
- rADCCON|=0x1;//使能AD轉換
- for(i=0;i<5;i++)
- {
- while(rADCCON&0x1);//判斷使能ADC轉換后被清零
- while(!(rADCCON&0x8000));//等待轉換結束
- while(!(rSRCPND&(BIT_ADC)));//checkifADCisfinishedwithinterruptbit
- PtX[i]=(rADCDAT0&0x3ff);
- PtY[i]=(rADCDAT1&0x3ff);
- }
- PtX[5]=(PtX[0]+PtX[1]+PtX[2]+PtX[3]+PtX[4])/5;
- PtY[5]=(PtY[0]+PtY[1]+PtY[2]+PtY[3]+PtY[4])/5;
- xdata=PtX[5];
- ydata=PtY[5];
- xdata*=0.272;
- ydata*=0.480;
- ydata=480-ydata;
- temp=ydata;
- ydata=xdata;
- xdata=temp;
- xdata=(xdata-20.0303)/0.8972;
- ydata=(ydata-37.86667)/0.7486;//將觸摸屏的AD轉換值轉換為LCD像素點的值
- //checkStylusUpInterrupt.
- rSUBSRCPND|=BIT_SUB_TC;
- ClearPending(BIT_ADC);
- rINTSUBMSK=~(BIT_SUB_TC);
- rINTMSK=~(BIT_ADC);//清中斷標志,再次使能中斷
- rADCTSC=0xd3;//再次設置等待中斷模式,這一次是判斷觸筆的抬起
- rADCTSC=rADCTSC|(1<<8);//檢測筆尖抬起中斷信號
- while(1)//tocheckPen-upstate
- {
- if(rSUBSRCPND&(BIT_SUB_TC))//checkifADCisfinishedwithinterruptbit
- {
- break;//ifStylusisup(1)state
- }
- }
- Uart_Printf("count=%03dXP=%04d,YP=%04dn",count++,xdata,ydata);//X-positionConversiondata
- //rADCDLY=50000;
- rADCTSC=rADCTSC&~(1<<8);//DetectstylusDowninterruptsignal.
- rSUBSRCPND|=BIT_SUB_TC;
- rINTSUBMSK=~(BIT_SUB_TC);//Unmasksubinterrupt(TC)
- ClearPending(BIT_ADC);//再次清A/D中斷
- }
評論