STM32学习笔记一一触摸屏
前言:
為了方便查看博客,特意申請了一個公眾號,附上二維碼,有興趣的朋友可以關(guān)注,和我一起討論學(xué)習(xí),一起享受技術(shù),一起成長。
1. 簡介
1.1 電阻式觸摸屏
電阻式觸摸屏利用壓力感應(yīng)進行觸點檢測控制,需要直接應(yīng)力接觸, 通過檢測電阻來定位觸摸位置 。
1.1.1 電阻式觸摸屏的原理
電阻觸摸屏的主要部分是一塊與顯示器表面非常配合的電阻薄膜屏,這是一種多層的復(fù)合薄膜,它以一層玻璃或硬塑料平板作為基層,表面涂有一層透明氧化金屬(透明的導(dǎo)電電阻)導(dǎo)電層,上面再蓋有一層外表面硬化處理、光滑防擦的塑料層、它的內(nèi)表面也涂有一層涂層、在他們之間有許多細小的(小于 1/1000 英寸)的透明隔離點把兩層導(dǎo)電層隔開絕緣。
當手指觸摸屏幕時,兩層導(dǎo)電層在觸摸點位置就有了接觸,電阻發(fā)生變化,在 X 和 Y 兩個方向上產(chǎn)生信號,然后送觸摸屏控制器??刂破鱾蓽y到這一接觸并計算出( X Y )的位置,再根據(jù)獲得的位置模擬鼠標的方式運作。
電阻式觸摸屏都需要一個AD 轉(zhuǎn)換器, 所以一般來說驅(qū)動屏幕需要一個控制器芯片。這種屏幕可以用四線、五線、七線或八線來產(chǎn)生屏幕偏置電壓,同時讀回觸摸點的電壓。
1.1.2 電阻式觸摸屏得到觸點坐標
如上圖所示,但在 X 軸方向的點極施加一定的電壓,而 Y 軸方向不加電壓時,在 X 軸的平行電場中,觸點處的電壓值可以在 Y 軸的測量點得到,知道了測量點處 Y 軸的電壓(X對地電阻的電壓),也就確定了 X 軸上的坐標;同理,當 Y 軸方向施加固定的電壓時,可在 X 軸的測量點上得到對應(yīng)的電壓。經(jīng)過兩次的測量,就可以得出觸點(X,Y)的坐標了。
1.1.3 電阻式觸摸屏的優(yōu)缺點
優(yōu)點: 精度高、價格便宜、抗干擾能力強、穩(wěn)定性好 。
缺點: 容易被劃傷、透光性不太好、不支持多點觸摸。直接的感覺就是體驗不如電容屏幕。
1.2 電容式觸摸屏
電容屏利用人體感應(yīng)進行觸點檢測控制,不需要直接接觸或只需要輕微接觸,通過檢測感應(yīng)電流來定位觸摸坐標 。
當手指點擊屏幕,會從接觸點吸收小量電流,造成角落電極的壓降,利用感應(yīng)人體微弱電流的方式來達到觸控的目的。
1.2.1 表面電容式電容觸摸屏
表面電容式觸摸屏技術(shù)是利用 ITO 銦錫氧化物,是 一種透明的導(dǎo)電材料導(dǎo)電膜,通過電場感應(yīng)方式感測屏幕表面的觸摸行為進行。但是表面電容式觸摸屏有一些局限性,它只能識別一個手指或者一次觸摸。
1.2.2 投射式電容觸摸屏
投射電容式觸摸屏是傳感器利用觸摸屏電極發(fā)射出靜電場線。一般用于投射電容傳感技術(shù)的電容類型有兩種: 自我電容和交互電容 。
自我電容: 又稱絕對電容,自我電容通常是指掃描電極與地構(gòu)成的電容。在玻璃表面有用 ITO 制成的橫向與縱向的掃描電極,這些電極和地之間就構(gòu)成一個電容的兩極。當用手或觸摸筆觸摸的時候就會并聯(lián)一個電容到電路中去,從而使在該條掃描線上的總體的電容量有所改變。在掃描的時候,控制 IC 依次掃描縱向和橫向電極,并根據(jù)掃描前后的電容變化來確定觸摸點坐標位置。筆記本電腦觸摸輸入板就是采用的這種方式。筆記本電腦的輸入板采用 X*Y 的傳感電極陣列形成一個傳感格子, 當手指靠近觸摸輸入板時,在手指和傳感電極之間產(chǎn)生一個小量電荷。采用特定的運算法則處理來自行、列傳感器的信號來確定手指的位置。
交互電容: 又叫做跨越電容,它是在玻璃表面的橫向和縱向的 ITO 電極的交叉處形成電容。交互電容的掃描方式就是掃描每個交叉處的電容變化,來判定觸摸點的位置。當觸摸的時候就會影響到相鄰電極的耦合,從而改變交叉處的電容量,交互電容的掃面方法可以偵測到每個交叉點的電容值和觸摸后電容變化,因而它需要的掃描時間與自我電容的掃描方式相比要長一些,需要掃描檢測 X*Y 根電極。 目前智能手機 平板電腦等的觸摸屏 ,都是采用 交互電容技術(shù)。
1.2.3 投射式電容觸摸屏——交互電容詳解
投射式電容觸摸屏采用縱橫兩列電極組成感應(yīng)矩陣,來感應(yīng)觸摸。以兩個交叉的電極矩陣,即: X 軸電極和 Y 軸電極,來檢測每一 格感應(yīng)單元的電容變化 。
如下圖,當手指觸碰到屏幕的時候,人體自身的感應(yīng)電流會引起屏幕上排布的電容的變化,進而讓處理器知道有觸摸動作發(fā)生,得到觸摸點坐標。
X 、 Y 軸的透明電極電容屏的精度、分辨率與 X 、 Y 軸的通道數(shù)有關(guān),通道數(shù)越多,精度越高。
1.2.4 電容式觸摸屏的優(yōu)缺點
優(yōu)點: 手感好、無需校準、支持多點觸摸、透光性好;
缺點: 成本高、精度不高、抗干擾能力差。
2. 電容觸摸驅(qū)動 IC——OTT2001A介紹
OTT2001A ,最多支持 208 個通道。支持 SPI/IIC 接口。 IIC 接口模式下,該驅(qū)動 IC 與 STM32 的連接僅需要 4 根線: SDA 、 SCL 、 RST 和 INT,SDA 和 SCL 是 IIC 通信用的, RST 是復(fù)位腳(低電平有效), INT 是中斷輸出信號。
2.1 寄存器介紹
(1)手勢 ID 寄存器
手勢 ID 寄存器( 00H )用于告訴 MCU ,哪些點有效,哪些點無效,從而讀取對應(yīng)的數(shù)據(jù)。
可知模塊只支持最多 5 點觸摸。表中只有 5 個位用來表示對應(yīng)點坐標是否有效,其余位為保留位(讀為 0 ),通過讀取該寄存器,可知哪些點有數(shù)據(jù),哪些點無數(shù)據(jù),如果讀到的全是 0 ,則說明沒有任何觸摸。
(2)傳感器控制寄存器(ODH)
傳感器控制寄存器(ODH ),該寄存器也是 8 位,僅最高位有效,其他位都是保留,當最高位為 1 的時候,打開傳感器(開始檢測),當最高位設(shè)置為 0 的時候,關(guān)閉傳感器(停止檢測)。
(3)坐標數(shù)據(jù)寄存器(共 20 個)
坐標數(shù)據(jù)寄存器總共有 20 個,每個坐標占用 4 個寄存器,坐標寄存器與坐標的對應(yīng)關(guān)系下圖;
每個坐標的值,可以通過 4 個寄存器讀出,比如讀取坐標 A: (X1,Y1),可以讀取 01H~04H ,就可以知道當前坐標 1 的具體數(shù)值了。也可以只發(fā)送寄存器 01 ,然后連續(xù)讀取 4 個字節(jié),也可以正常讀取坐標 A ,寄存器地址會自動增加,從而提高讀取速度。
注:
(1)OTT2001A 的寄存器是 8 位的,但是發(fā)送的時候要發(fā)送 16 位(高八位有效),才可以正常使用。
(2)OTT2001A 的輸出坐標,默認是以: X 坐標最大值是 2700 Y 坐標最大值是 1500 的分辨率輸出的,也就是輸出范圍為: X:0-2700,Y:0-1500 。MCU 在讀取到坐標后,必須根據(jù) LCD 分辨率做一個換算,才能得到真實的 LCD 坐標。
2.2 初始化流程
3. 軟件分析
這里簡要的分析一下電阻屏的驅(qū)動。
3.1 通信方式實現(xiàn)
/*軟件模擬SPI寫數(shù)據(jù)*/ void TP_Write_Byte(u8 num) { u8 count = 0;for(count = 0;count < 8;count++) { if(num&0x80)TDIN = 1; else TDIN = 0; num <<= 1; TCLK = 0; TCLK = 1; //上升沿有效 } }3.2 觸摸屏驅(qū)動實現(xiàn)
/*從觸摸屏讀取 ADC 的數(shù)值*/ u16 TP_Read_AD(u8 CMD) { u8 count = 0; u16 Num = 0; TCLK = 0; //先拉低時鐘 TDIN = 0; //拉低數(shù)據(jù)線TCS = 0; //選中觸摸屏ICTP_Write_Byte(CMD);//發(fā)送命令字delay_us(6);//ADS7846的轉(zhuǎn)換時間最長為6usTCLK = 0; delay_us(1); TCLK = 1; //給1個時鐘,清除BUSY TCLK = 0; for(count = 0;count < 16;count++)//讀出16位數(shù)據(jù),只有高12位有效 { Num <<= 1; TCLK = 0; //下降沿有效 TCLK = 1;if(DOUT)Num++; } Num >>= 4; //只有高12位有效,移除低四位TCS = 1; //釋放片選 return(Num); } /*讀取x或y的坐標值,并且多次讀取,去掉最大、最小值,減少測量誤差*/#define READ_TIMES 5 //讀取次數(shù) #define LOST_VAL 1 //丟棄值 u16 TP_Read_XOY(u8 xy) {u16 i, j;u16 buf[READ_TIMES];u16 sum=0;u16 temp;for(i=0;i<READ_TIMES;i++)buf[i] = TP_Read_AD(xy); for(i = 0;i < READ_TIMES-1; i++)//排序{for(j=i+1;j<READ_TIMES;j++){if(buf[i]>buf[j])//升序排列{temp = buf[i];buf[i] = buf[j];buf[j] = temp;}}} sum = 0;for(i = LOST_VAL;i < READ_TIMES-LOST_VAL;i++) //丟掉最大最小值sum += buf[i];temp = sum/(READ_TIMES-2*LOST_VAL);return temp; } /*讀取x,y的坐標值*/ u8 TP_Read_XY(u16 *x,u16 *y) {u16 xtemp,ytemp;xtemp = TP_Read_XOY(CMD_RDX);ytemp = TP_Read_XOY(CMD_RDY); //if(xtemp<100||ytemp<100)return 0;//讀數(shù)失敗*x = xtemp;*y = ytemp;return 1;//讀數(shù)成功 } /*連續(xù)兩次讀取觸摸屏數(shù)值,并且設(shè)定讀數(shù)誤差范圍*/#define ERR_RANGE 50 //誤差范圍 u8 TP_Read_XY2(u16 *x,u16 *y) {u16 x1,y1;u16 x2,y2;u8 flag; flag = TP_Read_XY(&x1,&y1); if(flag==0)return(0);flag = TP_Read_XY(&x2,&y2); if(flag==0)return(0); if(((x2<=x1&&x1<x2+ERR_RANGE)||(x1<=x2&&x2<x1+ERR_RANGE))//前后兩次采樣在+-50內(nèi)&&((y2<=y1&&y1<y2+ERR_RANGE)||(y1<=y2&&y2<y1+ERR_RANGE))){*x = (x1+x2)/2;*y = (y1+y2)/2;return 1;}else return 0; }3.3 顯示處理
/*調(diào)用LCD顯示函數(shù),顯示出觸摸點*/ void TP_Drow_Touch_Point(u16 x,u16 y,u16 color) {POINT_COLOR = color;LCD_DrawLine(x-12,y,x+13,y);//橫線LCD_DrawLine(x,y-12,x,y+13);//豎線LCD_DrawPoint(x+1,y+1);LCD_DrawPoint(x-1,y+1);LCD_DrawPoint(x+1,y-1);LCD_DrawPoint(x-1,y-1);LCD_Draw_Circle(x,y,6);//畫中心圈 }void TP_Draw_Big_Point(u16 x,u16 y,u16 color) { POINT_COLOR=color;LCD_DrawPoint(x,y);//中心點 LCD_DrawPoint(x+1,y);LCD_DrawPoint(x,y+1);LCD_DrawPoint(x+1,y+1); }3.4 觸摸屏數(shù)據(jù)處理
/*掃描觸摸按鍵*/ u8 TP_Scan(u8 tp) { if(PEN==0)//有按鍵按下{if(tp)TP_Read_XY2(&tp_dev.x[0],&tp_dev.y[0]);//讀取物理坐標else if(TP_Read_XY2(&tp_dev.x[0],&tp_dev.y[0]))//讀取屏幕坐標{tp_dev.x[0] = tp_dev.xfac*tp_dev.x[0]+tp_dev.xoff;//將結(jié)果轉(zhuǎn)換為屏幕坐標tp_dev.y[0] = tp_dev.yfac*tp_dev.y[0]+tp_dev.yoff; } if((tp_dev.sta&TP_PRES_DOWN)==0)//之前沒有被按下{ tp_dev.sta = TP_PRES_DOWN|TP_CATH_PRES;//按鍵按下 tp_dev.x[4] = tp_dev.x[0];//記錄第一次按下時的坐標tp_dev.y[4] = tp_dev.y[0]; } }else{if(tp_dev.sta&TP_PRES_DOWN)//之前是被按下的{tp_dev.sta&=~(1<<7);//標記按鍵松開 }else//之前就沒有被按下{tp_dev.x[4] = 0;tp_dev.y[4] = 0;tp_dev.x[0] = 0xffff;tp_dev.y[0] = 0xffff;} }return tp_dev.sta&TP_PRES_DOWN;//返回當前的觸屏狀態(tài) } #define SAVE_ADDR_BASE 40 //保存校準參數(shù) void TP_Save_Adjdata(void) { s32 temp; //保存校正結(jié)果! temp = tp_dev.xfac*100000000;//保存x校正因素 AT24CXX_WriteLenByte(SAVE_ADDR_BASE,temp,4); temp = tp_dev.yfac*100000000;//保存y校正因素 AT24CXX_WriteLenByte(SAVE_ADDR_BASE+4,temp,4);//保存x偏移量AT24CXX_WriteLenByte(SAVE_ADDR_BASE+8,tp_dev.xoff,2); //保存y偏移量AT24CXX_WriteLenByte(SAVE_ADDR_BASE+10,tp_dev.yoff,2); //保存觸屏類型AT24CXX_WriteOneByte(SAVE_ADDR_BASE+12,tp_dev.touchtype); temp = 0X0A;//標記校準過了AT24CXX_WriteOneByte(SAVE_ADDR_BASE+13,temp); } /*讀出保存的校準參數(shù),檢查屏幕狀態(tài)*/ u8 TP_Get_Adjdata(void) { s32 tempfac; u8 temp;temp = AT24CXX_ReadOneByte(SAVE_ADDR_BASE+13);//讀取標記字,看是否校準過! if(temp==0X0A)//觸摸屏已經(jīng)校準過了 { tempfac = AT24CXX_ReadLenByte(SAVE_ADDR_BASE,4); tp_dev.xfac = (float)tempfac/100000000;//得到x校準參數(shù)tempfac = AT24CXX_ReadLenByte(SAVE_ADDR_BASE+4,4); tp_dev.yfa c= (float)tempfac/100000000;//得到y(tǒng)校準參數(shù)//得到x偏移量tp_dev.xoff = AT24CXX_ReadLenByte(SAVE_ADDR_BASE+8,2); //得到y(tǒng)偏移量tp_dev.yoff = AT24CXX_ReadLenByte(SAVE_ADDR_BASE+10,2); tp_dev.touchtype = AT24CXX_ReadOneByte(SAVE_ADDR_BASE+12);//讀取觸屏類型標記if(tp_dev.touchtype)//X,Y方向與屏幕相反{CMD_RDX = 0X90;CMD_RDY = 0XD0; }else //X,Y方向與屏幕相同{CMD_RDX = 0XD0;CMD_RDY = 0X90; } return 1; }return 0; } /*顯示出校準的坐標參數(shù)*/ void TP_Adj_Info_Show(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2,u16 x3,u16 y3,u16 fac) { POINT_COLOR = RED;LCD_ShowString(40,160,lcddev.width,lcddev.height,16,"x1:");LCD_ShowString(40+80,160,lcddev.width,lcddev.height,16,"y1:");LCD_ShowString(40,180,lcddev.width,lcddev.height,16,"x2:");LCD_ShowString(40+80,180,lcddev.width,lcddev.height,16,"y2:");LCD_ShowString(40,200,lcddev.width,lcddev.height,16,"x3:");LCD_ShowString(40+80,200,lcddev.width,lcddev.height,16,"y3:");LCD_ShowString(40,220,lcddev.width,lcddev.height,16,"x4:");LCD_ShowString(40+80,220,lcddev.width,lcddev.height,16,"y4:"); LCD_ShowString(40,240,lcddev.width,lcddev.height,16,"fac is:"); LCD_ShowNum(40+24,160,x0,4,16); //顯示數(shù)值LCD_ShowNum(40+24+80,160,y0,4,16); //顯示數(shù)值LCD_ShowNum(40+24,180,x1,4,16); //顯示數(shù)值LCD_ShowNum(40+24+80,180,y1,4,16); //顯示數(shù)值LCD_ShowNum(40+24,200,x2,4,16); //顯示數(shù)值LCD_ShowNum(40+24+80,200,y2,4,16); //顯示數(shù)值LCD_ShowNum(40+24,220,x3,4,16); //顯示數(shù)值LCD_ShowNum(40+24+80,220,y3,4,16); //顯示數(shù)值LCD_ShowNum(40+56,lcddev.width,fac,3,16); //顯示數(shù)值,該數(shù)值必須在95~105范圍之內(nèi).} const u8 TP_ADJDIS_TBL[3][4]={{0,1,2,3},{0,2,1,3},{1,2,0,3}};//校準距離計算表 //觸摸屏校準代碼 //得到四個校準參數(shù) void TP_Adjust(void) { u16 pos_temp[4][2];//坐標緩存值u8 cnt = 0; u16 d1,d2;u32 tem1,tem2;float fac; u16 outtime=0; LCD_Clear(WHITE); //清屏 POINT_COLOR = BLUE; //藍色LCD_ShowString(40,40,160,100,16,(u8*)TP_REMIND_MSG_TBL);//顯示提示信息TP_Drow_Touch_Point(20,20,RED);//畫點1 tp_dev.sta = 0;//消除觸發(fā)信號 tp_dev.xfac = 0;//xfac用來標記是否校準過,所以校準之前必須清掉!以免錯誤 while(1)//如果連續(xù)10秒鐘沒有按下,則自動退出{ READJ:tp_dev.scan(1);//掃描物理坐標if((tp_dev.sta&0xc0)==TP_CATH_PRES)//按鍵按下了一次(此時按鍵松開了.){ outtime = 0; tp_dev.sta &= ~(1<<6); //標記按鍵已經(jīng)被處理過了. pos_temp[cnt][0] = tp_dev.x[0];pos_temp[cnt][1] = tp_dev.y[0];cnt++; switch(cnt){ case 1: TP_Drow_Touch_Point(20,20,WHITE); //清除點1 TP_Drow_Touch_Point(lcddev.width-20,20,RED); //畫點2break;case 2:TP_Drow_Touch_Point(lcddev.width-20,20,WHITE); //清除點2TP_Drow_Touch_Point(20,lcddev.height-20,RED); //畫點3break;case 3:TP_Drow_Touch_Point(20,lcddev.height-20,WHITE); //清除點3TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,RED); //畫點4break; case 4: //全部四個點已經(jīng)得到for(cnt = 0;cnt < 3;cnt++)//計算三組點的距離是否在允許范圍內(nèi)?{ tem1 = abs(pos_temp[TP_ADJDIS_TBL[cnt][0]][0]-pos_temp[TP_ADJDIS_TBL[cnt][1]][0]);//x1-x2/x1-x3/x2-x3tem2 = abs(pos_temp[TP_ADJDIS_TBL[cnt][0]][1]-pos_temp[TP_ADJDIS_TBL[cnt][1]][1]);//y1-y2/y1-y3/y2-y3tem1 *= tem1;tem2 *= tem2;d1 = sqrt(tem1+tem2);//得到兩點之間的距離 tem1 = abs(pos_temp[TP_ADJDIS_TBL[cnt][2]][0]-pos_temp[TP_ADJDIS_TBL[cnt][3]][0]);//x3-x4/x2-x4/x1-x4tem2 = abs(pos_temp[TP_ADJDIS_TBL[cnt][2]][1]-pos_temp[TP_ADJDIS_TBL[cnt][3]][1]);//y3-y4/y2-y4/y1-y4tem1 *= tem1;tem2 *= tem2;d2 = sqrt(tem1+tem2);//得到兩點之間的距離fac = (float)d1/d2;if(fac<0.95||fac>1.05||d1==0||d2==0)//不合格{cnt = 0;TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,WHITE); //清除點4TP_Drow_Touch_Point(20,20,RED); //畫點1TP_Adj_Info_Show(pos_temp[0][0],pos_temp[0][1],pos_temp[1][0],pos_temp[1][1],pos_temp[2][0],pos_temp[2][1],pos_temp[3][0],pos_temp[3][1],fac*100);//顯示數(shù)據(jù) goto READJ; //不合格,重新校準}} //正確了//計算結(jié)果tp_dev.xfac = (float)(lcddev.width-40)/(pos_temp[1][0]-pos_temp[0][0]);//得到xfac tp_dev.xoff = (lcddev.width-tp_dev.xfac*(pos_temp[1][0]+pos_temp[0][0]))/2;//得到xofftp_dev.yfac = (float)(lcddev.height-40)/(pos_temp[2][1]-pos_temp[0][1]);//得到y(tǒng)factp_dev.yoff = (lcddev.height-tp_dev.yfac*(pos_temp[2][1]+pos_temp[0][1]))/2;//得到y(tǒng)off if(abs(tp_dev.xfac)>2||abs(tp_dev.yfac)>2)//觸屏和預(yù)設(shè)的相反了.{cnt = 0;TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,WHITE); //清除點4TP_Drow_Touch_Point(20,20,RED); //畫點1LCD_ShowString(40,26,lcddev.width,lcddev.height,16,"TP Need readjust!");tp_dev.touchtype = !tp_dev.touchtype;//修改觸屏類型.if(tp_dev.touchtype)//X,Y方向與屏幕相反{CMD_RDX = 0X90;CMD_RDY = 0XD0; }else //X,Y方向與屏幕相同{CMD_RDX = 0XD0;CMD_RDY = 0X90; } continue;} POINT_COLOR=BLUE;LCD_Clear(WHITE);//清屏LCD_ShowString(35,110,lcddev.width,lcddev.height,16,"Touch Screen Adjust OK!");//校正完成delay_ms(1000);TP_Save_Adjdata(); LCD_Clear(WHITE);//清屏 return;//校正完成 }}delay_ms(10);outtime++;if(outtime>1000){TP_Get_Adjdata();break;} } }傳統(tǒng)的鼠標是一種相對定位系統(tǒng),只和前一次鼠標的位置坐標有關(guān)。而觸摸屏則
是一種絕對坐標系統(tǒng),要選哪就直接點哪,與相對定位系統(tǒng)有著本質(zhì)的區(qū)別。絕對坐標系統(tǒng)的特點是每一次定位坐標與上一次定位坐標沒有關(guān)系,每次觸摸的數(shù)據(jù)通過校準轉(zhuǎn)為屏幕上的坐標,不管在什么情況下,觸摸屏這套坐標在同一點的輸出數(shù)據(jù)是穩(wěn)定的。不過由于技術(shù)原理的原因,并不能保證同一點觸摸每一次采樣數(shù)據(jù)相同,不能保證絕對坐標定位,點不準,這就是觸摸屏最怕出現(xiàn)的問題:漂移。對于性能質(zhì)量好的觸摸屏來說,漂移的情況出現(xiàn)并不是很嚴重。所以很多應(yīng)用觸摸屏的系統(tǒng)啟 動后,進入應(yīng)用程序前,先要執(zhí)行校準程序。 通常應(yīng)用程序中使用的 LCD 坐標是以像素為單位的。比如說:左上角的坐標是一組非 0 的數(shù)值,比如( 20,20)而右下角的坐標為( 220,300 )。這些點的坐標都是以像素為單位的,而從觸摸屏中讀出的是點的物理坐標,其坐標軸的方向、 XY 值的比例因子、偏移量都與 LCD 坐標不同,所以, 需要在程序 中把物理坐標首先轉(zhuǎn)換為像素坐標,然后再賦給 POS 結(jié)構(gòu),達到坐標轉(zhuǎn)換的目的。
校正思路:在了解了校正原理之后,我們可以得出下面的一個從物理 坐標到像素坐標的轉(zhuǎn)換關(guān)系式:
LCDx = xfac*Px+xoff LCDy= yfac*Py+yoff其中(LCDx, 是在 LCD 上的像素坐標,( Px,Py )是從觸摸屏讀到的物理坐標。 xfac,yfac 分別是 X 軸方向和 Y 軸方向的比例因子,而 xoff 和 yoff 則是這兩個方向的偏移量。這樣我們只要事先在屏幕上面顯示 4 個點(這四個點的坐標是已 知的),分別按這四個點就可以從觸摸屏讀到 4 個物理坐標,這樣就可以通過待定系數(shù)法求出 xfac 、 yfac 、 xoff 、 yoff 這四個參數(shù)。我們保存好這四個參數(shù),在以后的使用中,我們把所有得到的物理坐標都按照這個關(guān)系式來計算,得到的就是準確的屏幕坐標,達到了觸摸屏校準的目的。
/*顯示屏初始化*/ u8 TP_Init(void) { GPIO_InitTypeDef GPIO_InitStructure;//GPIO if(lcddev.id==0X5510) //4.3寸電容觸摸屏{if(GT9147_Init()==0) //是GT9147{ tp_dev.scan=GT9147_Scan; //掃描函數(shù)指向GT9147觸摸屏掃描}else{OTT2001A_Init();tp_dev.scan=OTT2001A_Scan; //掃描函數(shù)指向OTT2001A觸摸屏掃描}tp_dev.touchtype|=0X80; //電容屏 tp_dev.touchtype|=lcddev.dir&0X01;//橫屏還是豎屏 return 0;}else if(lcddev.id==0X1963) //7寸電容觸摸屏{FT5206_Init();tp_dev.scan=FT5206_Scan; //掃描函數(shù)指向GT9147觸摸屏掃描 tp_dev.touchtype|=0X80; //電容屏 tp_dev.touchtype|=lcddev.dir&0X01;//橫屏還是豎屏 return 0;}else{ //注意,時鐘使能之后,對GPIO的操作才有效//所以上拉之前,必須使能時鐘.才能實現(xiàn)真正的上拉輸出RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_0|GPIO_Pin_13;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; GPIO_Init(GPIOC, &GPIO_InitStructure);//GPIOC->ODR|=0X200f; //PC0~3 13 全部上拉 TP_Read_XY(&tp_dev.x[0],&tp_dev.y[0]);//第一次讀取初始化 AT24CXX_Init();//初始化24CXXif(TP_Get_Adjdata())return 0;//已經(jīng)校準else //未校準?{ LCD_Clear(WHITE);//清屏TP_Adjust(); //屏幕校準 TP_Save_Adjdata(); } TP_Get_Adjdata(); }return 1; }參考:
總結(jié)
以上是生活随笔為你收集整理的STM32学习笔记一一触摸屏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解密蓝牙防丢器工作原理,让您避免遗失物品
- 下一篇: MT7628学习笔记(8)——开发板联网