Arduino应用开发——LCD显示图片

目录

  • Arduino应用开发——LCD显示图片
    • 前言
    • 1 硬件介绍
      • 1.1 硬件配置
      • 1.2 硬件连接
    • 2 开发环境搭建
      • 2.1 安装开发板
      • 2.2 安装库
    • 3 LCD驱动的使用和测试
      • 3.1 修改TFT_eSPI库基础配置
      • 3.2 LCD驱动测试
    • 4 制作图片数据
      • 4.1 制作图片素材
      • 4.2 生成图片数据
        • 4.2.1 位图数据生成方法
        • 4.2.2 JPEG格式图片数据生成方法
    • 5 编写应用程序
    • 6 测试验证
    • 结束语

前言

LCD是项目中比较常用的外设,基于Arduino开发有个好处就是它很多相关的库可用,这对于项目的开发或者前期的方案验证来说是非常方便的,缺点是灵活性较差。Arduino支持很多硬件,我们这一讲主要基于ESP8266和ESP32来讲解图片的显示。

1 硬件介绍

1.1 硬件配置

本文的硬件配置如下:

模块 型号 说明
LCD ST7789 LCD常用的驱动IC有很多,如:ILI9341、ST7735等,不同的驱动IC,驱动代码也是有区别的
注:驱动IC型号和屏幕型号是不同的,不管屏幕的厂家是哪个,屏幕尺寸是多大,只有驱动IC型号一样,驱动代码都是一样的
ESP8266 ESP-12F 这是安信可的一款模组,内部主要是用乐鑫的ESP8266EX再加上一个片外FLASH组成
ESP32 ESP-WROOM-32 MCU是乐鑫的一款芯片,开发板型号ESP32 DEVKITV1

注:我这里以ESP8266和ESP32为例讲解,实际上根据自己的MCU选择一种即可,方法和原理都是一样的。

1.2 硬件连接

ESP8266接线如下:

esp8266 lcd 说明
VCC VCC 电源正
GND GND 电源负
GPIO14\HSPI_CLK CLK SPI时钟线
GPIO13\HSPI_MOSI SDI SPI数据线,esp8266输出,lcd输入
GPIO12\HSPI_MISO SDO SPI数据线,esp8266输入,lcd输出,注:该引脚一般可以不用,除非你要读取LCD的信息
GPIO4 CS SPI片选
GPIO5 WR(D/C) 并口时作为写入信号/SPI时作为命令或参数的选择
RST RST LCD复位引脚,可以用普通IO控制,引脚不足的情况下也可以和esp8266的复位引脚接到一起
特别说明:不同厂家做的LCD对这几个引脚的命名可能会有差异,但意思是一样的。

ESP32接线如下:

esp32 lcd 说明
VCC VCC 电源正
GND GND 电源负
GPIO18\SPI_CLK CLK SPI时钟线
GPIO23\SPI_MOSI SDI SPI数据线,esp32输出,lcd输入
GPIO19\SPI_MISO SDO SPI数据线,esp32输入,lcd输出,注:该引脚一般可以不用,除非你要读取LCD的信息
GPIO15 CS SPI片选
GPIO5 WR(D/C) 并口时作为写入信号/SPI时作为命令或参数的选择
GPIO4 RST LCD复位引脚,可以用普通IO控制,引脚不足的情况下也可以和esp32的复位引脚接到一起
特别说明:不同厂家做的LCD对这几个引脚的命名可能会有差异,但意思是一样的。

2 开发环境搭建

2.1 安装开发板

关于ESP8266和ESP32的Arduino环境搭建我之前出过教程了,这里就不多说了,不懂的同学可以先看下我之前的博客。
esp8266开发入门教程(基于Arduino)——环境安装
ESP32-S2 Arduino开发环境搭建

2.2 安装库

打开Arduino IDE,依次打开 工具 -> 管理库…
在搜索框输入需要安装的库名称,找到对应的库,点击安装即可。

本文需要使用的Arduino库如下:

Arduino库 版本 说明
TFT_eSPI 2.4.2 该库通过SPI方式驱动LCD,支持多种LCD常用驱动IC
JPEGDecoder 1.8.0 JPEG格式解码库,用来显示JPEG图片
注:TFT_eSPI库本身就支持显示图片,但是只能是16进制的位图数据,而JPEGDecoder是可以显示JPEG格式图片,两种方式其实都是可以的。

