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()
{
    // 啥都不用做
}


发布了122 篇原创文章 · 获赞 61 · 访问量 53万+

猜你喜欢

转载自blog.csdn.net/ki1381/article/details/66974924
UNO