2016年5月11日 星期三

{ 2.8 吋 (400x240) 電阻式觸模液晶螢幕使用說明 } [ 3/4 ] - 塗鴉板:圖形與觸摸功能的結合

網頁最後修改時間:2016/05/11 

塗鴉板,藉由點擊在螢幕四周的調色盤來改變畫筆顏色,可在畫布空間中繪畫,看起來好像是小孩子玩的東西 ! 但是您知道嗎 ? 要在液晶螢幕建立具有觸摸功能的人機互動畫面,由於液晶螢幕會根據現場施工的要求擺放螢幕,因此螢幕的方向就會變動 ( 就如同調色盤在螢幕上的位置) 也會改變液晶螢幕圖形座標,因此要讓調色盤與觸摸功能做結合,就必須要將液晶螢幕的座標與觸摸座標做轉換,才會在點擊時執行相對應的動作。
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
這個液晶螢幕的使用需要使用賣場改寫的函式庫與範例程式碼,不然執行時圖型、字型方向與顯示都會出現問題,即便使用原廠所提供的函式庫也是一樣 !

如果有遇到這個問題的使用者,可以參考 ILI932# 的資料手冊。雖然晶片支援的解析度不一樣,但是可以作為修改的參考,因為絕大部分的暫存器設定是相同的,只要注意一下螢幕顯示方向的部分,就可以解決大部分的問題,但要花一些時間做測試,提供給手邊有此零件的使用者做參考。

有購買商品的使用者,網頁中所需相關資料已放置於雲端硬碟,請根據網頁中所提的資訊下載相關程式碼做測試。

其餘的使用者,網頁有提供範例程式碼可供下載。
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*

*********************************************************************************
2.8吋(400x240)電阻式觸摸液晶螢幕可至露天賣場訂購:
*********************************************************************************
硬體環境:
  • 2.8 吋 (400x240) 電阻式觸模液晶螢幕
  • Arduino UNO
其他板子只要接腳夠與液晶螢幕接的的話,我認為都可以用 ! 但是要特別確認使用的板子接腳與 UNO 和液晶螢幕相接的號碼是否相同,不同就要改一下,這可不能懶惰不去做,可以省下很多時間的 !

軟體環境:
  • 安裝編輯環境:Arduino IDE V1.6.5-r5, Arduino IDE V1.6.7, Arduino IDE V1.6.8 
  • 安裝液晶螢幕函式庫:
    Streaming,若開啟 DEBUG 功能,需要這個函式庫。
    --------------------
    TFTLCD-mPm
    檔案位於 {雲端硬碟}/arduino/codes/libraries
    確認 {My Documents}/Arduino/libraries 沒有其他的 TFTLCD 函式庫,不然會造成編譯時候的衝突或是出現編譯錯誤 !
    上面注意事項沒問題後,下載 TFTLCD-mPm.zip 後直接解壓縮到 {My Documents}\Arduino\libraries 目錄下,會產生一個 TFTLCD-mPm 的資料夾,裡面會包含下面幾個檔案
TFTLCD-mPm 函式庫檔案列表
  • 程式碼:tftpaint
    下載 {雲端硬碟}/arduino/codes/tftpaint 整個目錄,並解壓縮到 {My Documents}/Arduino/ 目錄下
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//* 截至 2016/05/09 為止,Arduino IDE ( https://www.arduino.cc/en/Main/Software ) 最新版本為 1.6.8,但不是新版本就可以用。每個程式都會將測試成功的 Arduino IDE 版本列在其中,所以若是與網頁中使用的版本不一樣而出現問題,就改用網頁建議的版本來試。

因為到現在個人認為用的最穩定的 Arduino IDE 版本是 1.6.5-r5 ! 如果之前在 Arduino IDE 寫程式編譯上傳成功,但是出現奇怪執行現象時,可以先換版本編譯再上傳試試,或許就會意料中的結果,而不是意想不到的 ! 
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*

下載程式碼編譯並上傳後,可以根據下面的說明測試調色盤。若是觸摸功能校正及邊界輸入正確,就能達到與影片中相同的動作。


程式碼:柿子挑軟的吃

這個程式主要的重點就是觸模螢幕的邊界要校正好,這樣在畫布空間作畫時才會讓筆尖與點在同一個位置。

下面針對程式碼中需要注意的地方來做說明,其他的就自己讀一下。