3 LCD驱动的使用和测试

LCD驱动的方式一般是用SPI、并口或者IIC,我这里是以SPI为例。我之前也发布过一篇关于LCD驱动讲解的博客,有什么不懂的话也可以去看一下。
esp8266应用教程——TFT LCD

3.1 修改TFT_eSPI库基础配置

安装好TFT_eSPI库之后需要根据自己电路实际的情况配置底层接口。
Arduino安装的库一般在C盘文档目录下,如:C:\Users\xxx\Documents\Arduino\libraries (xxx是你电脑的用户名)

找到TFT_eSPI文件夹,打开User_Setup.h文
件,修改以下几项参数。

1)驱动IC
根据自己使用的LCD驱动IC打开对应的宏。注意这些驱动只能选择一个打开,不用的要注释掉。

2)RGB数据格式
RGB格式指的是像素点颜色数据的排列方式,一般就BGR和RGB两种,区别其实就是数据高位在前还是低位在前,这个主要是用于图片显示,要用哪种格式主要是看你要显示的内容是怎么排的,不确定的话可以先不改,调试的时候如果颜色不对的话再换过来就好了。

3)像素
根据自己屏幕的像素修改,也可以先不改,直接在后面应用的时候再改。

4)GPIO
根据自己的电路设置引脚,除了几个必要的引脚,有些引脚可以不配置,如:RST可以通过硬件和MCU的RST接到一起,软件配置成-1即可。BL背光也可以硬件直接控制。
还有像ESP8266也可以不自定义SPI的几个引脚,它默认用的就是ESP8266硬件SPI的接口,你的接线保持一致即可。
注意:相同的GPIO定义只能打开一个,默认有些打开了的要注释掉。
特别说明:如果你用的是ESP32,TFT_eSPI建议使用2.4.0以上版本,因为之前的版本关于ESP32的引脚定义是分成HSPI和VSPI的,默认使用VSPI,如果要用HSPI要打开USE_HSPI_PORT定义,但是这套框架兼容性不强,不适用于ESP32-S2和ESP32-C2,而2.4.0以上版本取消了这个定义,直接都按引脚号来定义,这样一来就不用区分HSPI和VSPI了。

esp8266的引脚如下图所示,esp32的我就不贴出来了,都是差不多的。

5)字库
TFT_eSPI自带的这些字库你可以直接用,如果你有自己的字库不用这里的话也可以注释掉。flash空间足够的情况下,这点代码加不加都没关系。

6)SPI通讯速率
SPI通讯速率一般默认即可,默认的这个速率一般是足够了的,如果需要更快的话可以自己修改。

7)ESP32的特殊定义
TFT_eSPI旧版本关于ESP32的SPI接口是分为HSPI和VSPI两种的,默认使用VSPI,如果要用HSPI要打开USE_HSPI_PORT定义,如果你只是用ESP32,那这个框架是没什么问题的。
但是我之前因为项目需要从ESP32改用ESP32-S2,结果发现ESP32-S2就没有HSPI和VSPI,所有接口都是FSPI,于是我就要把底层很多东西都改掉才能正常使用。
不过现在TFT_eSPI库2.4.0以上版本就已经把这个问题改掉了,兼容了ESP32-S2和ESP-C3,取消了USE_HSPI_PORT这个定义,SPI接口都以GPIO引脚号来定义。所以,我建议都用新版本的库吧,兼容性更好,也不用去考虑用HSPI还是VSPI。

3.2 LCD驱动测试

TFT_eSPI库配置好了之后可以先烧录一个简单的程序测试一下硬件和代码是否能正常运行。
PS:当然,到了后面把图片数据做好直接显示图片也是可以的。

#include <SPI.h>
#include <TFT_eSPI.h>TFT_eSPI tft = TFT_eSPI(); void setup()
{Serial.begin(115200);tft.begin();tft.setRotation(0);tft.fillScreen(TFT_BLACK);
}void loop()
{tft.fillScreen(TFT_GREEN);delay(1000);tft.fillScreen(TFT_BLUE);delay(1000);tft.fillScreen(TFT_RED);delay(1000);
}

4 制作图片数据

