• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            唐吉訶德

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              5 Posts :: 75 Stories :: 3 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(2)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            轉載請注明出處

            作者:小馬


             

            前段時間移植 6.0 BSP,目前已移植到觸摸屏部分了. 移植過程中學到了不少東西. 由其是關于觸摸屏這部分, 掌握了很多以前不會的東西. 覺得有必要把這些知識點整理一下. 


            一 硬件部分


            硬件上的原理不是本文的重點,只講一下大概的原理(主要是我也只知道大概的原理, 畢竟咱不是搞硬件的. 嘻嘻!)


            我移植用的這個屏是320*240 的TFT屏, 四線電阻式觸屏. 這種觸屏的原理是由兩個電阻層組成, 一個實現X位置的測量,一個用于Y位置上的測量. 簡單來說,就是當用觸筆按下屏幕時,兩個電阻層接觸, 電阻發生變化,然后在X Y方向上產生信號, 這個信號是電壓信號, 再經過CPU內部分AD轉換為坐標值. 這個原理有點像高中物理課用的滑動電阻,有一個最大上限,滑動到不同的地方,阻值不同. 2410本身集成了touch的控制器,通過簡單的配置和讀取相關的寄存器,就可以實現觸摸屏的操作. 


            二 驅動部分

            Wince下的touch驅動跟很多其它的驅動一樣, 是分層的, 有MDD 和PDD兩層. MDD層被系統隱藏起來, 一般不用我們來修改. 而我們真正關心的是PDD 層. 也就是要由開發者來修改的這一層. 


            分析touch驅動時,以我最近剛剛移植到一個基于2410的板子上的6.0的BSP包的觸屏驅動為例.到C:\WINCE600\PLATFORM\DEVICEEMULATOR\SRC\DRIVERS\TOUCH下. 找到s3c2410x_touch.cpp文件. 這里面正是PDD層的實現代碼. 容易發現這里面的函數分為兩類,一類是以TSP開頭的函數,一類是以DDSI開頭的函數. TSP開頭的函數為內部私有的函數,是被DDSI調用的, 而DDSI開頭的函數則是對外的接口, 也就是被MDD層的函數調用的接口. 


            DdsiTouchPanelEnable是首先被調用的一個外部接口, 它的實現可參見源程序,  它主

            要做了下面幾個事情:

            1 通過調用TSP_VirtualAlloc函數為驅動所用的IO,中斷等硬件中斷分配內存空間. 


            2 通過調用KernelIoControl向系統申請兩個中斷,如果申請成功,賦予相應的邏輯中斷號. KernelIoControl向底層是調用OEMIoControl函數, OEMIoControl根據KernelIoControl傳進來的IOCTL代碼,做相應的操作,比如這里, IOCTL是IOCTL_HAL_REQUEST_SYSINTR, 它是向內核申請一個物理中斷和邏輯中斷的映射. 


            3 通過調用TSP_PowerOn來初始化中斷控制器,ADC寄存器,定時器等, 在TSP_PowerOn的實現中,有幾點要說明一下:

            ADCDLY 這個值在不同的模式下意義不同, 因為前面通過ADCTSC已經配置為wait for interrupt mode, 所以這個值的意義和你的觸筆按下時,  從產生中斷信號到開始自動轉換X,Y時的時間間隔是相關的,它的單位是ms


            v_pPWMregs->TCNTB3  = g_timer3_sampleticks

            TCNTB3是timer3的count buffer, 當定時器啟動時, 0,這個值以一個設置好的頻率遞減,直到減到0, 這時會產生一個定時器中斷. 這個有什么用呢. 要理解它,得知道觸摸屏在中斷模式下是如何工作的. 


            當我們按下的觸摸屏時,會產生一個ADC的中斷, 同時我們的驅動還會啟動一個定時器, 這個定時器觸發一個事件做數據采集, 在我們的手或觸筆抬起來前,這個定時器不斷的觸發采集事件,直到它被關閉, 而它什么時候會被關閉呢,就是在觸筆的抬起來時. 下面截取的代碼很好的說明的這個原理:

            if ( (v_pADCregs->ADCDAT0 & (1 << 15)) |(v_pADCregs->ADCDAT1 & (1 << 15)) )

            {

            bTSP_DownFlag = FALSE;

            DEBUGMSG(ZONE_TIPSTATE, (TEXT("up\r\n")));

            v_pADCregs->ADCTSC &= 0xff;

                    *pUncalX = x;

            *pUncalY = y;

            TSP_SampleStop();

                        ……

            }

            上面的代碼,if判斷的正是是否抬起. 

            而g_timer3_sampleticks的值是這樣計算出來的. 

            g_timer3_freq        = (g_s3c2410_pclk / TIMER3_DIVIDER);

            g_timer3_sampleticks = (g_timer3_freq / TSP_SAMPLE_RATE_LOW); 

            TIMER3_DIVIDER 的值是2, TSP_SAMPLE_RATE_LOW的值是100, 由

            v_pPWMregs->TCFG1  &= ~(0xf << 12);  

            v_pPWMregs->TCFG1  |=  (0   << 12); 

            可知定時器1/2分頻, 所以,很容易計算出,所設置的定時器是每10ms產生一次定時器中斷

            而觸摸屏中斷是在你按下和抬起時產生的. 


            DdsiTouchPanelGetPoint是采樣的主要實現函數,當MDD檢測到中斷事件發生時,該函數會被調用. 觸摸屏的中斷是SYSINTR_TOUCH, 而定時器的中斷是SYSINTR_TOUCH_CHANGED 

            該函數用if else分別處理兩種中斷, 如下:

            if (v_pINTregs->SUBSRCPND & (1<<IRQ_SUB_TC))      /* 觸摸屏中斷*/

            {

                ……

            }


            else        /*定時器中斷 */

            {

            }

            DdsiTouchPanelGetPoint函數的實現代碼中,調用了兩個很重要的函數TSP_TransXY和TSP_GetXY

            需要說明的是,這兩個函數的實現跟LCD本身的分辨率是沒有關系的.

            TSP_GetXY用來獲到AD采樣值,TSP_TransXY把它轉化為屏上的坐標. 我移植touch驅動時,遇到過點屏幕上面,下面有反應,或者點左上角,右上角有反應等類似的問題, 都是因為這兩個函數沒實現好.


            先來看TSP_GetXY函數.它的實現如下:

            TSP_GetXY(INT *px, INT *py)

            {

            INT i;

            INT xsum, ysum;

            INT x, y;

            INT dx, dy;

            xsum = ysum = 0;

            for (i = 0; i < TSP_SAMPLE_NUM; i++)

            {

            v_pADCregs->ADCTSC =   (0      <<  8) |        /* UD_Sen*/

            (1      <<  7) |        /* YMON  1 (YM = GND)*/

            (1      <<  6) |        /* nYPON 1 (YP Connected AIN[n])*/

            (0      <<  5) |        /* XMON  0 (XM = Z)*/

            (1      <<  4) |        /* nXPON 1 (XP = AIN[7])*/

            (1      <<  3) |        /* Pull Up Enable*/

            (1      <<  2) |        /* Auto ADC Conversion Mode*/

            (0      <<  0);         /* No Operation Mode*/


            v_pADCregs->ADCCON |= (1 << 0);  /* Start Auto conversion*/


            while (v_pADCregs->ADCCON & 0x1);               /* check if Enable_start is low*/

            while (!(v_pADCregs->ADCCON & (1 << 15)));      /* Check ECFLG*/


            y = (0x3ff & v_pADCregs->ADCDAT1);

            x = (0x3ff & v_pADCregs->ADCDAT0);

            xsum += x;

            ysum += y;

            }

            *px = xsum / TSP_SAMPLE_NUM;

            *py = ysum / TSP_SAMPLE_NUM;


            v_pADCregs->ADCTSC =    (1      <<  8) |            /* UD_Sen*/

            (1      <<  7) |            /* YMON  1 (YM = GND)*/

            (1      <<  6) |            /* nYPON 1 (YP Connected AIN[n])*/

            (0      <<  5) |            /* XMON  0 (XM = Z)*/

            (1      <<  4) |            /* nXPON 1 (XP = AIN[7])*/

            (0      <<  3) |            /* Pull Up Disable*/

            (0      <<  2) |            /* Normal ADC Conversion Mode*/

            (3      <<  0);             /* Waiting Interrupt*/


            dx = (*px > x) ? (*px - x) : (x - *px);

            dy = (*py > y) ? (*py - y) : (y - *py);


            return((dx > TSP_INVALIDLIMIT || dy > TSP_INVALIDLIMIT) ? FALSE : TRUE);

            }


            關于這個函數有幾點要說明. 

            根據2410的手冊, ADCDAT0 保存是X方向上采樣的結果,  ADCDAT1 保存是Y方向上采樣的結果,  所以, 我們看到下面的兩行代碼

            y = (0x3ff & v_pADCregs->ADCDAT1);

            x = (0x3ff & v_pADCregs->ADCDAT0);

            與上0x3ff, 是因為, ADCDAT寄存器只用了前面 10位來保存AD采樣的結果, 而這和2410內部的AD模塊只有10位精度是相一致的.所以,AD轉換后的最大值不會超過1024-1. 

            當然上在那種計算方法并不是絕對的 , 根據硬件構造的不同, 比如有可能你x方向的坐標值和采樣值成反比,就要按下面的方式計算:

            x = 0x3ff - (0x3ff & v_pADCregs->ADCDAT0);


            再看TSP_TransXY函數. 我移植的版本的實現如下:

            PRIVATE void

            TSP_TransXY(INT *px, INT *py)

            {

            *px = (*px >= TSP_MAXX) ? (TSP_MAXX) : *px;

            *py = (*py >= TSP_MAXY) ? (TSP_MAXY) : *py;


            *px = (*px - TSP_MINX);

            *py = (*py - TSP_MINY);


            *px = (*px >= 0) ? *px : 0;

            *py = (*py >= 0) ? *py : 0;


            *px = *px * TSP_LCDY / (TSP_MAXX - TSP_MINX);

            *py = *py * TSP_LCDX / (TSP_MAXY - TSP_MINY);


            *px = (*px >= TSP_LCDY)? (TSP_LCDY - 1) : *px;

            *py = (*py >= TSP_LCDX)? (TSP_LCDX - 1) : *py;


            *px = TSP_LCDY - *px - 1;

            *py = TSP_LCDX - *py - 1;


            }

            這個實現是我在模擬器的實現代碼基礎上修改的. 這個函數計算X,Y的坐標用的是一個公式,至于這個公式是怎么來的,我就不太清楚了. 只說明一點.

            #define TSP_MINX 88

            #define TSP_MINY 84


            #define TSP_MAXX 952

            #define TSP_MAXY 996

            上面四個值是定義X+, X-, Y+, Y-四個有效的采樣值, 理論上應該是0和1023(10 bit ADC), 但實際肯定有偏差,準確來講, 換了不同的硬件平臺,這四個值應該是要重新測過的. 我就直接沿用原BSP中的值了. 

                

            posted on 2011-03-01 11:50 心羽 閱讀(888) 評論(0)  編輯 收藏 引用 所屬分類: wince
            欧美噜噜久久久XXX| 精品久久久无码中文字幕| 伊人情人综合成人久久网小说| 国产成人久久精品麻豆一区| 精品国产青草久久久久福利| 精品久久人人爽天天玩人人妻| 伊人久久久AV老熟妇色| 久久精品国产亚洲沈樵| 久久国产精品波多野结衣AV| 丁香色欲久久久久久综合网| 久久96国产精品久久久| 亚洲精品高清一二区久久| 久久久久久国产精品免费无码| 大美女久久久久久j久久| 99精品国产免费久久久久久下载| 久久精品中文字幕无码绿巨人 | 国产成人精品久久| 麻豆av久久av盛宴av| 亚洲综合精品香蕉久久网97| 一级做a爰片久久毛片免费陪| 中文字幕久久欲求不满| 久久人人添人人爽添人人片牛牛| 激情五月综合综合久久69| 国内精品伊人久久久久av一坑| 日韩欧美亚洲综合久久影院Ds| 日韩亚洲欧美久久久www综合网 | 国产精品禁18久久久夂久| 久久亚洲国产成人影院| 久久久中文字幕日本| 久久91精品国产91久久小草 | 品成人欧美大片久久国产欧美...| 久久偷看各类wc女厕嘘嘘| 日韩欧美亚洲国产精品字幕久久久 | 91精品国产91久久综合| 日韩乱码人妻无码中文字幕久久| 久久久久99这里有精品10| 久久人人爽人人澡人人高潮AV| 99久久免费国产精品| 国产伊人久久| 亚洲精品久久久www| 久久这里的只有是精品23|