在上一篇,我們得到的觸模邊界值為
  • LEFT       :242
  • TOP         :872
  • RIGHT     :970
  • BOTTOM:244
為了要能使用觸摸座標的底部來清除螢幕,所以將原本的 BOTTOM 位置往上移動 20,讓觸碰筆在 Y = 0 - 20 的地方點擊時,清除螢幕。

如果在程式中啟用 DEBUG 功能的話,可以輸出觸摸座標與圖形座標之間轉換的數據;但塗鴉的時候會嚴重延遲,線條會斷斷續續。因為這是我除錯用的,不過我測試好了,所以現在是關閉的,想了解的可以打開看看輸出。
tftpaint.ino, line 34
//#define DEBUG

在程式碼前頭,將前一篇 [ 2/4 ] 所得到的校正結果輸入進去。其中,對於 TS_MINY 必須預留一些空間可以清除螢幕,所以可以自行看要加多少都可以;這裡是往上移 20。
tftpaint.ino, line 44 - 47
#define TS_MINX 242
#define TS_MINY 264  // 244 是最底部,為了 easer 所以 + 20
#define TS_MAXX 970
#define TS_MAXY 867

2.8 吋液晶螢幕的解析度為 400 * 240,大小要指定給下面這兩個定義
tftpaint.ino, line 50 - 51
#define TS_SIZEX    400
#define TS_SIZEY    240

修改一下最後一個參數的電阻值,這個數值在前一篇 [ 2/4 ] 已經量測過了。
tftpaint.ino, line 57
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 740);

影片中調色盤上面每一個顏色框的大小由 BOXSIZE 指定數值;觸碰筆點下去的一個點的大小就由 PENRADIUS 指定數值。
tftpaint.ino, line 79 - 80
#define BOXSIZE     40
#define PENRADIUS   3

rotation 是作為引述給 setRotation( rotation ),用來設定螢幕的座標原點位於螢幕的哪一個邊邊角角。這個東西下一節再說,現在先把這些程式碼前面的東西講完。
tftpaint.ino, line 83
uint8_t rotation = 2;

還記得電阻式觸摸螢幕觸摸時需要一點力度,下面就是設定"力度"的最小值與最大值
tftpaint.ino, line 83
#define MINPRESSURE 10
#define MAXPRESSURE 1000

只有介於"力度"介於 100 - 1000 之間才算有效,才能在螢幕畫畫
tftpaint.ino, loop(), line 206 - 272
    if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
        //...
        //... 中間省略 
        //...       
    }

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
座標轉換:

在這一節中,使用者要清楚了解兩個東西:液晶螢幕座標和觸摸座標。

觸摸與液晶螢幕座標最大的差別,就是觸摸座標原點不會因為程式設定或是圖型旋轉而改變,是固定的 ! 所以若是要建立圖形介面與使用者互動時,使用者在螢幕上所觸碰的圖形必須相互對應到,將兩個位置經座標轉換,程式就能知道使用者的選擇逕而進行預先定義的動作。
觸摸座標與液晶螢幕座標原點之間的關係
所以當設定 rotation = 2 就要對照上圖左下角的圖示。

不同的螢幕旋轉,座標原點會改變。在液晶螢幕上作畫,知道這個原點在那裡就很重要。

當液晶螢幕需要與使用者互動時,程式中必須先將觸摸的位置與轉換到液晶畫面上的位置來,根據轉換之後的位置找出畫面中點擊的圖示是哪一個,這樣才能對使用者在畫面上的點擊動作做反應。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//

繼續上一節最後的 loop() 程式碼中的內容。使用者觸摸輸入時,若是點擊的位置在螢幕的最下方 (也就是想要清除螢幕畫的東西),條件只要符合,就將液晶螢幕上除了調色盤的區域全部塗黑。
tftpaint.ino, loop(), line 211 - 215
        if (p.y < (TS_MINY-5)) {
            Serial.println("erase");
            // press the bottom of the screen to erase 
            tft.fillRect(0, BOXSIZE, tft.width(), tft.height()-BOXSIZE, BLACK);       
        }

若不是清除螢幕的動作,則將觸摸的位置先映射為符合液晶螢幕解析度的大小的位置
tftpaint.ino, loop(), line 223 -224
        p.x = map( p.x, TS_MINX, TS_MAXX, 0, TS_SIZEX );    // 觸摸的 x 位置轉換為螢幕長軸解析度
        p.y = map( p.y, TS_MINY, TS_MAXY, 0, TS_SIZEY );    // 觸摸的 y 位置轉換為螢幕短軸解析度