图片数据可以按位图的形式保存和显示,也可以按jpg格式保存。区别在于位图的方式占用的内存都是固定的,只跟像素大小有关,而相同像素下jpg的内存一般要更小,具体占用的内存大小跟图片的色彩复杂度有关,但是jpg的缺点是需要解码,而位图数据则不需要解码。
两种方式都可以选,根据自己的需求来用就行了。位图的话直接用TFT_eSPI库就行了,而jpg格式还需要使用JPEGDecoder库解码。

4.1 制作图片素材

网上随便找一张图片,借助WIN10自带图片编辑器或者其他图片处理软件把图片处理一下,裁剪出自己想要显示的内容之后,再把分辨率调整成适合的大小,图片以jpg,bmp或者其他格式保存都是可以的。
例如下面这张图片:
这是240x240分辨率的一张图片。

4.2 生成图片数据

我们可以借助一些工具来实现图片到数据的转换。我们的数据要以C语言数组的形式存储,像素颜色数据以16进制的形式保存。

4.2.1 位图数据生成方法

位图数据的工具很多,比如:Img2Lcd,lcd-image-converter等。
工具可以在下面的链接下载,也可以在网上自己查找。
工具链接:https://pan.baidu.com/s/1f2rgD1a9PY-_hboPdbfaow
提取码:4h6h

1)Img2Lcd使用方法
打开一张图片。
设置配置如下:
输出数据类型:C语言数组
扫描方式:水平扫描
输出灰度:16位真彩色
最大宽度和高度:自定义
下面的几个选项只勾选“高位在前(MSB First)”即可。(说明一下:高位在前的意思是指数据以GBR方式导出,如果不勾选的话则是以RGB方式导出,用哪种其实取决于你后面显示图片的那个函数处理数据的方式,保持一致即可。)

配置好参数之后点击保存,以.h文件保存即可。保存好这个头文件,后面会用到。
保存的这个头文件数据格式如下:

这个数组的定义我们可以改一下,因为图片的数据一般比较多,全部用RAM来存的话内存可能不足,所以我们可以把这些数据存放到flash里面。
修改定义之前:

