1. 程式人生 > >UNO R3從SD卡讀取圖片並顯示到2.2寸液晶屏上(220x176)

UNO R3從SD卡讀取圖片並顯示到2.2寸液晶屏上(220x176)



折騰了一個週末,終於基本搞定。之前也玩過一陣,但沒能解決圖片大到一定程度後記憶體不足或者陣列超限的問題,

所以決定再試一下用SD卡。220x176的資料比較少,查了一圈壇內壇外中文外文的網站之後總算找到了一些思路。

大思路就是從SD卡中讀指定圖片檔案的每個畫素的RGB,然後在對應位置顯示。

我用的液晶模組解析度220x176,帶SD卡槽的,支援直插UNO,但SD卡相關的針腳要自己焊。另外還有一種320x240的也是2.2寸,看到的資料說是要電平轉換之後才能用。這個暫時先放一放。

接線很簡單,顯示相關的直接插進UNO R3,從5V開始一直到A5對準就行。原裝正品有個插座是悶掉的,所以液晶模組對應的引腳要掰掉。相容UNO在這個位置多數是個缺口所以可以不用管它。

SD卡部分接線也很簡單,按照PIN11 - PIN13的硬體SPI定義對應起來就行(官方示例的註釋中也有詳細說明)。另外有個SD_CS引腳,我是接在了10上。這個不是原則問題,因為一會兒程式碼中SD.begin的引數就是SD_CS。

反正SD部分不是很複雜,看下示例中的SD的DumpFile基本上就差不多了。多說一句,網上有說SD最好用2G以下,但是我用的SD卡是4G的。另外,示例中把pinMode是註釋掉的,我這裡不行,必須顯式指定它是OUTPUT,否則就是認不出SD卡。

圖片檔案我也走了點彎路,目前為止不算徹底解決,只是用了種比較麻煩的變通方式。理想狀況是用Bitmap檔案(JPEG、PNG等等都是編過碼的,考慮到微控制器可憐的16M時鐘頻率還要去解碼。。。所以資料還得直接喂。就這樣載入完都得近1分鐘)。seek(0x12)得到寬度,seek(0x16)得到高度,seek(0x36)起得到資料。這樣做是可行的,但我這裡測試下來遇到的最大問題是缺色。這麼說吧,人臉都是阿凡達。。。。。。Bitmap檔案結構還沒仔細研究過,估計跟製作Bitmap時的儲存選項或者到手的BMP檔案的調色盤有關係,稍後再折騰吧。

現在的做法是,自己用C#寫了個程式直接轉成一個畫素RGB檔案,沒有任何檔案頭。比方說有個寬3畫素高2畫素的圖片,第一行都是紅色,第二行都是綠色,那麼我輸出的檔案二進位制就是:
0xFF 0x00 0x00 0xFF 0x00 0x00 0xFF 0x00 0x00
0x00 0xFF 0x00 0x00 0xFF 0x00 0x00 0xFF 0x00
(為了照顧人類的閱讀習慣加了空格和換行,實際上沒有。缺點顯而易見,得自己知道寬高。)
共3*2*3=18位元組。

我相信是有現成的這種格式的,但不知道查詢的關鍵字。猜過RAW和MemoryBmp格式,但在我手裡都沒成功。

Arduino裡依次讀取每個位元組,每讀三次就能拿到一個畫素的RGB資訊,就可以在當前座標上顯示了。實際效果如圖:

主要程式碼如下,略去了很多異常判斷。完整演算法請參考官方示例。

#include <UTFT.h>
#include <SPI.h>
#include <SD.h>

const int chipSelect = 10;

UTFT lcd(QD220A, A2, A1, A5, A4, A3); 

void setup()
{
  int r, g, b;
  //Serial.begin(9600);

  pinMode(chipSelect, OUTPUT);

  lcd.InitLCD();
  lcd.clrScr();

  int width;
  int height;

  if (SD.begin(chipSelect)) {
    File bmpImage = SD.open("TEST.RAW", FILE_READ);
    
    /*

    bmpImage.seek(0x12);  // 寬度
    width = bmpImage.read();
    bmpImage.seek(0x16);  // 高度
    height = bmpImage.read();

    //Serial.println(width);
    //Serial.println(height);

    bmpImage.seek(0x36); //跳過Bitmap檔案頭
	
    */

    width = 220;
    height = 176;

    for (int y = 0; y < height; y ++) {
      for (int x = 0; x < width; x++) {

        r = bmpImage.read();
        g = bmpImage.read();
        b = bmpImage.read();

        lcd.setColor(r, g, b);
        lcd.drawPixel(x, y);
      }
    }

    bmpImage.close();
  }
}

void loop()
{
    // 啥都不用做
}