將這個映射之後的位置,轉換為液晶螢幕旋轉之後的實際座標位置,由這個位置可以知道使用者是要更換畫筆顏色還是要作畫
tftpaint.ino, loop(), line 232 - 254
switch(rotation)
        {
            case 0:
                boxInc = p.y;
                boxWidth = p.x;
                boundary = TS_SIZEX;    // 400
            break;
            case 1:
                boxInc = p.x;
                boxWidth = TS_SIZEY - p.y - 1;  // 240 - p.y - 1
                boundary = TS_SIZEY;    // 240
            break;
            case 2:
                boxInc = TS_SIZEY - p.y - 1;
                boxWidth = TS_SIZEX - p.x - 1;
                boundary = TS_SIZEX;
            break;
            case 3:
                boxInc = TS_SIZEX - p.x - 1;
                boxWidth = p.y;
                boundary = TS_SIZEY;
            break;
        }

boxWidth 是液晶螢幕旋轉之後的 X 軸位置;boxInc 是液晶螢幕旋轉之後的 Y 軸位置。將這兩個數值輸入到 colorSelect 函式中:若是 boxWidth 位於調色盤的區域內,則經由輸入的 boxInc 就可以得知使用者選擇的色盤顏色;不是的話就直接跳出,往下執行繪畫的動作處理。

ts2b 函式的處理與上面 switch {} 裡所處理的東西一樣,只不過將名稱改一下容易了解其意思而已,轉換後的位置都一樣

  • tsp.x = boxWodth
  • tsp.y = boxInc

轉換後的位置,就是筆觸點 ! 若筆觸點不畏於調色盤區域,則直接上色 (就是填上一個半徑為 PENRADIUS 大小的實心圓 )。
tftpaint.ino, loop(), line 259 - 271
        colorSelect( boxWidth, boxInc );
        
        //***--- 修改對齊的位置
        TSPoint ts2b = t2bCoord( p );
        //---***
        // 觸摸的位置減掉點半徑要大於 BOX SIZE,且觸摸的位置加上點半徑要小於 BOX 延伸的最大寬度
        if (((boxWidth - PENRADIUS) > BOXSIZE) && ((boxWidth + PENRADIUS) < boundary )) {
            #ifdef DEBUG
            Serial << "Cir : ts2b.x, y=" << ts2b.x << ", " << ts2b.y << endl;
            Serial << "************" << endl;
            #endif
            tft.fillCircle(ts2b.x, ts2b.y, PENRADIUS, currentcolor);
        }

整個塗鴉板的程式運作就是這樣。

結論:

塗鴉板程式是與使用者互動的圖形化介面,可以做為下一個自己創建的介面做參考。函式庫裡面還有其他用來繪圖的函式很值得一看,可以省下許多寫程式的時間。

下一篇,將說明如何讀取儲存在 MicroSD 卡的圖片檔,並顯示在液晶螢幕上。


<<部落格相關網頁連結>>

2 則留言:

  1. 不好意思,打擾了,請問一下,塗鴉板上手繪過的路徑(X,Y座標)有辦法一一顯示在電腦上嗎?
    我們想利用塗鴉板將手繪的圖形的XY座標做轉換
    使我們實驗室的龍門繪圖機可以畫出跟塗鴉板上一樣的圖形,

    回覆刪除
    回覆
    1. 手指觸摸的位置抓到之後,才會轉換為螢幕畫素的位置;所以既然能夠知道觸摸的位置,將其輸出就可以! 可以使用 USB 轉 TTL 線連接電腦與 Arduino 就可以將 X, Y 座標顯示在電腦上!
      如果龍門繪圖機是吃 G-Code,想辦法將 X, Y 座標直接轉換成 G-Code 的方式試試;要不就是電腦收座標,然後由電腦端坐轉換的動作!

      刪除

留言屬名為"Unknown"或"不明"的用戶,大多這樣的留言都會直接被刪除掉,不會得到任何回覆!

發問問題,請描述清楚你(妳)的問題,別人回答前不會想去 "猜" 問題是什麼?

不知道怎麼發問,請看 [公告] 部落格提問須知 - 如何問問題 !