const unsigned char gImage_demo_image1[115200] = { /* 0X10,0X10,0X00,0XF0,0X00,0XF0,0X01,0X1B, */

修改定义之后:

#ifndef PROGMEM
#define PROGMEM
#endif
const uint8_t gImage_demo_image1[115200] PROGMEM = { /* 0X10,0X10,0X00,0XF0,0X00,0XF0,0X01,0X1B, */

PROGMEM的用法具体我就不说了,不懂的可以自己去查。

2)lcd-image-converter使用方法
打开一张图片,点击 Options -> Conversion…

参数配置好了之后点击"Show Preview"即可看到图片转换后的位图数据。
这个软件不能直接生成头文件,需要自己另外新建一个头文件,然后定义一个数组,再把这些数据拷贝进去。

4.2.2 JPEG格式图片数据生成方法

我这里用的转换工具是在GitHub上面找到的一个代码,你们想要的话可以在下面的链接下载。这个工具使用起来稍微有点麻烦,如果你有更好的工具也可以推荐给博主。

工具链接:https://pan.baidu.com/s/1f2rgD1a9PY-_hboPdbfaow
提取码:4h6h

运行方法如下:
第一步:把要转换的图片放到这个工具的目录下。

第二步:打开电脑的运行窗口(win10可以使用win+R快捷键),输入“cmd”打开命令窗口。

第三步:在命令窗口中输入跳转命令,跳转到转换工具所在的目录下。
例如:

cd C:\Users\z\Desktop\图片处理工具\image_to_c\dist\Windows


第四步:运行应用程序。
格式:应用程序名+空格+图片名+空格+>+空格+转换后的文件名。
例如:

image_to_c64.exe demo-image1.jpg > demo-image1.h


运行成功的话就会生成相应的头文件。

5 编写应用程序

使用Arduino IDE新建并保存一个工程,把图片数据(.h文件)放到工程目录下。然后编写应用代码。
示例代码如下:
特别说明:该代码是用ESP32-S2进行测试的,ESP32和ESP8266我之前也调试过,不是下面的这个代码,不过写法基本都是一样的。主要是TFT_eSPI库的引脚改一下即可。
本文所用源码和图片素材都上传到云盘了,可以在文章底部链接下载。

#include <SPI.h>
#include <TFT_eSPI.h>
// #include "Arduino.h"#ifdef ESP8266
#include <avr/pgmspace.h>
#else
#include <pgmspace.h>
#endif// 图片位图数据,注意:下面这几个只是示例文件,而且都是240x240分辨率的图片,内存比较大,如果你用的FLASH内存不足的话编译会出错
#include "demo_image1.h"
#include "demo_image2.h"
#include "demo_image3.h"
#include "test_image.h"// #define JPEG_ENABLE   // 打开该宏使用JPEG解码TFT_eSPI tft = TFT_eSPI(); // JPEG图片显示相关函数
#ifdef JPEG_ENABLE
// JPEG decoder library
#include <JPEGDecoder.h>
#include "demo_jpg1.h"
#include "demo_jpg2.h"
#include "demo_jpg3.h"// Return the minimum of two values a and b
#define minimum(a,b)     (((a) < (b)) ? (a) : (b))//####################################################################################################
// Draw a JPEG on the TFT pulled from a program memory array
//####################################################################################################
void drawArrayJpeg(const uint8_t arrayname[], uint32_t array_size, int xpos, int ypos) {int x = xpos;int y = ypos;JpegDec.decodeArray(arrayname, array_size);jpegInfo(); // Print information from the JPEG file (could comment this line out)renderJPEG(x, y);Serial.println("#########################");
}//####################################################################################################
// Draw a JPEG on the TFT, images will be cropped on the right/bottom sides if they do not fit
//####################################################################################################
// This function assumes xpos,ypos is a valid screen coordinate. For convenience images that do not
// fit totally on the screen are cropped to the nearest MCU size and may leave right/bottom borders.
void renderJPEG(int xpos, int ypos) {// retrieve infomration about the imageuint16_t *pImg;uint16_t mcu_w = JpegDec.MCUWidth;uint16_t mcu_h = JpegDec.MCUHeight;uint32_t max_x = JpegDec.width;uint32_t max_y = JpegDec.height;// Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)// Typically these MCUs are 16x16 pixel blocks// Determine the width and height of the right and bottom edge image blocksuint32_t min_w = minimum(mcu_w, max_x % mcu_w);uint32_t min_h = minimum(mcu_h, max_y % mcu_h);// save the current image block sizeuint32_t win_w = mcu_w;uint32_t win_h = mcu_h;// record the current time so we can measure how long it takes to draw an imageuint32_t drawTime = millis();// save the coordinate of the right and bottom edges to assist image cropping// to the screen sizemax_x += xpos;max_y += ypos;// read each MCU block until there are no morewhile (JpegDec.readSwappedBytes()) {// save a pointer to the image blockpImg = JpegDec.pImage ;// calculate where the image block should be drawn on the screenint mcu_x = JpegDec.MCUx * mcu_w + xpos;  // Calculate coordinates of top left corner of current MCUint mcu_y = JpegDec.MCUy * mcu_h + ypos;// check if the image block size needs to be changed for the right edgeif (mcu_x + mcu_w <= max_x) win_w = mcu_w;else win_w = min_w;// check if the image block size needs to be changed for the bottom edgeif (mcu_y + mcu_h <= max_y) win_h = mcu_h;else win_h = min_h;// copy pixels into a contiguous blockif (win_w != mcu_w){uint16_t *cImg;int p = 0;cImg = pImg + win_w;for (int h = 1; h < win_h; h++){p += mcu_w;for (int w = 0; w < win_w; w++){*cImg = *(pImg + w + p);cImg++;}}}// draw image MCU block only if it will fit on the screenif (( mcu_x + win_w ) <= tft.width() && ( mcu_y + win_h ) <= tft.height()){tft.pushRect(mcu_x, mcu_y, win_w, win_h, pImg);}else if ( (mcu_y + win_h) >= tft.height()) JpegDec.abort(); // Image has run off bottom of screen so abort decoding}// calculate how long it took to draw the imagedrawTime = millis() - drawTime;// print the results to the serial portSerial.print(F(  "Total render time was    : ")); Serial.print(drawTime); Serial.println(F(" ms"));Serial.println(F(""));
}//####################################################################################################
// Print image information to the serial port (optional)
//####################################################################################################
void jpegInfo() {Serial.println(F("==============="));Serial.println(F("JPEG image info"));Serial.println(F("==============="));Serial.print(F(  "Width      :")); Serial.println(JpegDec.width);Serial.print(F(  "Height     :")); Serial.println(JpegDec.height);Serial.print(F(  "Components :")); Serial.println(JpegDec.comps);Serial.print(F(  "MCU / row  :")); Serial.println(JpegDec.MCUSPerRow);Serial.print(F(  "MCU / col  :")); Serial.println(JpegDec.MCUSPerCol);Serial.print(F(  "Scan type  :")); Serial.println(JpegDec.scanType);Serial.print(F(  "MCU width  :")); Serial.println(JpegDec.MCUWidth);Serial.print(F(  "MCU height :")); Serial.println(JpegDec.MCUHeight);Serial.println(F("==============="));
}//####################################################################################################
// Show the execution time (optional)
//####################################################################################################
// WARNING: for UNO/AVR legacy reasons printing text to the screen with the Mega might not work for
// sketch sizes greater than ~70KBytes because 16 bit address pointers are used in some libraries.// The Due will work fine with the HX8357_Due library.void showTime(uint32_t msTime) {//tft.setCursor(0, 0);//tft.setTextFont(1);//tft.setTextSize(2);//tft.setTextColor(TFT_WHITE, TFT_BLACK);//tft.print(F(" JPEG drawn in "));//tft.print(msTime);//tft.println(F(" ms "));Serial.print(F(" JPEG drawn in "));Serial.print(msTime);Serial.println(F(" ms "));
}
#endifvoid setup()
{Serial.begin(115200);tft.begin();tft.setRotation(0);tft.fillScreen(TFT_BLACK);
}void loop()
{#if 1tft.pushImage(0, 0, 240, 240, (uint16_t*)test_image);delay(1000);tft.pushImage(0, 0, 240, 240, (uint16_t*)gImage_demo_image1);delay(1000);tft.pushImage(0, 0, 240, 240, (uint16_t*)gImage_demo_image2);delay(1000);tft.pushImage(0, 0, 240, 240, (uint16_t*)gImage_demo_image3);delay(1000);
#endif#ifdef JPEG_ENABLEdrawArrayJpeg(demo_image1, sizeof(demo_image1), 0, 0);delay(1000);drawArrayJpeg(demo_image2, sizeof(demo_image2), 0, 0);delay(1000);drawArrayJpeg(demo_image3, sizeof(demo_image3), 0, 0);delay(1000);
#endif
}

