Débutant en Arduino, mes connaissances en programmation était surtout le Pascal. (il y a longtemps).
Pour une maquette (salle de contrôle du NCC-1701 série STAR TREK), j'avais besoin d'afficher divers images sur plusieurs écrans. ( 1er série de 5 écrans (sur 12 de la maquette) avec 1 lecteur SD et une carte NANO, pour la puissance 2 alim 5v et 3.3 3A.
voici donc mon code source , pour le câblage mes photos ne sont pas terribles, j'ai essayé de détailler au mieux sur le code.
/* image bmp 24 bits, ecran tft 128x160/ 1.8", 240x280/1.69", 135x240/1.14"
Affichage d'images en format .bmp sur un
5 écrans 4 ST7735 et 1 ST7789 avec lecteurcarte sd, module arduino NANO
auteur: SKRZYPEK Frederic
basé sur
https://electroniqueamateur.blogspot.com/2020/04/aficher-sur-un-ecran-st7735-les.html
*/
// inclusion des bibliothèques
#include <Adafruit_GFX.h> // graphics library
#include <Adafruit_ST7789.h> // spécifique à l'écran
#include <Adafruit_ST7735.h> // spécifique à l'écran
#include <SPI.h> // communication SPI (écran et carte SD)
#include <SD.h> // carte SD
// définition des broches utilisée
#define ECRAN_CS 10 // Aout R=1kΩ
#define ECRAN_DC 9 // Aout R=1kΩ
//#define ECRAN_RST5 5
#define RESET_RST -1 // 2 bornes RST sur NANO
//D11 -> MOSI SD + SDA TFT (ecran3.3v 1/2/3/4 Aout R=1kΩ, ecran 5v pas de resistance sur commun carte sd et sck ecran )
//D12 -> MISO SD
//D13 -> SCK SD + SCL TFT
#define SD_CS 4
#define ECRAN1_CS A0 // Aout R=1kΩ
#define ECRAN1_DC A1 // Aout R=1kΩ
#define ECRAN2_CS A3// Aout R=1kΩ
#define ECRAN2_DC A2 // Aout R=1kΩ
#define ECRAN3_CS A4 // Aout R=1kΩ
#define ECRAN3_DC A5 // Aout R=1kΩ
#define ECRAN4_CS 8 // Aout R=1kΩ
#define ECRAN4_DC 7 // Aout R=1kΩ
//--- jusqu a 7 ecrans maxi si SD_cs sur D10 ( D3 D2 / D4 D5 / D6 D7 / D8 D9 / A0 A1 / A2 A3 / A4 A5). A6 A7 / RX0 TX1 ne fonctionne pas pour les ecrans CS DC.
#define dureeAffichage 7500 // Duree d'affichage
Adafruit_ST7735 tft = Adafruit_ST7735(ECRAN_CS, ECRAN_DC,RESET_RST);
Adafruit_ST7789 tft1 = Adafruit_ST7789(ECRAN1_CS, ECRAN1_DC, RESET_RST);
Adafruit_ST7789 tft2 = Adafruit_ST7789(ECRAN2_CS, ECRAN2_DC, RESET_RST);
Adafruit_ST7789 tft3 = Adafruit_ST7789(ECRAN3_CS, ECRAN3_DC, RESET_RST);
Adafruit_ST7789 tft4 = Adafruit_ST7789(ECRAN4_CS, ECRAN4_DC,RESET_RST );
// ------------------------------------variables
int largeur_image=0;
int hauteur_image=0;
int mon_ecran240 =0;
int mon_ecran280 =0;
#define CORNER_RADIUS 0
// - -----_-----------------------definition des couleurs
#define NOIR 0x0000
#define BLEU 0x001F
#define ROUGE 0xF800
#define VERT 0x07E0
#define CYAN 0x07FF
#define VIOLLET 0xF81F
#define JAUNE 0xFFE0
#define BLANC 0xFFFF
void setup(void) {
Serial.begin(9600); // utile pour débogage
tft.initR(INITR_BLACKTAB); // intialisation des écrans
tft1.init(135,240);
tft2.init(240,280);
tft3.init(240,280);
tft4.init(135,240);
tft.setRotation(3); // mode paysage
tft1.setRotation(1); // mode paysage
tft2.setRotation(3); // mode paysage
tft3.setRotation(3); // mode paysage
tft4.setRotation(1); // mode paysage
//Serial.print("Initialisation de la carte SD...");
if (!SD.begin(SD_CS)) {
Serial.println("Echec!");
return;
}
Serial.println("Reussie!");
//------------------------------TEST des ecrans
tft.fillScreen(0);
tft1.fillScreen(0);
tft2.fillScreen(0);
tft3.fillScreen(0);
tft4.fillScreen(0);
delay(200);
tft4.fillRect(0,0,135,240, BLEU);
tft4.drawRect(0,0,135,240, BLEU);
tft4.fillRect(0,0,135,240,ROUGE);
tft4.drawRect(0,0,135,240, ROUGE);
delay(200);
tft1.fillRect(0,0,135,240, JAUNE);
tft1.drawRect(0,0,135,240,JAUNE);
tft1.fillRect(0,0,135,240,VERT);
tft1.drawRect(0,0,135,240, VERT);
delay(200);
tft2.fillRect(0,0,240,280,CYAN);
tft2.drawRect(0,0,240,280, CYAN);
tft2.fillRect(0,0,240,280,BLEU);
tft2.drawRect(0,0,240,280, BLEU);
delay(200);
tft3.fillRect(0,0,240,280, VERT);
tft3.drawRect(0,0,240,280,VERT);
tft3.fillRect(0,0,240,280,VIOLLET);
tft3.drawRect(0,0,240,280, VIOLLET);
delay(200);
}
void loop() {
// on regarde le contenu de la carte SD, et on tente
// d'afficher chaque fichier, un après l'autre.
File root = SD.open("/");
while (true) {
File entry = root.openNextFile();
if (! entry) {
root.close();
return;
} // fichier lu mais inexistant ? SYSTEM~1 genere un retour au 1er bmp
if (entry.name() =='SYSTEM~1') {
Serial.print(entry.name());
delay(200); }
else {
controlelataille(entry.name(), 0, 0);
Serial.print(largeur_image); // je controle la taille de l'image pour envoie sur mon bon ecran
if (largeur_image == 160 ) {
bmpDraw160(entry.name(), 0, 0);
}
if (largeur_image == 240 ) {
if (mon_ecran240 == 0) {
bmpDraw240_1(entry.name(), 0, 0);
mon_ecran240 = 1 ;}
else {bmpDraw240_2(entry.name(), 0, 0);
mon_ecran240 = 0;}
}
if (largeur_image == 280 ) {
if (mon_ecran280 == 0) {
bmpDraw280_1(entry.name(), 0, 0);
mon_ecran280 = 1 ;}
else {bmpDraw280_2(entry.name(), 0, 0);
mon_ecran280 = 0;}
}
delay(1000);
}
entry.close();
}
}
//-----------------------------------------------------------------------------------------------------------------------------
#define BUFFPIXEL 20// nombre de pixels traités à la fois.
// la fonction bmpDrawd'Adafruit qui affiche un fichier .bmp:
void bmpDraw160(char *filename, uint8_t x, uint16_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // largeur et hauteur en pixels
uint8_t bmpDepth; // bits par pixels (doit être 24)
uint32_t bmpImageoffset; // Début de la description de l'image dans le fichier
uint32_t rowSize;
uint8_t sdbuffer[3 * BUFFPIXEL];
uint8_t buffidx = sizeof(sdbuffer);
boolean goodBmp = false;
boolean flip = true;
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.print(F("Chargement de l'image "));
// Serial.println(filename);
// ouverture du fichier
if ((bmpFile = SD.open(filename)) == NULL) {
// Serial.print(F("Fichier non trouve"));
return;
}
// Analyse du fichier
if (read16(bmpFile) == 0x4D42) { // lecture des 16 premiers bits du fichier <
read32(bmpFile); // lecture des 32 bits suivants (pas utiles)
read32(bmpFile);
bmpImageoffset = read32(bmpFile);
read32(bmpFile);
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if (read16(bmpFile) == 1) {
bmpDepth = read16(bmpFile); // bits par pixel
if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = non compressé
goodBmp = true; // Supported BMP format -- proceed!
rowSize = (bmpWidth * 3 + 3) & ~3;
if (bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if ((x + w - 1) >= tft.width()) w = tft.width() - x;
if ((y + h - 1) >= tft.height()) h = tft.height() - y;
tft.startWrite();
tft.setAddrWindow(x, y, w, h);
for (row = 0; row < h; row++) { // pour chaque ligne
if (flip)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) {
tft.endWrite();
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer);
}
for (col = 0; col < w; col++) { // pour chaque pixel
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
tft.startWrite();
}
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft.pushColor(tft.color565(r, g, b));
} // fin pixel
} // fin ligne
tft.endWrite();
delay(2000); // on laisse l'image à l'écran 20 secondes
} // fin goodBmp
}
}
bmpFile.close();
if (!goodBmp) Serial.println(F("Format de BMP non reconnu"));
}//--------------------------------------------------------------------------------------------------------------
void bmpDraw240_1(char *filename, uint8_t x, uint16_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // largeur et hauteur en pixels
uint8_t bmpDepth; // bits par pixels (doit être 24)
uint32_t bmpImageoffset; // Début de la description de l'image dans le fichier
uint32_t rowSize;
uint8_t sdbuffer[3 * BUFFPIXEL];
uint8_t buffidx = sizeof(sdbuffer);
boolean goodBmp = false;
boolean flip = true;
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if ((x >= tft1.width()) || (y >= tft1.height())) return;
//Serial.print(F("Chargement de l'image "));
// Serial.println(filename);
// ouverture du fichier
if ((bmpFile = SD.open(filename)) == NULL) {
// Serial.print(F("Fichier non trouve"));
return;
}
// Analyse du fichier
if (read16(bmpFile) == 0x4D42) { // lecture des 16 premiers bits du fichier <
read32(bmpFile); // lecture des 32 bits suivants (pas utiles)
read32(bmpFile);
bmpImageoffset = read32(bmpFile);
read32(bmpFile);
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if (read16(bmpFile) == 1) {
bmpDepth = read16(bmpFile); // bits par pixel
if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = non compressé
goodBmp = true; // Supported BMP format -- proceed!
rowSize = (bmpWidth * 3 + 3) & ~3;
if (bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if ((x + w - 1) >= tft1.width()) w = tft1.width() - x;
if ((y + h - 1) >= tft1.height()) h = tft1.height() - y;
tft1.startWrite();
tft1.setAddrWindow(x, y, w, h);
for (row = 0; row < h; row++) { // pour chaque ligne
if (flip)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) {
tft1.endWrite();
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer);
}
for (col = 0; col < w; col++) { // pour chaque pixel
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
tft1.startWrite();
}
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft1.pushColor(tft.color565(r, g, b));
} // fin pixel
} // fin ligne
tft1.endWrite();
//delay(2000); // on laisse l'image à l'écran 20 secondes
} // fin goodBmp
}
}
bmpFile.close();
if (!goodBmp) Serial.println(F("Format de BMP non reconnu"));
} //-------------------------------- fin image 240 ecran n°1
void bmpDraw240_2(char *filename, uint8_t x, uint16_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // largeur et hauteur en pixels
uint8_t bmpDepth; // bits par pixels (doit être 24)
uint32_t bmpImageoffset; // Début de la description de l'image dans le fichier
uint32_t rowSize;
uint8_t sdbuffer[3 * BUFFPIXEL];
uint8_t buffidx = sizeof(sdbuffer);
boolean goodBmp = false;
boolean flip = true;
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if ((x >= tft4.width()) || (y >= tft4.height())) return;
//Serial.print(F("Chargement de l'image "));
// Serial.println(filename);
// ouverture du fichier
if ((bmpFile = SD.open(filename)) == NULL) {
// Serial.print(F("Fichier non trouve"));
return;
}
// Analyse du fichier
if (read16(bmpFile) == 0x4D42) { // lecture des 16 premiers bits du fichier <
read32(bmpFile); // lecture des 32 bits suivants (pas utiles)
read32(bmpFile);
bmpImageoffset = read32(bmpFile);
read32(bmpFile);
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if (read16(bmpFile) == 1) {
bmpDepth = read16(bmpFile); // bits par pixel
if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = non compressé
goodBmp = true; // Supported BMP format -- proceed!
rowSize = (bmpWidth * 3 + 3) & ~3;
if (bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if ((x + w - 1) >= tft4.width()) w = tft4.width() - x;
if ((y + h - 1) >= tft4.height()) h = tft4.height() - y;
tft4.startWrite();
tft4.setAddrWindow(x, y, w, h);
for (row = 0; row < h; row++) { // pour chaque ligne
if (flip)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) {
tft4.endWrite();
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer);
}
for (col = 0; col < w; col++) { // pour chaque pixel
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
tft4.startWrite();
}
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft4.pushColor(tft.color565(r, g, b));
} // fin pixel
} // fin ligne
tft4.endWrite();
//delay(2000); // on laisse l'image à l'écran 20 secondes
} // fin goodBmp
}
}
bmpFile.close();
if (!goodBmp) Serial.println(F("Format de BMP non reconnu"));
} //-------------------------------- fin image 240 second
void bmpDraw280_1(char *filename, uint8_t x, uint16_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // largeur et hauteur en pixels
uint8_t bmpDepth; // bits par pixels (doit être 24)
uint32_t bmpImageoffset; // Début de la description de l'image dans le fichier
uint32_t rowSize;
uint8_t sdbuffer[3 * BUFFPIXEL];
uint8_t buffidx = sizeof(sdbuffer);
boolean goodBmp = false;
boolean flip = true;
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if ((x >= tft2.width()) || (y >= tft2.height())) return;
//Serial.print(F("Chargement de l'image "));
// Serial.println(filename);
// ouverture du fichier
if ((bmpFile = SD.open(filename)) == NULL) {
// Serial.print(F("Fichier non trouve"));
return;
}
// Analyse du fichier
if (read16(bmpFile) == 0x4D42) { // lecture des 16 premiers bits du fichier <
read32(bmpFile); // lecture des 32 bits suivants (pas utiles)
read32(bmpFile);
bmpImageoffset = read32(bmpFile);
read32(bmpFile);
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if (read16(bmpFile) == 1) {
bmpDepth = read16(bmpFile); // bits par pixel
if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = non compressé
goodBmp = true; // Supported BMP format -- proceed!
rowSize = (bmpWidth * 3 + 3) & ~3;
if (bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if ((x + w - 1) >= tft2.width()) w = tft2.width() - x;
if ((y + h - 1) >= tft2.height()) h = tft2.height() - y;
tft2.startWrite();
tft2.setAddrWindow(x, y, w, h);
for (row = 0; row < h; row++) { // pour chaque ligne
if (flip)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) {
tft2.endWrite();
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer);
}
for (col = 0; col < w; col++) { // pour chaque pixel
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
tft2.startWrite();
}
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft2.pushColor(tft.color565(r, g, b));
} // fin pixel
} // fin ligne
tft2.endWrite();
delay(2000); // on laisse l'image à l'écran 20 secondes
} // fin goodBmp
}
}
bmpFile.close();
if (!goodBmp) Serial.println(F("Format de BMP non reconnu"));
} //-----------------------fin ecran 280
void bmpDraw280_2(char *filename, uint8_t x, uint16_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // largeur et hauteur en pixels
uint8_t bmpDepth; // bits par pixels (doit être 24)
uint32_t bmpImageoffset; // Début de la description de l'image dans le fichier
uint32_t rowSize;
uint8_t sdbuffer[3 * BUFFPIXEL];
uint8_t buffidx = sizeof(sdbuffer);
boolean goodBmp = false;
boolean flip = true;
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if ((x >= tft3.width()) || (y >= tft3.height())) return;
//Serial.print(F("Chargement de l'image "));
// Serial.println(filename);
// ouverture du fichier
if ((bmpFile = SD.open(filename)) == NULL) {
// Serial.print(F("Fichier non trouve"));
return;
}
// Analyse du fichier
if (read16(bmpFile) == 0x4D42) { // lecture des 16 premiers bits du fichier <
read32(bmpFile); // lecture des 32 bits suivants (pas utiles)
read32(bmpFile);
bmpImageoffset = read32(bmpFile);
read32(bmpFile);
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if (read16(bmpFile) == 1) {
bmpDepth = read16(bmpFile); // bits par pixel
if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = non compressé
goodBmp = true; // Supported BMP format -- procedé!
rowSize = (bmpWidth * 3 + 3) & ~3;
if (bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if ((x + w - 1) >= tft3.width()) w = tft3.width() - x;
if ((y + h - 1) >= tft3.height()) h = tft3.height() - y;
tft3.startWrite();
tft3.setAddrWindow(x, y, w, h);
for (row = 0; row < h; row++) { // pour chaque ligne
if (flip)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) {
tft3.endWrite();
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer);
}
for (col = 0; col < w; col++) { // pour chaque pixel
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
tft3.startWrite();
}
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft3.pushColor(tft.color565(r, g, b));
} // fin pixel
} // fin ligne
tft3.endWrite();
//delay(2000); // on laisse l'image à l'écran 20 secondes
} // fin goodBmp
}
}
bmpFile.close();
if (!goodBmp) Serial.println(F("Format de BMP non reconnu"));
} //-----------------------fin ecran 280 second
// pour controle taille image
void controlelataille(char *filename, uint8_t x, uint16_t y) {
File bmpFile;
int bmpWidth, bmpHeight;
uint8_t bmpDepth;
uint32_t bmpImageoffset;
uint32_t rowSize;
boolean goodBmp = false;
boolean flip = true;
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
// Serial.print(F("pas d'image"));
return;
}
// Analyser l'en-tête BMP
if(read16(bmpFile) == 0x4D42) { // BMP signature
//Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Lire et ignorer les octets du créateur
bmpImageoffset = read32(bmpFile); // Début des données d'image
//Lire l'en-tête DIB
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
largeur_image =read32(bmpFile);
hauteur_image= read32(bmpFile);
//Serial.print(largeur_image);
// Serial.print('x');
// Serial.print(hauteur_image);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
// Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
} // end goodBmp
}
}
bmpFile.close();
//if(!goodBmp) Serial.println(F("BMP format non reconnu."));
}
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;
}





