Arduino与Proteus仿真实例-电子相册仿真

电子相册仿真

本次实例将仿真如何从SD卡读取BMP格式图像并在ILI9341驱动器的LCD显示屏上显示。

1、仿真电路原理图

在这里插入图片描述

在仿真电路原理图中,SD卡通过SPI方式连接,ILI9341 LCD显示屏也是通过SPI方式连接。SD卡的CS引脚连接Arduino Mega2560的SS引脚(Pin10),显示屏的CS引脚连接Arduino Mega2560的Pin8引脚。

关于ILI9341 LCD驱动,请参考前面的文章:

关于SD卡驱动,请参考前面文章:

2、仿真代码实现

此次仿真实例,主要分为如下几个步骤:

  • 初始化SD卡
  • 初始化ILI9341
  • 加载图像
  • 显示图像

1)导入依赖库

1
2
3
4
5
6
#include <SPI.h>
#include <SD.h>

#include <Adafruit\_ILI9341.h>
#include <Adafruit\_GFX.h>

2)定义ILI9341显示设备

1
2
3
4
5
6
#define TFT\_CS 8 // TFT CS 引脚
#define TFT\_RST 9 // TFT RST 引脚
#define TFT\_DC 10 // TFT DC 引脚
// ILI9341设备对象
Adafruit_ILI9341 tft = Adafruit\_ILI9341(TFT_CS, TFT_DC, TFT_RST);

3)定义SD卡设备

1
2
3
4
5
Sd2Card card;
SdVolume volume;
SdFile root;
const int chipSelect = SS;

4)SD卡初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
void sdcard\_init(){

Serial.println("Initializing SD card...");

// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
if (!card.init(SPI_HALF_SPEED, chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("\* is a card inserted?");
Serial.println("\* is your wiring correct?");
Serial.println("\* did you change the chipSelect pin to match your shield or module?");
while (1);
} else {
Serial.println("Wiring is correct and a card is present.");
}

// print the type of card
Serial.println();
Serial.print("Card type: ");
switch (card.type()) {
case SD_CARD_TYPE_SD1:
Serial.println("SD1");
break;
case SD_CARD_TYPE_SD2:
Serial.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
Serial.println("SDHC");
break;
default:
Serial.println("Unknown");
}

// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
Serial.println("Could not find FAT16/FAT32 partition.\r\nMake sure you've formatted the card");
while (1);
}

Serial.print("Clusters: ");
Serial.println(volume.clusterCount());
Serial.print("Blocks x Cluster: ");
Serial.println(volume.blocksPerCluster());

Serial.print("Total Blocks: ");
Serial.println(volume.blocksPerCluster() \* volume.clusterCount());
Serial.println();

// print the type and size of the first FAT-type volume
uint32\_t volumesize;
Serial.print("Volume type is: FAT");
Serial.println(volume.fatType(), DEC);

volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize \*= volume.clusterCount(); // we'll have a lot of clusters
volumesize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB)
Serial.print("Volume size (Kb): ");
Serial.println(volumesize);
Serial.print("Volume size (Mb): ");
volumesize /= 1024;
Serial.println(volumesize);
Serial.print("Volume size (Gb): ");
Serial.println((float)volumesize / 1024.0);

Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);

// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
if(!SD.begin(chipSelect)){
Serial.println("SDCard Init failed");
while(1);
}
Serial.println("Sd card init done");
}
void progmemPrint(const char \*str) {
char c;
while(c = pgm\_read\_byte(str++)) Serial.print(c);
}
// Same as above, with trailing newline
void progmemPrintln(const char \*str) {
progmemPrint(str);
Serial.println();
}

5)ILI9341 LCD设备初始化

1
2
3
4
5
void tft\_lcd\_init(){
tft.begin();
tft.setRotation(1); // 设置为横向
}

6)在setup函数中初始化各设备

1
2
3
4
5
6
7
8
9
10
void setup(){
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

sdcard\_init();
tft\_lcd\_init();
}

7)从SD卡加载并解析BMP图像文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#define BUFFPIXEL 40

void bmpDraw(char \*filename, uint8\_t x, uint8\_t y) {

File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8\_t bmpDepth; // Bit depth (currently must be 24)
uint32\_t bmpImageoffset; // Start of image data in file
uint32\_t rowSize; // Not always = bmpWidth; may have padding
uint8\_t sdbuffer[3\*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
uint8\_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
uint8\_t r, g, b;
uint32\_t pos = 0, startTime = millis();

if((x >= tft.width()) || (y >= tft.height())) return;

Serial.println();
Serial.print("Loading image '");
Serial.print(filename);
Serial.println('\'');

// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print("File not found");
return;
}

// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print("File size: "); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print("Header size: "); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print("Bit Depth: "); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

goodBmp = true; // Supported BMP format -- proceed!
Serial.print("Image size: ");
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);

// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth \* 3 + 3) & ~3;

// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}

// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;

// Set TFT address window to clipped image bounds
tft.startWrite();
tft.setAddrWindow(x, y, w, h);

for (row=0; row<h; row++) { // 按行读取
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) \* rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row \* rowSize;
if(bmpFile.position() != pos) { // Need seek?
tft.endWrite();
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}

for (col=0; col<w; col++) { // For each pixel...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
tft.startWrite();
}

// 转换像素格式
r = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
b = sdbuffer[buffidx++];
tft.pushColor(tft.color565(b,g,r)); // 注意,ILI9341驱动库中显示的颜色格式为BGR
} // end pixel
} // end scanline
tft.endWrite();
Serial.print("Loaded in ");
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}

bmpFile.close();
if(!goodBmp) Serial.println("BMP format not recognized.");
}


// 从SD卡读取一位16/32位数据,小端。BMP数据以小端方式储存数据
uint16\_t read16(File f) {
uint16\_t result;
((uint8\_t \*)&result)[0] = f.read(); // LSB
((uint8\_t \*)&result)[1] = f.read(); // MSB
return result;
}

uint32\_t read32(File f) {
uint32\_t result;
((uint8\_t \*)&result)[0] = f.read(); // LSB
((uint8\_t \*)&result)[1] = f.read();
((uint8\_t \*)&result)[2] = f.read();
((uint8\_t \*)&result)[3] = f.read(); // MSB
return result;
}

8)在loop函数中,加载并显示图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void loop(){
tft.fillScreen(ILI9341_BLACK);
bmpDraw("IMAGE\_1.BMP", 0, 0);
delay(2000);

tft.fillScreen(ILI9341_BLACK);
bmpDraw("IMAGE\_2.BMP", 0, 0);
delay(2000);

tft.fillScreen(ILI9341_BLACK);
bmpDraw("IMAGE\_3.BMP", 0, 0);
delay(2000);

tft.fillScreen(ILI9341_BLACK);
bmpDraw("IMAGE\_4.BMP", 0, 0);
delay(2000);

tft.fillScreen(ILI9341_BLACK);
bmpDraw("IMAGE\_5.BMP", 0, 0);
delay(2000);

tft.fillScreen(ILI9341_BLACK);
bmpDraw("IMAGE\_6.BMP", 0, 0);
delay(2000);

}

3、仿真结果

在这里插入图片描述

文章来源: https://iotsmart.blog.csdn.net/article/details/127900420