6 测试验证

4张图片间隔轮1秒流播放的效果如下,手机拍屏幕会有很大的色差,这个没办法,将就着看吧,反正上面例程效果大概就是这样的。不管是用位图数据显示还是jpg格式显示,最终的结果是一样的。

结束语

这一讲简单介绍了在Arduino环境下使用LCD显示图片,主要介绍了位图和JPEG格式的显示,其他格式比如PNG其实也是可以解码的,不过这里就不再讲解了,感兴趣的同学自己去找相应的库吧。整个流程总的来说还是不难的,把驱动调好之后直接凋库显示就完了。如果还有什么问题,欢迎在评论区留言或者私信给我。

想要源代码或者图片处理工具的自行下载:
链接:https://pan.baidu.com/s/1f2rgD1a9PY-_hboPdbfaow
提取码:4h6h

Arduino开发教程汇总:
https://blog.csdn.net/ShenZhen_zixian/article/details/121659482

Arduino应用开发——LCD显示图片相关推荐

  1. Arduino应用开发——LCD显示GIF动图

    Arduino应用开发--LCD显示GIF动图 目录 Arduino应用开发--LCD显示GIF动图 前言 1 硬件介绍 1.1 硬件配置 1.2 硬件连接 2 开发环境搭建 2.1 安装开发板 2. ...

  2. 【龙芯1B】:LCD显示图片文字背景色前景色、小创语音控制lcd显示、数码管倒计时

    项目场景:     闲来无事,写了几个关于嵌入式技能大赛的任务.希望对大家有所帮助.本文开发板由百科荣创的龙芯1b开发板支持,关于嵌入式技能大赛的开发板.  LCD显示图片&文字&背景 ...

  3. java开发 图片显示不出来_java web开发中 显示图片的问题

    记录一个java Web开发中显示图片的小问题: 我碰到的问题是:把服务器上存的图片,在客户端的浏览器中显示出来.解决方法如下: 两种显示方式 一是:在servlet 或 action中直接输入图片到 ...

  4. 深入理解ARM体系架构(S3C6410)---lcd 显示图片

    本系列文章由张同浩编写,转载请注明出处:http://blog.csdn.net/muge0913/article/details/7437153 邮箱:muge0913@sina.com S3C64 ...

  5. 如何使用STM32指南者LCD显示图片

    一.上面是不完整的程序,包括LCD GPIO的初始化,FSMC模拟时序结构体的设计还有写命令函数与写数据函数,这些函数都可以在B站上找到源程序,完成这些之后,接下来要说的是如何获得图片的十六进制,就是 ...

  6. ESP32开发-LVGL显示图片

    图片使用方式 LVGL中可以使用两种方式显示图片 1.作为内部存储器(RAM 或 ROM)中的变量 2.作为文件 内部读取图片 优点:数据跟代码一起编译成固件,使用方便. 缺点:图片需要用工具转化成数 ...

  7. Android开发中显示图片Glide使用详解(Google推荐)

    一.简介 Glide,一个被google所推荐的图片加载库,作者是bumptech.这个库被广泛运用在google的开源项目中,包括2014年的google I/O大会上发布的官方app.(PS:众所 ...

  8. Linux应用开发-LCD显示BMP图片

    1. 前言 BMP是一种与硬件设备无关的图像文件格式,是Windows环境中交换与图有关的数据的一种标准,在Windows环境中运行的图形图像软件都支持BMP图像格式.BMP格式的图片存放的就是原始的 ...

  9. android lcd 显示图片,Android开发中通过AIDL文件中的方法打开钱箱,显示LCD屏幕

    下载相关 资源文件 ,在项目中新建如下层级的文件夹,将源文件中的AIDL文件放入其中. ICallback:打印服务执行结果的回调 ITax:打印服务执行结果的回调 ILcdCallback:顾显反馈 ...

  10. OKI单片机开发-LCD显示

    本章主要讲解如何利用OKI单片机驱动LCD,并且转换之后,显示到开发板屏幕之中,那么,在开发之前,我们上一章节讲解了点亮LED,因此总结LCD也不难,如下所示: Demo:点亮LED 第一步:LCD寄 ...

最新文章

  1. mysql自动增长恢复_mysql自动增长的有关问题,怎么恢复从1开始
  2. 如何利用FineReport制作动态树报表
  3. 【正一专栏】梅西!梅西!梅西!
  4. 多人互砍游戏的后台服务器的多线程架构
  5. python3.4学习笔记(二十一) python实现指定字符串补全空格、前面填充0的方法
  6. asp.net 下载文件
  7. C# winform webbrowser如何指定内核为IE11?
  8. 移动端图片裁剪上传—jQuery.cropper.js
  9. asp.net中使用FreeTextBox控件
  10. Python飞机大战+图片
  11. Hadoop各组件详解
  12. idea上传新项目至svn仓库
  13. 下拉框输入模糊查询_高考英语听力考试查询、网上填报志愿时间、诈骗陷阱提防!全在这里了...
  14. 1到100号的灯开关问题
  15. ios给按钮图片根据不同的主题更改颜色
  16. Python中的字符串下标
  17. 软件概要设计说明书模版
  18. 一套政务OA系统,助力高效线上办公
  19. Head First C#中文版 图文皆译 (page13)
  20. C语言学习基础(day06)(达内)

热门文章

  1. 超给力,一键生成数据库文档-数据库表结构逆向工程
  2. Excel自动化报表制作
  3. uwb定位与wifi、蓝牙和RFID定位技术的区别
  4. WPF实现DoEvents
  5. 品优购架构和数据库结构
  6. catia v5r18 百度云_CATIA V5 R18全套的教程.pdf
  7. 百度网盘 海量资源链接
  8. linux系统安装yarn,centos安装yarn
  9. 前端截图与贴图神器snipaste下载与常见问题(1)
  10. 近视矫正手术:准分子激光,飞秒,全飞秒