Dans ce tuto, je branche l'écran ST7735 et son lecteur de carte SD à un module STM32F103C8T6 "Blue Pill" et, en le programmant avec l'IDE Arduino, j'affiche à l'écran du texte et des images qui avaient préalablement été enregistrés sur une carte SD.
Tout ceci pourrait être fait sans problème avec une carte Arduino Uno, mais ça m'a semblé intéressant d'utiliser la Blue Pill, puisqu'elle est plutôt rapide et son niveau logique de 3,3 V est parfaitement adapté à l'écran et au lecteur de cartes.
Connexions de l'écran au module Blue Pill
Le lecteur de cartes SD et l'écran communiquent tous les deux en SPI et, pour cette raison, ils partagent la même broche SCLK (A5) et la même broche MOSI (A7) (le lecteur de cartes est le seul des deux périphériques à utiliser la broche MISO).
Si votre écran ST7735 ne comporte pas de lecteur de carte SD intégré, vous pouvez obtenir les mêmes résultats avec un lecteur de carte SD distinct.
- Broche 1 GND de l'écran - Broche G de la Blue Pill
- Broche 2 VCC de l'écran - 5 V de la Blue Pill
- Broches 3, 4, et 5 NC de l'écran - pas branchées
- Broche 6 RESET de l'écran - Broche A3 de la Blue Pill
- Broche 7 AO de l'écran - Broche A2 de la Blue Pill
- Broche 8 SDA de l'écran - Broche A7 de la Blue Pill
- Broche 9 SCL de l'écran - Broche A5 de la Blue Pill
- Broche 10 CS de l'écran - Broche A8 de la Blue Pill
- Broche 11 SCK de l'écran (SD) - Broche A5 de la Blue Pill
- Broche 12 MISO de l'écran (SD) - Broche A6 de la Blue Pill
- Broche 13 MOSI de l'écran (SD) - Broche A7 de la Blue Pill
- Broche 14 SD_CS de l'écran (SD) - Broche A4 de la Blue Pill
- Broche 15 LED+ de l'écran - Broche 3.3 de la Blue Pill
- Broche 16 LED- de l'écran - Broche G de la Blue Pill
Préparation de l'IDE Arduino pour la programmation d'un STM32
Puisque nous allons programmer la Blue Pill avec l'IDE Arduino, c'est important que le logiciel ait été configuré pour la programmation des cartes STM32. Tout est expliqué dans cet article.
Installation des bibliothèques GFX et ST7735 d'Adafruit
La bibliothèque SD est déjà disponible, par défaut, dans l'IDE Arduino, mais nous avons également besoin de la bibliothèque GFX et de la bibliothèque ST7735, toutes deux mises au point par Adafruit. Elles peuvent toutes les deux s'installer par l'entremise du gestionnaire de bibliothèque.
Sketch #1: affichage de texte stocké sur la carte SD
Dans ce premier exemple, l'écran affiche successivement toutes les lignes d'un texte enregistré sous forme de fichier sur la carte SD.
Le fichier s'intitule "mots.txt" et doit avoir préalablement été enregistré sur la carte SD. Pour cette démonstration, j'ai écrit dans ce fichier quelques proverbes. La raison pour laquelle vous pouvez voir plusieurs espaces entre certains mots, c'est que l'écran affichera 13 caractères par ligne. Si le 13e caractère se trouve au milieu d'un mot, le mot sera séparé en deux parties lors de l'affichage à l'écran, ce qui ne fait pas très joli.
Lors de l'exécution du programme, l'écran affiche successivement chaque ligne du fichier txt pendant 5 secondes. Notre Blue Pill s'est transformée en philosophe un peu casse-pieds!
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Le contenu d'un fichier .txt enregistré sur | |
une carte SD est affiché sur un écran ST7735 | |
branché à un module STM32 Blue Pill. | |
Pour plus d'informations; | |
https://electroniqueamateur.blogspot.com/2020/04/aficher-sur-un-ecran-st7735-les.html | |
*/ | |
// bibliothèques utiles | |
#include <Adafruit_GFX.h> // routines de dessin | |
#include <Adafruit_ST7735.h> // spécifique à l'écran | |
#include <SPI.h> // communication SPI avec l'écran et la carte SD | |
#include <SD.h> // pour la lecture avec la carte SD | |
// définition des broches utilisées | |
#define ECRAN_CS PA8 | |
#define ECRAN_RST PA3 | |
#define ECRAN_DC PA2 | |
#define SD_CS PA4 | |
Adafruit_ST7735 ecran = Adafruit_ST7735(ECRAN_CS, ECRAN_DC, ECRAN_RST); | |
File monFichier; | |
char ligne[128]; | |
char lettre; | |
void lectureFichier(void) { | |
if (monFichier) { | |
int rang = 0; // position de la lettre à l'intérieur de la ligne de texte | |
if (monFichier.peek() == -1) { // on a atteint la fin du fichier | |
monFichier.seek(0); // retour au début du fichier | |
} | |
while (monFichier.available()) { | |
lettre = monFichier.read(); // lecture d'un caractère dans le fichier | |
if (rang <= 120) { | |
ligne[rang] = lettre; // on place ce caractère dans la chaîne de caractères à afficher | |
} | |
rang++; | |
if (lettre == '\n') { // on a atteint la fin de la ligne | |
ligne[rang] = '\0'; // terminaison de la chaîne de caractères | |
ecran.fillScreen(ST7735_WHITE); // pour effacer le message précédent | |
ecran.setCursor(0, 10); | |
ecran.println(ligne); // écriture à l'écran de la chaîne de caractères | |
Serial.print(ligne); // pour débogage seulement | |
break; // sortons du while(monFichier.available()) | |
} | |
} | |
monFichier.flush(); | |
} else { | |
Serial.println("Impossible d'ouvrir le fichier!"); | |
} | |
} | |
void setup() { | |
Serial.begin(9600); // pour débogage | |
ecran.initR(INITR_BLACKTAB); // initialisation de l'écran (GREENTAB et REDTAB également possibles) | |
ecran.setRotation(1); // réglage en mode paysage (0, 1, 2 ou 3) | |
Serial.print("Initialisation de la carte SD..."); | |
if (!SD.begin(SD_CS)) { | |
Serial.println("Echec!"); | |
return; | |
} | |
Serial.println("Reussie!"); | |
monFichier = SD.open("mots.txt"); // ouverture du fichier | |
ecran.setTextColor(ST7735_BLUE); // texte bleu | |
ecran.setTextSize(2); | |
} | |
void loop() { | |
lectureFichier(); | |
delay(5000); // 5 secondes avant d'afficher la ligne suivante | |
} |
-
Sketch #2: Affichage à l'écran d'images .bmp stockées sur la carte SD
Dans ce deuxième exemple, des images se trouvant sur la carte SD sous la forme de fichiers .bmp sont affichées à l'écran, l'une après l'autre. Dans ce cas, j'ai utilisé, avec assez peu de modifications, un sketch mis au point par Adafruit.
Les images doivent être enregistrées sur la carte SD sous la forme de fichiers bitmap (.bmp) ayant la même résolution que l'écran (donc 160 pixels de large par 128 pixels de haut, dans mon cas).
L'image ne sera pas redimensionnée: si elle est plus grande que l'écran, seule une portion de l'image sera affichée, en taille réelle!
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Affichage d'images en format .bmp sur un | |
écran ST7735. Testé sur STM32 Bluepill. | |
Très très très basé sur spitftbitmap.ino par Adafruit: | |
https://github.com/PaulStoffregen/Adafruit_ST7735/blob/master/examples/spitftbitmap/spitftbitmap.ino | |
Plus de détails: | |
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_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ées | |
#define ECRAN_CS PA8 | |
#define ECRAN_RST PA3 | |
#define ECRAN_DC PA2 | |
#define SD_CS PA4 | |
Adafruit_ST7735 tft = Adafruit_ST7735(ECRAN_CS, ECRAN_DC, ECRAN_RST); | |
void setup(void) { | |
Serial.begin(9600); // utile pour débogage | |
tft.initR(INITR_BLACKTAB); // intialisation de l'écran | |
tft.setRotation(1); // mode paysage | |
Serial.print("Initialisation de la carte SD..."); | |
if (!SD.begin(SD_CS)) { | |
Serial.println("Echec!"); | |
return; | |
} | |
Serial.println("Reussie!"); | |
} | |
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; | |
} | |
bmpDraw(entry.name(), 0, 0); | |
entry.close(); | |
} | |
} | |
#define BUFFPIXEL 20 // nombre de pixels traités à la fois. | |
// la fonction d'Adafruit qui affiche un fichier .bmp: | |
void bmpDraw(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 2 secondes | |
} // fin goodBmp | |
} | |
} | |
bmpFile.close(); | |
if (!goodBmp) Serial.println(F("Format de BMP 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; | |
} |
-
À lire aussi
- Un autre article sur l'utilisation d'un écran ST7735 avec les cartes STM32.
- Un autre article sur l'utilisation d'un lecteur de cartes SD avec une Blue Pill
- Tous les articles implicant les cartes STM32
Yves Pelletier (Twitter, Facebook)