電阻屏是通過檢測(cè)觸點(diǎn)處的電壓來確定位置的,電壓受到電阻材料的影響,而生產(chǎn)中不同批次的電阻材料可能會(huì)有偏差,因此需要先定位幾個(gè)點(diǎn)來確定屏幕的偏移量 ( 也就是校準(zhǔn) ) ,以后通過校準(zhǔn)得來的偏移量調(diào)整坐標(biāo)輸出,才能準(zhǔn)確通過電壓反映坐標(biāo)。而電容屏是直接由多個(gè)電容組成的矩陣,檢測(cè)時(shí)可獲知整個(gè)電容矩陣中哪些電容發(fā)生了改變,而且各個(gè)電容在生產(chǎn)時(shí)就確認(rèn)了它在觸摸屏中的坐標(biāo),所以只要獲知哪些電容發(fā)生了變化,就可直接得出觸點(diǎn)位置,無須校準(zhǔn)。
由于用的是電阻屏,所以這里需要進(jìn)行校準(zhǔn)。
屏幕坐標(biāo)與AD轉(zhuǎn)換結(jié)果也不是相等的,面是存在一定比例關(guān)系,也就是說AD轉(zhuǎn)換結(jié)果與實(shí)際屏幕坐標(biāo)之間是一條不過坐標(biāo)原點(diǎn),且斜率不為1的直線,線性關(guān)系可表示為:
**LCD_X=KxADC_x+offset_x
LCD_Y=KyADC_y+offset_y *
式中LCD_X和LCD_ Y是LCD屏幕上的坐標(biāo)位置,ADC_x和ADCy為點(diǎn)擊屏上(LCDX.,LCD Y)時(shí)所采集的AD值,Kx和Ky是兩者之同的比例關(guān)系,而 offset_x和 offset_y則為兩者相對(duì)于坐標(biāo)原點(diǎn)時(shí)的的偏移量。屏幕上點(diǎn)的坐標(biāo)與其AD值之間的關(guān)系可用圖表示:

由圖可知,只要確定線性關(guān)系當(dāng)中的Kx、Ky及 Offset_x和 Offset_y,當(dāng)獲取到觸摸點(diǎn)對(duì)應(yīng)的AD值時(shí),即可確定觸摸點(diǎn)的位置,比較簡(jiǎn)單的方法是采集屏幕的左上角(0,0)位置和右下角(239,319)位置的AD值,假定為(ad_x0,ad_y0)和(ad_x1,ad_y1),有了坐標(biāo)和AD值,即可確定線性關(guān)系,Kx=(ad_x1- ad_x1)/239;Ky=( ade y1-ad_y0)/319,確定了Kx和Ky即可確定 Offset_x和Offset_y,從而最終確定線性關(guān)系,以后點(diǎn)擊屏幕任意點(diǎn),都可根據(jù)線性關(guān)系確定屏幕坐標(biāo)位置。
通常,由于LCD屏幕邊界處存在較多的噪點(diǎn),為了更為準(zhǔn)確地校準(zhǔn)屏幕,并確定線性關(guān)系,往往采用四點(diǎn)校屏法或五點(diǎn)校屏法,但本質(zhì)都是一樣的。四點(diǎn)校屏即在屏幕靠近四個(gè)角落的地方給定四個(gè)點(diǎn),以提示用戶點(diǎn)擊這四點(diǎn),并假定用戶點(diǎn)擊后所得的AD值就是這四個(gè)點(diǎn)的AD值(當(dāng)然,實(shí)際觸摸位置總是會(huì)存在一定偏差,若在一定誤差范圍內(nèi),則認(rèn)為觸摸點(diǎn)就是給定點(diǎn)),從而根據(jù)給定位置和所得AD值,就可確定線性關(guān)系,原理與點(diǎn)擊左上角與右下角是一樣的。至于五點(diǎn)校屏,無非就是在屏幕中心位置又增加一參考點(diǎn)而已 。
先為校準(zhǔn)的參數(shù)定義一個(gè)結(jié)構(gòu)體:
typedef struct{
  float kx;
  float ky;
  float dx;
  float dy;
  u8 flag;        //用來標(biāo)識(shí),是否校準(zhǔn)過
}TouchParam_Typedef;
校準(zhǔn)思路:在在屏幕上給出參考的點(diǎn)擊點(diǎn),當(dāng)用戶觸摸屏幕時(shí),假定所得的觸點(diǎn)AD值就是參考點(diǎn)的ADC,利用實(shí)際所得的AD值和參考坐標(biāo),計(jì)算出一個(gè)線性關(guān)系。然后,再把觸點(diǎn)AD值代入所得的線性關(guān)系中,計(jì)算實(shí)際觸點(diǎn)的坐標(biāo),若實(shí)際坐標(biāo)與給定坐標(biāo)滿足的誤差條件,則認(rèn)為該直線即為線性關(guān)系。下面給出校準(zhǔn)示意圖:

