Afficher une image sur l’écran TFT ST7735 avec Arduino
L’écran TFT ST7735 avec ses dégradés de couleur et sa résolution de 128×160 se prête bien à l’affichage d’image.
Dans ce paragraphe, nous allons voir qu’il est possible de partir d’un fichier image de dimension 160×128 au format .bmp, .png ou autre, disponible sur son PC, de le convertir en code C (Arduino) et de l’afficher sur un TFT ST7735 couleur. L’encodage des couleurs utilisé ici sera de 16 bits par pixel, ce qui signifie qu’une image englobant la totalité de l’écran (160×128) nécessite 40 Ko (40960 octets) de mémoire.
Pour le cas particulier de la carte Arduino Uno, celle-ci ne possède que 32ko de mémoire flash auxquels il faut retirer 5ko occupé par le bootloader (programme d’amorçage). Une image réduite sera donc utilisée pour l’Arduino Uno.
Code logiciel de départ
Dans ce paragraphe, nous partons du code logiciel suivant:
/* Déclaration des bibliothèques utilisées */ #include <lcdgfx.h> #if defined(__AVR_ATmega128__) // Ports d'E/S pour la carte Michelino ////////////////////////////////////// /* Ecran */ #define PORT_ECRAN_RESET 40 #define PORT_ECRAN_CS 38 #define PORT_ECRAN_DC 39 #define PORT_ECRAN_MOSI_SDA 10 #define PORT_ECRAN_SCK_SCL 9 #define PORT_ECRAN_ECLAIRAGE 37 /* Encodeur */ #define PORT_BOUTON_SELECTION 43 #define PORT_ENCODEUR_ROTATIF_1 41 #define PORT_ENCODEUR_ROTATIF_2 42 #elif defined(ARDUINO_AVR_UNO) // Ports d'E/S pour la carte Mega Uno ////////////////////////////////////// /* Ecran */ #define PORT_ECRAN_RESET 10 #define PORT_ECRAN_CS 8 #define PORT_ECRAN_DC 9 #define PORT_ECRAN_MOSI_SDA 11 #define PORT_ECRAN_SCK_SCL 13 #define PORT_ECRAN_ECLAIRAGE 7 /* Encodeur */ #define PORT_BOUTON_SELECTION 4 #define PORT_ENCODEUR_ROTATIF_1 5 #define PORT_ENCODEUR_ROTATIF_2 6 #elif defined(ARDUINO_AVR_MEGA2560) // Ports d'E/S pour la carte Mega 2560 ////////////////////////////////////// /* Ecran */ #define PORT_ECRAN_RESET 10 #define PORT_ECRAN_CS 8 #define PORT_ECRAN_DC 9 #define PORT_ECRAN_MOSI_SDA 51 #define PORT_ECRAN_SCK_SCL 52 #define PORT_ECRAN_ECLAIRAGE 7 /* Encodeur */ #define PORT_BOUTON_SELECTION 4 #define PORT_ENCODEUR_ROTATIF_1 5 #define PORT_ENCODEUR_ROTATIF_2 6 #endif // Déclaration globales DisplayST7735_128x160x16_SPI afficheur_g = DisplayST7735_128x160x16_SPI(PORT_ECRAN_RESET,{-1, PORT_ECRAN_CS, PORT_ECRAN_DC, 0, PORT_ECRAN_MOSI_SDA, PORT_ECRAN_SCK_SCL}); // Fonction de démarrage, s'exécute une seule fois: void setup() { afficheur_g.begin(); // Initialisation de l'écran afficheur_g.getInterface().setRotation(1); // Rotation de l'écran de 90° afficheur_g.getInterface().setOffset(2,1); // Correction du décalage de l'origine des coordonnées afficheur_g.clear(); // Effacement de l'écran } // Fonction principale du programme, s'exécute en boucle: void loop() { }
Choix de l’image
Concernant, l’image le choix de l’image est libre du moment qu’elle respecte les mêmes dimensions et le format cité précédemment. Pour ma part, j’utilise l’image libre de droit suivante :
au format 160×128 pour l’Arduino Mega et la carte Michelino |
au format 110×110 pour l’Arduino Uno qui possède une mémoire flash réduite |
Téléchargement et exécution de l’utilitaire de conversion
Pour convertir cette image en code logiciel compréhensible par le compilateur Arduino, je vous invite à télécharger l’outil LCD Image Converter également disponible ici.
Une fois dézippé, vous avez juste à cliquer sur l’exécutable “lcd-image-converter.exe” pour lancer l’application. Sélectionnez ensuite « Open… » dans le menu « File » et choisissez l’image que vous souhaitez convertir.
Paramètres de conversion
Avant de convertir l’image, il est nécessaire de définir les paramètres pour la conversion. Pour cela, aller dans le menu « Options… » et choisir « Conversion… ».
Vous atterrissez alors sur l’onglet “Prepare” des options de conversion. Il est à vérifier que la valeur par défaut du menu déroulant situé au dessus est bien “Color R5G6B5”. Pour le reste, les paramètres par défaut de l’onglet “Prepare” sont satisfaisants.
Les paramètres par défaut de l’onglet “Matrix” n’ont pas besoin d’être modifiés.
Les paramètres par défaut de l’onglet “Reordering” sont également satisfaisants.
Sous l’onglet “Image” la valeur par défaut pour le “Block size” est à remplacer par la “8 bit” car nous utiliserons des tableaux d’octets.
Les valeurs des 2 autres onglets “Font” et “Template” n’ont pas d’importance pour notre projet. La fenêtre des paramètres peut être fermée.
Conversion de l’image
Pour réaliser la conversion de l’image en code C, allez dans le menu « File » et choisir « Convert… ». Une fenêtre demandera ensuite de choisir un nom de fichier C. Je choisis “Sorciere.c” pour ma part.
Création d’un 2ème fichier de code logicel dans le répertoire projet de l’Arduino IDE
Pour une meilleure lisibilité de notre programme, nous créons un fichier dédié “Image.h” à l’aide de notre éditeur de texte favori (Notepad++ pour ma part mais le Bloc-notes de Windows suffit pour ce que nous avons à écrire).
Le contenu initial de ce fichier “Image.h” est le suivant:
/* Image.h - Definitions des images utilisées pour l'affichage graphique. */ #ifndef Image_h #define Image_h #endif
Quelques explication sur le code précédent:
Définir un “Image_h” à l’aide de la directive “#define” uniquement s’il n’a pas déjà été défini permet d’empêcher de créer une boucle d’inclusion du fichier header lors de la compilation du programme. Pour plus de détails je vous invite à vous reporter à l’article Wikipédia Include guard.
L’ajout de ce fichier d’en-tête à votre projet Arduino s’effectue de la façon suivante:
1) Enregistrez le fichier “Image.h” au même endroit que votre fichier croquis (fichier .ino).
2) Fermez l’IDE Arduino
3) Ré-ouvrez votre projet dans l’éditeur Arduino, un deuxième onglet apparait nommé “Image.h”.
4) Indiquez au compilateur qu’une partie de vos déclarations se situe dans un fichier séparé, en ajoutant l’instruction “#include” au début de votre fichier principal (.ino):
/* Déclaration des headers utilisées */ #include "image.h"
Voici à quoi doit ressembler votre projet sous l’IDE Arduino une fois le fichier “Image.h” inclus:
Insertion dans le programme Arduino du code généré
Du fait de la taille important de l’image, nous allons demander au compilateur de la stocker dans la mémoire flash du microcontrôleur plutôt que la mémoire SRAM plus réduite (emplacement par défaut). Pour cela, nous utilisons l’instruction “PROGMEM” et baptisons le tableau de stockage de cet image “Sorciere” dans le fichier “Image_h” :
const uint8_t Sorciere[] PROGMEM = { };
Une fois ce tableau déclaré, nous le remplissons par un copié/collé de l’énumération de valeurs hexadécimales du fichier “Sorciere.c” généré (la suite de valeurs “0x??” séparées par des virgules) représentant l’encodage de l’image.
const uint8_t Sorciere[] PROGMEM = { 0x30, 0xa1, 0x30, 0xa1, 0x30, 0xa1, 0x30, 0xa1, 0x30, 0xc1, 0x38, 0xc1, ... et ainsi de suite ... 0x41, 0x08, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20 };
Il ne reste plus qu’à demander à Arduino d’afficher cette image par un appel à la méthode drawBitmap16 de notre objet afficheur_g avec en paramètres:
- la position X de l’image (son bord gauche),
- la position y de l’image (son bord supérieur),
- la largeur de l’image en nombre de pixels,
- la hauteur de l’image en nombre de pixels.
- l’adresse du tableau d’octet des données de l’image
Ce qui donne pour les cartes Michelino et Mega 2560 :
afficheur_g.drawBitmap16(0, 0, 160, 128, Sorciere);
et pour la carte carte Uno :
afficheur_g.drawBitmap16(0, 0, 110, 110, Sorciere);
Erreur de compilation pour les cartes Mega 2560 et Michelino
Lorsque vous lancer la compilation Arduino pour les cartes Mega 2560 et Michelino, vous tombez sur l’erreur ci dessous. Cette erreur de compilation n’est pas présente pour la carte Uno :
Mais que se passe-t-il ?
Il se passe que nous venons de déclarer un tableau de 40 Ko (40960 octets) de mémoire pour les cartes Michelino / Mega 2560 et un tableau de taille inférieur à 24 Ko (24200 octets) pour la carte Arduino Uno. Or l’environnement de dévelopement Arduino utilise le compilateur AVR-GCC qui limite la taille des tableaux à 32 Ko !
La solution que je vous propose est de découper l’image en 2 parties égales:
const uint8_t Sorciere_01[] PROGMEM = { // Première partie de l'image (ligne 1 à 64) }; const uint8_t Sorciere_02[] PROGMEM = { // Deuxième partie de l'image (ligne 65 à 128) };
Et d’effectuer deux appels successifs à la méthode drawBitmap16 pour afficher la partie supérieur puis la partie inférieur de l’image:
afficheur_g.drawBitmap16(0, 0, 160, 64, Sorciere_01); afficheur_g.drawBitmap16(0, 64, 160, 64, Sorciere_02);
Code source pour afficher l’image et résultat
Du fait de la taille conséquent du fichier “Image_h”, vous trouverez le code source des projet sous forme de zip ci-dessous:
- Zip du projet Arduino pour afficher l’image sur une carte Uno: Lien pour Uno
- Zip du projet Arduino pour afficher l’image sur une carte Michelino ou Mega 2560: Lien pour Michelino ou Mega 2560
Une fois le code logiciel compilé puis transféré dans l’Arduino, voici ce que nous obtenons pour l’Arduino Mega:
pour la carte Michelino: |
pour l’Arduino Uno: |
Nous sommes à la fin du tutoriel. J’espère que cet article vous a plu et que vous êtes maintenant familiarisé avec l’utilisation sous Arduino d’un écran TFT couleur ST7735 et d’un encodeur rotatif.
Bonjour,
A la compilation j’ai cette erreur :
fatal error: image.h: No such file or directory
#include “image.h”
^~~~~~~~~
compilation terminated.
exit status 1
Que dois-je faire ?
Merci de votre réponse
Cordialement
Bonjour Pascal,
avez vous bien inclus le fichier “image.h” dans votre projet comme décrit ici https://tropratik.fr/ecran-tft-couleur-st7735-et-encodeur-rotatif-avec-arduino/2#Creation-2eme-fichier ?
Ah , non, j’ai sauter cette étape. Je vais le faire !
Désolé pour ma négligence.
Merci pour votre réponse et sa rapidité.
Bonne journée et encore bravo pour votre travail !