一、觸摸屏原理:
可以參考相關(guān)資料,本人參考的是阿南的<<>入門與實(shí)踐>>中有關(guān)觸摸屏的內(nèi)容。
二、2440觸摸屏的設(shè)置
1、ADCON: ADC控制寄存器
#define ADCPRS 24
rADCCON=(1<<14)+(ADCPRS<<6);
使能讀啟動操作。
AD轉(zhuǎn)換器的預(yù)分頻值為24,注意:
AD轉(zhuǎn)換頻率=PCLK/(分頻值+1),且AD的最高頻率為2.5M,這里PCLK=50M,所以AD的轉(zhuǎn)換頻率為2M.
2、ADCTSC ADC觸摸屏控制寄存器
rADCTSC=0xd3;
當(dāng)筆尖落下時觸摸屏控制器產(chǎn)生中斷(INT_TC)信號。
YM輸出驅(qū)動器使能
YP輸出驅(qū)動器禁止
XM輸出驅(qū)動器禁止
XP輸出驅(qū)動器禁止
等待中斷模式
注意:自動x,y方向測量是指當(dāng)測完x跟y后產(chǎn)生ADC中斷。
3、ADCDLY ADC啟動或初始化延時寄存器
rADCDLY=50000;
設(shè)置一個適當(dāng)?shù)谋憧?/p>
4、設(shè)置中斷服務(wù)函數(shù)
pISR_ADC = (int)AdcTsAuto;//設(shè)置中斷函數(shù)地址
rINTMSK=~BIT_ADC;//ADC Touch Screen Mask bit clear
rINTSUBMSK=~(BIT_SUB_TC); //觸摸屏中斷
三、觸摸屏檢測及校正
1、觸摸屏的檢測思路類似于按鍵檢測,以下為檢測一個點(diǎn)的思路:
(1)、設(shè)置等待中斷,按下有效
(2)、按下進(jìn)入中斷后讀取x,y數(shù)據(jù)
(3)、讀取完成后設(shè)置成彈起中斷,等待一個動作結(jié)束
(4)、結(jié)束后進(jìn)入下一次準(zhǔn)備。
程序如下:
void __irq AdcTsAuto(void)
{
//解摸屏按下,產(chǎn)生中斷
U32 saveAdcdly;
if(rADCDAT0&0x8000)
rADCTSC&=0xff;// Set stylus down interrupt bit
//關(guān)閉XP上拉,啟動自動順序x/y轉(zhuǎn)換
rADCTSC=(1<<3)|(1<<2);//Pull-up disable, Seq. X,Y postion measure.
//設(shè)置延時時間
saveAdcdly=rADCDLY;
rADCDLY=40000;
//開始AD轉(zhuǎn)換
rADCCON|=0x1;//start ADC
//AD轉(zhuǎn)換啟動后開始位會被清0
while(rADCCON & 0x1);//check if Enable_start is low
//等待轉(zhuǎn)換結(jié)束
while(!(rADCCON & 0x8000));//check if EC(End of Conversion) flag is high, This line is necessary~!!
//查詢INT_ADC中斷,直到查到結(jié)束中斷標(biāo)志
while(!(rSRCPND & (BIT_ADC)));//check if ADC is finished with interrupt bit
//產(chǎn)生中斷標(biāo)志說明x,y已經(jīng)轉(zhuǎn)換結(jié)束,讀取數(shù)據(jù)。
xdata=(rADCDAT0&0x3ff);
ydata=(rADCDAT1&0x3ff);
//按下標(biāo)志
touchedflag=TRUE;
//check Stylus Up Interrupt.
//清中斷,并且重開中斷,再次設(shè)置等待中斷,這一次設(shè)置等待彈起中斷。
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.
//查詢等待彈起中斷標(biāo)志,直到查到彈起。
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
}
}
//此時,一個觸摸屏動作檢測已經(jīng)完成,輸出坐標(biāo)信息。
Uart_Printf("count=%03dXP=%d, YP=%dn", count++, xdata, ydata);//X-position Conversion data
//再次設(shè)置成按下中斷,等待下一次動作
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、觸摸屏的校正
觸摸屏校正的目的是為了把觸摸屏上的坐標(biāo)跟LCD上坐標(biāo)一一對應(yīng)起來。
如上圖,假設(shè)LCD與觸摸屏的點(diǎn)是一一對應(yīng)的,LCD上四個角的點(diǎn)為人為設(shè)置的點(diǎn)(實(shí)際只需要上左上跟右下兩個點(diǎn)就可以了,還有兩個點(diǎn)是用來做平均的),觸摸屏上四個角的點(diǎn)為LCD上四個點(diǎn)對應(yīng)轉(zhuǎn)換來的數(shù)值。(ax,ay)為正常工作時點(diǎn)擊的點(diǎn),(x,y)為(ax,ay)對應(yīng)的坐標(biāo)。
那么LCD與觸摸屏的關(guān)系為:
x=x0+(x1-x0)*(ax-ax0)/(ax1-ax0)
y=y0+(y1-y0)*(ay-ay0)/(ay1-ay0)
具體步驟:
以320*240的屏舉例:
(1)、設(shè)置四個LCD點(diǎn)(30,30)、(30,210)、(290,210)、(290,30)
(2)、在屏幕上依次畫出這四個點(diǎn)(以四個點(diǎn)為中心點(diǎn)的十字形),并且依次點(diǎn)擊這四個點(diǎn),分別記下四個點(diǎn)轉(zhuǎn)換出來的數(shù)值。(ax0,ay0),(ax0,ax1),(ax1,ay1),(ax1,ay0)
(3)、由x=x0+(x1-x0)*(ax-ax0)/(ax1-ax0),可以把(x1-x0)/(ax1-ax0)轉(zhuǎn)換成常量系數(shù)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)、校正完成,正常工作時當(dāng)點(diǎn)擊觸摸屏?xí)r產(chǎn)生(ax,ay),則
x=x0+(ax-ax0)*Kx
y=y0+(ay-ay0)*Ky
便可以很容易求出實(shí)際坐標(biāo)。
校正程序如下:
//觸摸屏校正
//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;
//必要的參數(shù)
typedef struct cali
{
intx0;
intax0;
floatKx;
inty0;
intay0;
floatKy;
}TCpara;
typedef struct Point
{
int x;
int y;
}POINT;
//LCD四個校正點(diǎn)
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++)
{
//分別畫出四個點(diǎn)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