這里采用四點(diǎn)校屏法,來確定線性關(guān)系中的比例系數(shù)和偏移量,即屏幕校準(zhǔn)。選擇4個(gè)參考點(diǎn),參考點(diǎn)選取越靠邊界,范圍就越大,這樣校準(zhǔn)精度就越高,但是越靠近邊界,噪聲就越大,所以我們?nèi)ゾ嚯x邊界20的4個(gè)點(diǎn)來校準(zhǔn):(20,20)、(220,20)、(20,300)、(220,300)。
void Touch_Adjust()
{
  u16 ref_Point[4][2] = {{20,20},{220,20},{20,300},{220,300}};
  u16 real_Point[4][2] = {0};
  Point_Typedef pt = {0xffff,0xffff};
  u16 err[4] = {0};
  u8 i = 0;
  s8 error = 0;
  LCD_ClearScreen(0xffff);
  while(1)
  {
    for(i=0;i< 4;i++)
    {
      //畫點(diǎn)
      //畫水平線
      LCD_DrawLine(ref_Point[i][0]-7,ref_Point[i][1],ref_Point[i][0]+7,ref_Point[i][1],RED);
      //畫垂直線
      LCD_DrawLine(ref_Point[i][0],ref_Point[i][1]-7,ref_Point[i][0],ref_Point[i][1]+7,RED);
      //畫圓圈
      LCD_DrawCircle(ref_Point[i][0],ref_Point[i][1],5,RED);
      while(GPIOB- >IDR & (1< 1)){}    //未觸摸
      Delay_ms(30);
      while(GPIOB- >IDR & (1< 1)){}  //未觸摸
      //暫時(shí)把采用的ADC值,存儲(chǔ)到real_Point中
      pt = Touch_GetPointADC();
      real_Point[i][0] = pt.x;
      real_Point[i][1] = pt.y;
        printf("%d,%drn",real_Point[i][0],real_Point[i][1]);
      //等待松手
      while((GPIOB- >IDR & (1< 1)) == 0){}
      //清除已觸摸的點(diǎn)
      LCD_DrawLine(ref_Point[i][0]-7,ref_Point[i][1],ref_Point[i][0]+7,ref_Point[i][1],0xffff);
      //畫垂直線
      LCD_DrawLine(ref_Point[i][0],ref_Point[i][1]-7,ref_Point[i][0],ref_Point[i][1]+7,0xffff);
      //畫圓圈
      LCD_DrawCircle(ref_Point[i][0],ref_Point[i][1],5,0xffff);
    }
    //4個(gè)點(diǎn)的ADC值已經(jīng)獲取,根據(jù)AD值和參考坐標(biāo),求線性關(guān)系
    //利用第1點(diǎn)和第4點(diǎn),求線性關(guān)系
    /*
        ref_Point[0][0] = Kx * real_Point[0][0] + dx;    (1)
        ref_Point[3][0] = Kx * real_Point[3][0] + dx;   (2)
      由(1)和(2)可得:
        Kx = (float)(ref_Point[3][0] - ref_Point[0][0])/(real_Point[3][0] - real_Point[0][0]);
        dx = (float)(ref_Point[3][0]*real_Point[0][0] - ref_Point[0][0]*real_Point[3][0])/(real_Point[0][0] - real_Point[3][0]);
        ref_Point[0][1] = Ky * real_Point[0][1] + dy;    (3)
        ref_Point[3][1] = Ky * real_Point[3][1] + dy;   (4)
      由(3)和(4)可得:
        Ky = (float)(ref_Point[3][1] - ref_Point[0][1])/(real_Point[3][1] - real_Point[0][1]);
        dy = (float)(ref_Point[3][1]*real_Point[0][1] - ref_Point[0][1]*real_Point[3][1])/(real_Point[0][1] - real_Point[3][1]);
    */
      touchParam.kx = (float)(ref_Point[3][0] - ref_Point[0][0])/(real_Point[3][0] - real_Point[0][0]);
      touchParam.dx = (float)(ref_Point[3][0]*real_Point[0][0] - ref_Point[0][0]*real_Point[3][0])/(real_Point[0][0] - real_Point[3][0]);
      touchParam.ky = (float)(ref_Point[3][1] - ref_Point[0][1])/(real_Point[3][1] - real_Point[0][1]);
      touchParam.dy = (float)(ref_Point[3][1]*real_Point[0][1] - ref_Point[0][1]*real_Point[3][1])/(real_Point[0][1] - real_Point[3][1]);
      //利用計(jì)算的線性關(guān)系,求實(shí)際觸點(diǎn)坐標(biāo)
      for(i=0;i< 4;i++)
      {
        real_Point[i][0] = touchParam.kx * real_Point[i][0] + touchParam.dx;
        real_Point[i][1] = touchParam.ky * real_Point[i][1] + touchParam.dy;
        printf("(%d,%d)rn",real_Point[i][0],real_Point[i][1] );
      }
      //引入誤差條件(如果4個(gè)實(shí)際點(diǎn)都在小圓內(nèi),此認(rèn)為校準(zhǔn)通過,)
      for(i=0;i< 4;i++)
      {
        //這里計(jì)算距離平方
        err[i] = (real_Point[i][0] - ref_Point[i][0]) * (real_Point[i][0] - ref_Point[i][0])
                + (real_Point[i][1] - ref_Point[i][1]) * (real_Point[i][1] - ref_Point[i][1]);
        printf("err[%d]=%drn",i,err[i]);
      }
      //誤差判斷
      if(err[0]< 100 && err[1]< 100 && err[2]< 100 && err[3]< 100)
      {
        //認(rèn)為校準(zhǔn)通過(存儲(chǔ)到24c02或w25q64中,以24c02為例)
        touchParam.flag = 0xaa;  
        AT24C02_ContinueWrite(TOUCH_PARAM_ADD,(u8 *)&touchParam,sizeof(touchParam),&error);
        break;
      }
  }
  //校準(zhǔn)通過
  LCD_Print(50,160,(u8 *)"Adjust ok",0,0xffff,1,24);
  Delay_ms(3000);
  LCD_ClearScreen(0xffff);
}
校準(zhǔn)函數(shù)編寫完成,需要添加到觸摸屏初始化函數(shù)中,初始化GPIO時(shí)判斷是否已經(jīng)校準(zhǔn)過,沒有校準(zhǔn)過就進(jìn)行校準(zhǔn)。
void Touch_Init()
{
  s8 error = 0;
  Touch_gpio_Init();
  AT24C02_ContinueRead(TOUCH_PARAM_ADD,(u8 *)&touchParam,sizeof(touchParam),&error);
  if(touchParam.flag != 0x77)    //沒有校準(zhǔn)
    Touch_Adjust();
}
接著編寫主函數(shù)進(jìn)行測(cè)試。
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "stdio.h"
#include "touch.h"
#include "AT24C02.h"
#include "ili9341.h"
#include "lcd.h"
int main()
{
  Usart1_Init(115200);
  AT24C02_Init();
  LCD_Init();
  Touch_Init();
  while(1)
  {}
}
運(yùn)行后,顯示一個(gè)校準(zhǔn)點(diǎn),點(diǎn)擊該點(diǎn)校準(zhǔn)后,第一個(gè)校準(zhǔn)點(diǎn)被擦除,顯示第二個(gè)校準(zhǔn)點(diǎn),這樣依次校準(zhǔn)四個(gè)校準(zhǔn)點(diǎn),校準(zhǔn)結(jié)果在誤差允許范圍內(nèi),屏幕顯示Adjust ok,延時(shí)3秒后,屏幕被清為白色,觸摸屏校準(zhǔn)成功,接下來就可以在校準(zhǔn)好的基礎(chǔ)上在觸摸屏上做其他應(yīng)用了。
測(cè)試結(jié)果如下圖所示:



 電子發(fā)燒友App
                        電子發(fā)燒友App
                     
                 
                 
           
        
 
        










 
            
             
             
                 
             工商網(wǎng)監(jiān)
工商網(wǎng)監(jiān)
        
評(píng)論