Les Carnets de Byfeel domotique , Objets connectés , DIY , Programmation, Nouvelles Technologies ….

Affichage XL pour Matrice LED 72xx

Dans cet article , je vais expliquer comment mettre en place un affichage sur une Double hauteur de matrice LED. Chaque Matrice étant un carré composé de 8×8 Led , doubler la zone d’affichage donnera une grande matrice , composé de 4 matrices , soit un affichage de 16×16 .

Chaque caractère aura donc une hauteur max pouvant aller jusqu’a 16 LED.

Pour cela , il va falloir :

Disposition des matrices

Singe vs Double taille

Pour obtenir un double affichage en hauteur , il va falloir multiplier par 4 le nombre de matrice. Deux pour la hauteur et deux pour la largeur. Ce qui nous permet de passe d’un affichage de 8×8 à un affichage de 16×16.
Pour l’affichage d’une police de caractère en double taille , j’utilise le système des Zones , fournis avec la bibliothèque MD_Parola . Chaque Zone représentera une moitié d’affichage , la Zone Inférieur la moitié inférieur du caractère et la Zone Supérieur la moitié supérieur du caractère.
Selon les types de matrices utilisés , il faudra connecter la zone supérieur de deux façons différentes :

Matrice type FC16 ou ICStation : ( Mode ZigZag )

Connexion Zone Inferieur avec Zone Supérieur
pour type ICS ou FC16

Dans ce mode , chaque début de Zone , commence à droite .

ou pour les Matrices de type Parola ou Génerique . ( Mode S )

Parola ou generic

Dans ce mode , les debuts de Zones sont alternés , une fois a droite , une fois a gauche , etc ….

Branchement

Un affichage sur double hauteur implique , d’utiliser beaucoup plus de matrices. Afin d’avoir un affichage « correct » , il faut utiliser 4 Modules de 4 matrices au minimum ( soit une surface totale de 16×64 ).

Pin à relier ( schema avec Wemos D1R1 )
pour Wemos mini D8 à la place de D10

Attention aux PIN , en fonction de votre module ESP. Vérifier , selon votre module ou se situe les PIN ( SS , MOSI et SCK).
Le branchement sera toujours le suivant :
ESP ——–> Matrice LED
SCK ——–> Clock
MOSI ——–> DIN
SS ——–> CS

Définir une police en double taille

Pour cela , il faut utiliser des tableaux de définitions pour chaque caractère . Par exemple , pour l’affichage des caractéres sur le Notifheure , j’utilise le tableau fournis dans le fichier Parola_font_data.h .
Ce qui donne , par exemple pour les chiffres :

  5, 62, 81, 73, 69, 62,		// 48 - '0'
  3, 66, 127, 64,		        // 49 - '1'
  5, 114, 73, 73, 73, 70,		// 50 - '2'
  5, 33, 65, 73, 77, 51,		// 51 - '3'
  5, 24, 20, 18, 127, 16,		// 52 - '4'
  5, 39, 69, 69, 69, 57,		// 53 - '5'
  5, 60, 74, 73, 73, 49,		// 54 - '6'
  5, 65, 33, 17, 9, 7,		        // 55 - '7'
  5, 54, 73, 73, 73, 54,		// 56 - '8'
  5, 70, 73, 73, 41, 30,		// 57 - '9'

Ce tableau se lit de la manière suivante :
Pour le code Ascii 48 ( qui représente le chiffre 0 ) , je vais l’afficher sur 5 colones . Les 5 autres chiffres ( 62,81,73,69,62 ) sont les « poids » binaire qui permet de cibler les leds à allumer sur la colonne 1, 2 , 3 , 4 et 5 .
La led la plus haute à le poids 1 , puis 2 , 4 , 8 , 16 , 32 , 64 et 128. Avec la valeur 62 , sur la première colonne , j’aurais donc les led 2,3,4,5 et 6 allumés.
Pour créer ses propres polices de caractères , il existe des simulateur comme celui ci. ( il peut être téléchargé en local sur le github )

Exemple : tableau des codes ascii étendus

Pour afficher un caractère en double taille , il faut donc deux définitions de police de caractére , une qui sera affiché sur la zone inférieur et l’autre moitié qui sera affiché sur la zone supérieur.
Pour cela , il est possible d’utiliser deux tableau de définition ou un tableau.
Utiliser deux tableau permettra de définir , un plus grand nombre de caractère , mais prendra plus de place en mémoire.
Un tableau , permettra de réduire l’encombrement mémoire , mais devra être divisé par deux . De 0 à 127 la moitié inférieur et de 128 à 255 la moitié supérieur . Il contiendra , moins de caractères.

Dans cet article , je vais me baser sur la police bigfont , fournis avec la bibliothèque Parola . Ce tableau contient les deux définitions ( inférieur et supérieur ) .

Dans les illustrations ci dessous , les définitions des caractères répartis sur les 255 codes Ascii , de 0 à 127 la moitié basse et de 128 à 255 la moitié haute . Ainsi que le visuel de ce que l’on obtient une fois les deux définitions réunis.

Par exemple , pour le caractère « A » , il est définis par le code Ascii 65 et 193 ( 65 + 128 ).

Maintenant , que l’on a toutes les clés pour modifier ou jouer avec les polices de caractères à afficher , comment les afficher et synchroniser le tout.

Programmation

la théorie …

Pour que le caractère supérieur et inférieur soit afficher automatiquement sur les deux zones , il va falloir envoyer le bon code au bon nomment sur chaque Zone. Chaque caractère est donc égale au code ASCII de la lettre ( A=65 ) et de la moitié supérieur ( décalé de 128 ).

Pour cela j’utilise la fonction suivante :

// chaine decalage
void createHString(char *pH, char *pL)
{
  for (; *pL != '\0'; pL++)  *pH++ = *pL | 0x80;   // decalage caractére en positionnant le 8eme bit ( 128) à 1
    *pH = '\0'; // termine la chaine
}

Cette fonction , fabrique pour chaque caractère de la chaine inférieur un caractère décalé de 128 ( ou en hexa 0x80 ) pour la chaine supérieur . Par exemple pL contiendra le code ascii 65 ( A inferieur ) et pH contiendra le code ascii 193 ( A supérieur ) . Il suffit, ensuite d’envoyer sur chaque Zone les deux chaines de caractères et synchroniser le tout par la commande : P.synchZoneStart();

Pour gérer , les différents types de matrices ( Parola , generic , ICS , FC16 … ) , le test If invertUpperZone va tester le type définis et en fonction de ce dernier inversera le sens de l’écriture sur la zone supérieur ( pour les montages de type S ).

  // Selon type module inversion ou non de la zone supérieur 
  if (invertUpperZone)
  {
    P.setZoneEffect(ZONE_UPPER, true, PA_FLIP_UD);
    P.setZoneEffect(ZONE_UPPER, true, PA_FLIP_LR);
  }

…La pratique : Afficher un simple Texte

Pour commencer , on va afficher un texte , en utilisant la police livré avec la bibliothèque MD_Parola ( bigfont ) , et un effet de scrollig vertical, pour un peu d’animation.

// Tuto affichage double taille
// Byfeel 2019
// ****************************
// Exemple affichage texte sur 4 module de 4 Matrices Led 72xx
//
// Selon Module , il faudra brancher les matrices de deux façon differentes
// * Modules ( type FC16 ou ICSstation ) - Type ZigZag
//  n n-1 n-2 ... n/2+1   <- Matrice haute
//  n/2 ... 3  2  1  0    <- Matrice basse
//
// * Modules (Parola ou Generic )  - type S
//  n/2+1 ... n-2 n-1 n   -> Matrice haute
//  n/2 ... 3  2  1  0    <- Matrice basse

// Bibliotheque à inclure
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include "Font_Data.h"

//****************************************************
// En fonction de vos matrices , si probléme         *
// d'affichage ( inversé , effet miroir , etc .....) *
// ***************************************************
// matrix   - decocher selon config matrix    ********
//#define HARDWARE_TYPE MD_MAX72XX::FC16_HW        //***
//#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW    //***
#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW //***
//#define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW   //***
// ***************************************************
// Taille des deux zones
#define MAX_ZONES 2
#define ZONE_SIZE 8
#define MAX_DEVICES (MAX_ZONES * ZONE_SIZE)
// Définition de la zone inferieur et de la zone superieur
#define ZONE_UPPER  1
#define ZONE_LOWER  0
// gestion des effets
#define PAUSE_TIME 5000
#define SCROLL_SPEED 60
// Branchement des matrices
#define CLK_PIN   14  // SCK (D5 wemos D1 ou mini )
#define DATA_PIN  13  // MOSI ( D7 wemos D1 ou mini )
#define CS_PIN    15  // SS ( GPIO 15 sur D1  ou D8 sur Mini )

//variable pour inversion zone superieur selon module
bool invertUpperZone = false;  // Type ICS ou FC16

// HARDWARE SPI
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// définition des chaines de stockage pour les zones inf et sup
char *msgH; 
char msgL[15]; // un buffer de 15 caractères au max

// Message a afficher
String Msg="Byfeel";

// chaine decalage
void createHString(char *pH, char *pL)
{
  for (; *pL != '\0'; pL++)  *pH++ = *pL | 0x80;   // decalage caractére en positionnant le 8 bit ( 128) à 1
    *pH = '\0'; // termine la chaine
}

void setup() {
// transfére de la chaine String dans la chaine inférieur  
  Msg.toCharArray( msgL,15);
  uint8_t max = 0;
  // Selon modele des matrices - inversion de l'affichage ( true si Generic ou Parola )
  invertUpperZone = (HARDWARE_TYPE == MD_MAX72XX::GENERIC_HW || HARDWARE_TYPE == MD_MAX72XX::PAROLA_HW);
 
//calcul taille champs à afficher et allocation mémoire
    if (strlen(msgL) > max) max = strlen(msgL);
     msgH = (char *)malloc(sizeof(char)*(max + 2));

  // initialisation des Zones
  P.begin(MAX_ZONES);

  // Création des deux Zones pour les deux moitiés d'affichage
  P.setZone(ZONE_LOWER, 0, ZONE_SIZE - 1);
  P.setZone(ZONE_UPPER, ZONE_SIZE, MAX_DEVICES-1);
  // police de caractére à afficher
  P.setFont(BigFont);
  
  // Selon type module inversion ou non de la zone supérieur 
  if (invertUpperZone)
  {
    P.setZoneEffect(ZONE_UPPER, true, PA_FLIP_UD);
    P.setZoneEffect(ZONE_UPPER, true, PA_FLIP_LR);
  }
}

void loop() {
  P.displayAnimate();
// l'animation commence
  if (P.getZoneStatus(ZONE_LOWER) && P.getZoneStatus(ZONE_UPPER))
  {
     createHString(msgH, msgL);  // fabrique la chaine Supérieur
     P.displayClear();
     
    P.displayZoneText(ZONE_LOWER, msgL, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_SCROLL_UP, PA_SCROLL_UP);
    P.displayZoneText(ZONE_UPPER, msgH, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_SCROLL_DOWN, PA_SCROLL_DOWN);

  P.synchZoneStart();
  }

}

Et le fichier de définition des polices de caractères

// Data file for user example user defined fonts
#ifndef FONTDATA_H
#define FONTDATA_H

MD_MAX72XX::fontType_t BigFont[] PROGMEM = {
    0,		// 0
    0,		// 1
    0,		// 2
    0,		// 3
    0,		// 4
    0,		// 5
    0,		// 6
    0,		// 7
    0,		// 8
    0,		// 9
    0,		// 10
    0,		// 11
    0,		// 12
    0,		// 13
    0,		// 14
    0,		// 15
    0,		// 16
    0,		// 17
    0,		// 18
    0,		// 19
    0,		// 20
    0,		// 21
    0,		// 22
    0,		// 23
    0,		// 24
    0,		// 25
    0,		// 26
    0,		// 27
    0,		// 28
    0,		// 29
    0,		// 30
    0,		// 31
    4, 0, 0, 0, 0,		// 32 - 'Space lower'
    2, 51, 51,		// 33 - '! lower'
    6, 0, 0, 0, 0, 0, 0,		// 34 - '" lower'
    10, 3, 3, 63, 63, 3, 3, 63, 63, 3, 3,		// 35 - '# lower'
    10, 24, 56, 48, 48, 127, 127, 48, 57, 31, 15,		// 36 - '$ lower'
    8, 48, 60, 15, 3, 24, 36, 36, 24,		// 37 - '% lower'
    10, 15, 31, 57, 48, 48, 59, 31, 14, 63, 51,		// 38 - '& lower'
    2, 0, 0,		// 39 - ' lower'
    5, 3, 15, 28, 56, 48,		// 40 - '( lower'
    5, 48, 56, 28, 15, 3,		// 41 - ') lower'
    10, 6, 7, 7, 1, 31, 31, 1, 3, 7, 6,		// 42 - '* lower'
    10, 0, 0, 0, 0, 15, 15, 0, 0, 0, 0,		// 43 - '+ lower'
    2, 176, 112,		// 44 - ', lower'
    9, 0, 0, 0, 0, 0, 0, 0, 0, 0,		// 45 - '- lower'
    2, 48, 48,		// 46 - '. lower'
    8, 48, 60, 15, 3, 0, 0, 0, 0,		// 47 - '/ lower'
    10, 15, 31, 57, 48, 48, 48, 48, 56, 31, 15,		// 48 - '0 lower'
    5, 0, 48, 63, 63, 48,		// 49 - '1 lower'
    10, 63, 63, 49, 48, 48, 48, 48, 48, 48, 48,		// 50 - '2 lower'
    10, 12, 28, 56, 48, 48, 48, 48, 56, 31, 15,		// 51 - '3 lower'
    10, 3, 3, 3, 3, 3, 3, 3, 63, 63, 3,		// 52 - '4 lower'
    10, 12, 28, 56, 48, 48, 48, 48, 56, 31, 15,		// 53 - '5 lower'
    10, 15, 31, 56, 48, 48, 48, 48, 56, 31, 15,		// 54 - '6 lower'
    10, 0, 0, 0, 63, 63, 0, 0, 0, 0, 0,		// 55 - '7 lower'
    10, 15, 31, 57, 48, 48, 48, 48, 57, 31, 15,		// 56 - '8 lower'
    10, 0, 0, 0, 0, 0, 0, 0, 0, 63, 63,		// 57 - '9 lower'
    2, 24, 24,		// 58 - ': lower'
    2, 88, 56,		// 59 - '; lower'
    8, 0, 1, 3, 7, 14, 28, 56, 48,		// 60 - '< lower'
    9, 6, 6, 6, 6, 6, 6, 6, 6, 6,		// 61 - '= lower'
    8, 48, 56, 28, 14, 7, 3, 1, 0,		// 62 - '> lower'
    10, 0, 0, 0, 0, 55, 55, 1, 0, 0, 0,		// 63 - '? lower'
    10, 15, 31, 56, 51, 54, 54, 51, 54, 55, 19,		// 64 - '@ lower'
    10, 63, 63, 1, 1, 1, 1, 1, 1, 63, 63,		// 65 - 'A lower'
    10, 63, 63, 48, 48, 48, 48, 48, 57, 31, 15,		// 66 - 'B lower'
    10, 15, 31, 56, 48, 48, 48, 48, 56, 28, 12,		// 67 - 'C lower'
    10, 63, 63, 48, 48, 48, 48, 48, 56, 31, 15,		// 68 - 'D lower'
    9, 63, 63, 48, 48, 48, 48, 48, 48, 48,		// 69 - 'E lower'
    9, 63, 63, 0, 0, 0, 0, 0, 0, 0,		// 70 - 'F lower'
    10, 15, 31, 56, 48, 48, 48, 49, 57, 31, 15,		// 71 - 'G lower'
    10, 63, 63, 0, 0, 0, 0, 0, 0, 63, 63,		// 72 - 'H lower'
    4, 48, 63, 63, 48,		// 73 - 'I lower'
    8, 12, 28, 56, 48, 48, 56, 31, 15,		// 74 - 'J lower'
    9, 63, 63, 1, 3, 7, 14, 28, 56, 48,		// 75 - 'K lower'
    9, 63, 63, 48, 48, 48, 48, 48, 48, 48,		// 76 - 'L lower'
    10, 63, 63, 0, 0, 0, 0, 0, 0, 63, 63,		// 77 - 'M lower'
    10, 63, 63, 0, 0, 0, 0, 1, 3, 63, 63,		// 78 - 'N lower'
    10, 15, 31, 56, 48, 48, 48, 48, 56, 31, 15,		// 79 - 'O lower'
    10, 63, 63, 0, 0, 0, 0, 0, 0, 0, 0,		// 80 - 'P lower'
    10, 15, 31, 56, 48, 48, 54, 62, 28, 63, 55,		// 81 - 'Q lower'
    10, 63, 63, 0, 1, 3, 7, 14, 28, 56, 48,		// 82 - 'R lower'
    10, 24, 56, 48, 48, 48, 48, 48, 57, 31, 15,		// 83 - 'S lower'
    8, 0, 0, 0, 63, 63, 0, 0, 0,		// 84 - 'T lower'
    10, 15, 31, 56, 48, 48, 48, 48, 56, 31, 15,		// 85 - 'U lower'
    10, 3, 7, 14, 28, 56, 56, 28, 14, 7, 3,		// 86 - 'V lower'
    10, 15, 31, 56, 60, 31, 31, 60, 56, 31, 15,		// 87 - 'W lower'
    10, 60, 62, 7, 3, 1, 1, 3, 7, 62, 60,		// 88 - 'X lower'
    10, 0, 0, 0, 0, 63, 63, 0, 0, 0, 0,		// 89 - 'Y lower'
    10, 60, 62, 55, 51, 49, 48, 48, 48, 48, 48,		// 90 - 'Z lower'
    4, 63, 63, 48, 48,		// 91 - '[ lower'
    8, 0, 0, 0, 0, 3, 15, 60, 48,		// 92 - '\ lower'
    4, 48, 48, 63, 63,		// 93 - '] lower'
    8, 0, 0, 0, 0, 0, 0, 0, 0,		// 94 - '^ lower'
    10, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,		// 95 - '_ lower'
    3, 0, 0, 0,		// 96 - '` lower'
    10, 12, 30, 51, 51, 51, 51, 51, 51, 63, 31,		// 97 - 'a lower'
    10, 63, 63, 28, 56, 48, 48, 48, 56, 31, 15,		// 98 - 'b lower'
    9, 15, 31, 56, 48, 48, 48, 56, 28, 12,		// 99 - 'c lower'
    10, 15, 31, 56, 48, 48, 48, 56, 28, 63, 63,		// 100 - 'd lower'
    9, 15, 31, 59, 51, 51, 51, 59, 27, 9,		// 101 - 'e lower'
    7, 0, 63, 63, 0, 0, 0, 0,		// 102 - 'f lower'
    9, 49, 115, 231, 198, 198, 198, 230, 127, 63,		// 103 - 'g lower'
    9, 63, 63, 0, 0, 0, 0, 0, 63, 63,		// 104 - 'h lower'
    2, 63, 63,		// 105 - 'i lower'
    8, 48, 112, 224, 192, 192, 224, 127, 63,		// 106 - 'j lower'
    8, 63, 63, 3, 7, 15, 28, 56, 48,		// 107 - 'k lower'
    4, 48, 63, 63, 48,		// 108 - 'l lower'
    10, 63, 63, 0, 0, 63, 63, 0, 0, 63, 63,		// 109 - 'm lower'
    9, 63, 63, 0, 0, 0, 0, 0, 63, 63,		// 110 - 'n lower'
    9, 15, 31, 56, 48, 48, 48, 56, 31, 15,		// 111 - 'o lower'
    9, 255, 255, 7, 14, 12, 12, 14, 7, 3,		// 112 - 'p lower'
    9, 3, 7, 14, 12, 12, 14, 7, 255, 255,		// 113 - 'q lower'
    9, 63, 63, 0, 0, 0, 0, 0, 0, 0,		// 114 - 'r lower'
    9, 24, 57, 51, 51, 51, 51, 51, 30, 12,		// 115 - 's lower'
    6, 0, 31, 63, 48, 56, 24,		// 116 - 't lower'
    9, 15, 31, 56, 48, 48, 56, 28, 63, 63,		// 117 - 'u lower'
    9, 7, 15, 28, 56, 48, 56, 28, 15, 7,		// 118 - 'v lower'
    10, 15, 31, 56, 56, 31, 31, 56, 56, 31, 15,		// 119 - 'w lower'
    10, 48, 56, 28, 15, 7, 7, 15, 28, 56, 48,		// 120 - 'x lower'
    9, 49, 115, 230, 198, 198, 198, 230, 127, 63,		// 121 - 'y lower'
    10, 48, 56, 60, 62, 55, 51, 49, 48, 48, 48,		// 122 - 'z lower'
    6, 0, 1, 15, 31, 56, 48,		// 123 - '{ lower'
    2, 255, 255,		// 124 - '| lower'
    6, 48, 56, 31, 15, 1, 0,		// 125 - '} lower'
    0,		// 126
    0,		// 127
    0,		// 128
    0,		// 129
    0,		// 130
    0,		// 131
    0,		// 132
    0,		// 133
    0,		// 134
    0,		// 135
    0,		// 136
    0,		// 137
    0,		// 138
    0,		// 139
    0,		// 140
    0,		// 141
    0,		// 142
    0,		// 143
    0,		// 144
    0,		// 145
    0,		// 146
    0,		// 147
    0,		// 148
    0,		// 149
    0,		// 150
    0,		// 151
    0,		// 152
    0,		// 153
    0,		// 154
    0,		// 155
    0,		// 156
    0,		// 157
    0,		// 158
    0,		// 159
    4, 0, 0, 0, 0,		// 160 - 'Space upper'
    2, 255, 255,		// 161 - '! upper'
    6, 15, 15, 0, 0, 15, 15,		// 162 - '" upper'
    10, 48, 48, 255, 255, 48, 48, 255, 255, 48, 48,		// 163 - '# upper'
    10, 56, 124, 238, 198, 255, 255, 198, 198, 142, 12,		// 164 - '$ upper'
    8, 6, 9, 9, 198, 240, 60, 15, 3,		// 165 - '% upper'
    10, 0, 128, 204, 254, 243, 243, 158, 12, 0, 0,		// 166 - '& upper'
    2, 15, 15,		// 167 - '' upper'
    5, 240, 252, 14, 7, 3,		// 168 - '( upper'
    5, 3, 7, 14, 252, 240,		// 169 - ') upper'
    10, 48, 112, 224, 192, 252, 252, 192, 224, 112, 48,		// 170 - '* upper'
    10, 192, 192, 192, 192, 252, 252, 192, 192, 192, 192,		// 171 - '+ upper'
    2, 0, 0,		// 172 - ', upper'
    9, 192, 192, 192, 192, 192, 192, 192, 192, 192,		// 173 - '- upper'
    2, 0, 0,		// 174 - '. upper'
    8, 0, 0, 0, 192, 240, 60, 15, 3,		// 175 - '/ upper'
    10, 252, 254, 135, 195, 99, 51, 27, 15, 254, 252,		// 176 - '0 upper'
    5, 4, 6, 255, 255, 0,		// 177 - '1 upper'
    10, 12, 142, 199, 195, 195, 195, 195, 231, 126, 60,		// 178 - '2 upper'
    10, 12, 14, 7, 3, 3, 195, 195, 199, 254, 60,		// 179 - '3 upper'
    10, 128, 192, 224, 112, 56, 28, 14, 255, 255, 0,		// 180 - '4 upper'
    10, 63, 63, 51, 51, 51, 51, 51, 115, 227, 195,		// 181 - '5 upper'
    10, 252, 254, 231, 99, 99, 99, 99, 231, 198, 132,		// 182 - '6 upper'
    10, 3, 3, 3, 131, 195, 227, 115, 59, 31, 15,		// 183 - '7 upper'
    10, 28, 190, 247, 227, 195, 195, 227, 247, 190, 28,		// 184 - '8 upper'
    10, 60, 126, 231, 195, 195, 195, 195, 231, 255, 254,		// 185 - '9 upper'
    2, 48, 48,		// 186 - ': upper'
    2, 48, 48,		// 187 - '; upper'
    8, 192, 224, 240, 56, 28, 14, 7, 3,		// 188 - '< upper'
    9, 96, 96, 96, 96, 96, 96, 96, 96, 96,		// 189 - '= upper'
    8, 3, 7, 14, 28, 56, 240, 224, 192,		// 190 - '> upper'
    10, 12, 14, 7, 3, 3, 131, 195, 231, 126, 60,		// 191 - '? upper'
    10, 252, 254, 7, 243, 27, 27, 243, 7, 254, 252,		// 192 - '@ upper'
    10, 248, 254, 134, 131, 131, 131, 131, 134, 254, 248,		// 193 - 'A upper'
    10, 255, 255, 195, 195, 195, 195, 195, 231, 254, 60,		// 194 - 'B upper'
    10, 252, 254, 7, 3, 3, 3, 3, 7, 14, 12,		// 195 - 'C upper'
    10, 255, 255, 3, 3, 3, 3, 3, 7, 254, 252,		// 196 - 'D upper'
    9, 255, 255, 195, 195, 195, 195, 195, 3, 3,		// 197 - 'E upper'
    9, 255, 255, 195, 195, 195, 195, 195, 3, 3,		// 198 - 'F upper'
    10, 252, 254, 7, 3, 3, 3, 131, 135, 142, 140,		// 199 - 'G upper'
    10, 255, 255, 192, 192, 192, 192, 192, 192, 255, 255,		// 200 - 'H upper'
    4, 3, 255, 255, 3,		// 201 - 'I upper'
    8, 3, 3, 3, 3, 3, 3, 255, 255,		// 202 - 'J upper'
    9, 255, 255, 224, 240, 56, 28, 14, 7, 3,		// 203 - 'K upper'
    9, 255, 255, 0, 0, 0, 0, 0, 0, 0,		// 204 - 'L upper'
    10, 255, 255, 14, 28, 120, 120, 28, 14, 255, 255,		// 205 - 'M upper'
    10, 255, 255, 28, 56, 112, 224, 192, 128, 255, 255,		// 206 - 'N upper'
    10, 252, 254, 7, 3, 3, 3, 3, 7, 254, 252,		// 207 - 'O upper'
    10, 255, 255, 195, 195, 195, 195, 195, 231, 126, 60,		// 208 - 'P upper'
    10, 252, 254, 7, 3, 3, 3, 3, 7, 254, 252,		// 209 - 'Q upper'
    10, 255, 255, 195, 195, 195, 195, 195, 231, 126, 60,		// 210 - 'R upper'
    10, 60, 126, 231, 195, 195, 195, 195, 195, 135, 6,		// 211 - 'S upper'
    8, 3, 3, 3, 255, 255, 3, 3, 3,		// 212 - 'T upper'
    10, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255,		// 213 - 'U upper'
    10, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255,		// 214 - 'V upper'
    10, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255,		// 215 - 'W upper'
    10, 15, 31, 56, 240, 224, 224, 240, 56, 31, 15,		// 216 - 'X upper'
    10, 15, 31, 56, 112, 224, 224, 112, 56, 31, 15,		// 217 - 'Y upper'
    10, 3, 3, 3, 131, 195, 227, 115, 59, 31, 15,		// 218 - 'Z upper'
    4, 255, 255, 3, 3,		// 219 - '[ upper'
    8, 3, 15, 60, 240, 192, 0, 0, 0,		// 220 - '\ upper'
    4, 3, 3, 255, 255,		// 221 - '] upper'
    8, 24, 12, 6, 3, 3, 6, 12, 24,		// 222 - '^ upper'
    10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		// 223 - '_ upper'
    3, 3, 15, 12,		// 224 - '` upper'
    10, 0, 96, 112, 48, 48, 48, 48, 112, 224, 192,		// 225 - 'a upper'
    10, 255, 255, 224, 112, 48, 48, 48, 112, 224, 192,		// 226 - 'b upper'
    9, 192, 224, 112, 48, 48, 48, 112, 224, 192,		// 227 - 'c upper'
    10, 192, 224, 112, 48, 48, 48, 112, 224, 255, 255,		// 228 - 'd upper'
    9, 192, 224, 112, 48, 48, 48, 112, 224, 192,		// 229 - 'e upper'
    7, 192, 252, 254, 199, 199, 14, 12,		// 230 - 'f upper'
    9, 192, 224, 112, 48, 48, 48, 112, 224, 192,		// 231 - 'g upper'
    9, 255, 255, 224, 112, 48, 48, 112, 224, 192,		// 232 - 'h upper'
    2, 246, 246,		// 233 - 'i upper'
    8, 0, 0, 0, 0, 0, 0, 246, 246,		// 234 - 'j upper'
    8, 254, 254, 0, 128, 192, 224, 112, 48,		// 235 - 'k upper'
    4, 3, 255, 255, 0,		// 236 - 'l upper'
    10, 240, 240, 48, 48, 240, 240, 48, 48, 240, 224,		// 237 - 'm upper'
    9, 240, 240, 224, 112, 48, 48, 112, 224, 192,		// 238 - 'n upper'
    9, 192, 224, 112, 48, 48, 48, 112, 224, 192,		// 239 - 'o upper'
    9, 240, 240, 96, 112, 48, 48, 112, 224, 192,		// 240 - 'p upper'
    9, 192, 224, 112, 48, 48, 112, 96, 240, 240,		// 241 - 'q upper'
    9, 240, 240, 224, 112, 48, 48, 112, 224, 192,		// 242 - 'r upper'
    9, 192, 224, 48, 48, 48, 48, 112, 96, 0,		// 243 - 's upper'
    6, 96, 252, 252, 96, 96, 0,		// 244 - 't upper'
    9, 240, 240, 0, 0, 0, 0, 0, 240, 240,		// 245 - 'u upper'
    9, 240, 240, 0, 0, 0, 0, 0, 240, 240,		// 246 - 'v upper'
    10, 240, 240, 0, 0, 0, 0, 0, 0, 240, 240,		// 247 - 'w upper'
    10, 48, 112, 224, 192, 128, 128, 192, 224, 112, 48,		// 248 - 'x upper'
    9, 240, 240, 0, 0, 0, 0, 0, 240, 240,		// 249 - 'y upper'
    10, 48, 48, 48, 48, 48, 176, 240, 240, 112, 48,		// 250 - 'z upper'
    6, 192, 224, 252, 62, 7, 3,		// 251 - '{ upper'
    2, 255, 255,		// 252 - '| upper'
    6, 3, 7, 62, 252, 224, 192,		// 253 - '} upper'
    0,		// 254
    0,		// 255
  };

#endif

les deux fichier , doivent êtres présent dans le même dossier.

Exemple structure dossier
le résultat

… Afficher l’heure

Afin de récupérer l’heure et de l’afficher , il va falloir :

  • Se connecter au réseau WIFI
  • Récupérer l’heure via NTP
  • Formater l’heure pour affichage ( adapter une police type Clock )

Il suffit de rajouter les lignes suivantes :

Pour la partie Wifi et NTP , inclure les bibliothèques suivantes . ( la bibliotheque NTP peut etre récupéré à l’adresse suivante sur le github de fabrice weinberg).

#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

Puis configurer le WIFI et le service NTP

const char *ssid     = "SSID";
const char *password = "password";

WiFiUDP ntpUDP;

// serveur NTP , Decalage heure ici 7200 secondes pour les deux heures ETE ou 3600 pour hiver , et synchro toutes les 60 secondes ( temps en millisecondes )
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 7200, 60000);

Enfin dans la boucle Setup() , on active le Wifi et le service NTP

setup() {  
WiFi.begin(ssid, password);

  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
    //Serial.print ( "." );
  }

  timeClient.begin();
//......
// code ...
//.....
}

Pour le formatage de l’heure , j’utilise la fonction getDisplayClock , qui met en forme les heures et les minutes ,séparé par les deux points : qui clignote toutes les secondes .

Pour l’affichage , je supprime les effets précedents , et je demande un affichage sans effet et une pause à Zero ( define PAUSE_TIME 0 )

     if (millis() - lastTime >= 1000)
    {
      lastTime = millis();
      getDisplayClock(msgL, flasher);
      createHString(msgH, msgL);  // fabrique la chaine Supérieur
      flasher = !flasher; // inverse affichage des deux points
    }
// affichage sans effet
    P.displayZoneText(ZONE_LOWER, msgL, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);
    P.displayZoneText(ZONE_UPPER, msgH, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);

  P.synchZoneStart();

Pour avoir un affichage de l’heure qui ne bouge pas, il faut utiliser une police de caractére ou tous les chiffres ont la même largeur ( ce qui n’est pas le cas avec la police bigfont ). J’utilise ici , la police numeric7SegDouble qui est affecté aux zones par la commande P.setFont(numeric7SegDouble);

// Data file for user example user defined fonts
#ifndef FONTDATA_H
#define FONTDATA_H

MD_MAX72XX::fontType_t numeric7SegDouble[] PROGMEM = {
    0,		// 0
    0,		// 1
    0,		// 2
    0,		// 3
    0,		// 4
    0,		// 5
    0,		// 6
    0,		// 7
    0,		// 8
    0,		// 9
    0,		// 10
    0,		// 11
    0,		// 12
    0,		// 13
    0,		// 14
    0,		// 15
    0,		// 16
    0,		// 17
    0,		// 18
    0,		// 19
    0,		// 20
    0,		// 21
    0,		// 22
    0,		// 23
    0,		// 24
    0,		// 25
    0,		// 26
    0,		// 27
    0,		// 28
    0,		// 29
    0,		// 30
    0,		// 31
    2, 0, 0,		// 32 - 'Space'
    0,		// 33 - '!'
    0,		// 34 - '"'
    0,		// 35 - '#'
    0,		// 36 - '$'
    0,		// 37 - '%'
    0,		// 38 - '&'
    0,		// 39 - '''
    0,		// 40 - '('
    0,		// 41 - ')'
    0,		// 42 - '*'
    0,		// 43 - '+'
    0,		// 44 - ','
    0,		// 45 - '-'
    2, 48, 48,		// 46 - '.'
    0,		// 47 - '/'
    10, 62, 127, 192, 192, 192, 192, 192, 192, 127, 62,		// 48 - '0'
    10, 0, 0, 0, 0, 0, 0, 0, 0, 127, 62,		// 49 - '1'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 64, 0,		// 50 - '2'
    10, 0, 65, 193, 193, 193, 193, 193, 193, 127, 62,		// 51 - '3'
    10, 0, 0, 1, 1, 1, 1, 1, 1, 127, 62,		// 52 - '4'
    10, 0, 64, 193, 193, 193, 193, 193, 193, 127, 62,		// 53 - '5'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 127, 62,		// 54 - '6'
    10, 0, 0, 0, 0, 0, 0, 0, 0, 127, 62,		// 55 - '7'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 127, 62,		// 56 - '8'
    10, 0, 64, 193, 193, 193, 193, 193, 193, 127, 62,		// 57 - '9'
    2, 6, 6,		// 58 - ':'
    0,		// 59 - ';'
    0,		// 60 - '<'
    0,		// 61 - '='
    0,		// 62 - '>'
    0,		// 63 - '?'
    0,		// 64 - '@'
    10, 62, 127, 1, 1, 1, 1, 1, 1, 127, 62,		// 65 - 'A'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 127, 62,		// 66 - 'B'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 65, 0,		// 67 - 'C'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 127, 62,		// 68 - 'D'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 65, 0,		// 69 - 'E'
    10, 62, 127, 1, 1, 1, 1, 1, 1, 1, 0,		// 70 - 'F'
    0,		// 71 - 'G'
    0,		// 72 - 'H'
    0,		// 73 - 'I'
    0,		// 74 - 'J'
    0,		// 75 - 'K'
    0,		// 76 - 'L'
    0,		// 77 - 'M'
    0,		// 78 - 'N'
    0,		// 79 - 'O'
    0,		// 80 - 'P'
    0,		// 81 - 'Q'
    0,		// 82 - 'R'
    0,		// 83 - 'S'
    0,		// 84 - 'T'
    0,		// 85 - 'U'
    0,		// 86 - 'V'
    0,		// 87 - 'W'
    0,		// 88 - 'X'
    0,		// 89 - 'Y'
    0,		// 90 - 'Z'
    0,		// 91 - '['
    0,		// 92 - '\'
    0,		// 93 - ']'
    0,		// 94 - '^'
    0,		// 95 - '_'
    0,		// 96 - '`'
    10, 62, 127, 1, 1, 1, 1, 1, 1, 127, 62,		// 97 - 'a'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 127, 62,		// 98 - 'b'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 65, 0,		// 99 - 'c'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 127, 62,		// 100 - 'd'
    10, 62, 127, 193, 193, 193, 193, 193, 193, 65, 0,		// 101 - 'e'
    10, 62, 127, 1, 1, 1, 1, 1, 1, 1, 0,		// 102 - 'f'
    0,		// 103 - 'g'
    0,		// 104 - 'h'
    0,		// 105 - 'i'
    0,		// 106 - 'j'
    0,		// 107 - 'k'
    0,		// 108 - 'l'
    0,		// 109 - 'm'
    0,		// 110 - 'n'
    0,		// 111 - 'o'
    0,		// 112 - 'p'
    0,		// 113 - 'q'
    0,		// 114 - 'r'
    0,		// 115 - 's'
    0,		// 116 - 't'
    0,		// 117 - 'u'
    0,		// 118 - 'v'
    0,		// 119 - 'w'
    0,		// 120 - 'x'
    0,		// 121 - 'y'
    0,		// 122 - 'z'
    0,		// 123 - '{'
    2, 255, 255,		// 124 - '|'
    0,		// 125
    0,		// 126
    0,		// 127
    0,		// 128
    0,		// 129
    0,		// 130
    0,		// 131
    0,		// 132
    0,		// 133
    0,		// 134
    0,		// 135
    0,		// 136
    0,		// 137
    0,		// 138
    0,		// 139
    0,		// 140
    0,		// 141
    0,		// 142
    0,		// 143
    0,		// 144
    0,		// 145
    0,		// 146
    0,		// 147
    0,		// 148
    0,		// 149
    0,		// 150
    0,		// 151
    0,		// 152
    0,		// 153
    0,		// 154
    0,		// 155
    0,		// 156
    0,		// 157
    0,		// 158
    0,		// 159
    2, 0, 0,		// 160
    0,		// 161
    0,		// 162
    0,		// 163
    0,		// 164
    0,		// 165
    0,		// 166
    0,		// 167
    0,		// 168
    0,		// 169
    0,		// 170
    0,		// 171
    0,		// 172
    0,		// 173
    2, 0, 0,		// 174
    0,		// 175
    10, 124, 254, 3, 3, 3, 3, 3, 3, 254, 124,		// 176
    10, 0, 0, 0, 0, 0, 0, 0, 0, 254, 124,		// 177
    10, 0, 2, 131, 131, 131, 131, 131, 131, 254, 124,		// 178
    10, 0, 130, 131, 131, 131, 131, 131, 131, 254, 124,		// 179
    10, 124, 254, 128, 128, 128, 128, 128, 128, 254, 124,		// 180
    10, 124, 254, 131, 131, 131, 131, 131, 131, 2, 0,		// 181
    10, 124, 254, 131, 131, 131, 131, 131, 131, 2, 0,		// 182
    10, 0, 2, 3, 3, 3, 3, 3, 3, 254, 124,		// 183
    10, 124, 254, 131, 131, 131, 131, 131, 131, 254, 124,		// 184
    10, 124, 254, 131, 131, 131, 131, 131, 131, 254, 124,		// 185
    2, 96, 96,		// 186
    0,		// 187
    0,		// 188
    0,		// 189
    0,		// 190
    0,		// 191
    0,		// 192
    10, 124, 254, 131, 131, 131, 131, 131, 131, 254, 124,		// 193
    10, 124, 254, 128, 128, 128, 128, 128, 128, 0, 0,		// 194
    10, 0, 0, 128, 128, 128, 128, 128, 128, 0, 0,		// 195
    10, 0, 0, 128, 128, 128, 128, 128, 128, 254, 124,		// 196
    10, 124, 254, 131, 131, 131, 131, 131, 131, 130, 0,		// 197
    10, 124, 254, 131, 131, 131, 131, 131, 131, 130, 0,		// 198
    0,		// 199
    0,		// 200
    0,		// 201
    0,		// 202
    0,		// 203
    0,		// 204
    0,		// 205
    0,		// 206
    0,		// 207
    0,		// 208
    0,		// 209
    0,		// 210
    0,		// 211
    0,		// 212
    0,		// 213
    0,		// 214
    0,		// 215
    0,		// 216
    0,		// 217
    0,		// 218
    0,		// 219
    0,		// 220
    0,		// 221
    0,		// 222
    0,		// 223
    0,		// 224
    10, 124, 254, 131, 131, 131, 131, 131, 131, 254, 124,		// 225
    10, 124, 254, 128, 128, 128, 128, 128, 128, 0, 0,		// 226
    10, 0, 0, 128, 128, 128, 128, 128, 128, 0, 0,		// 227
    10, 0, 0, 128, 128, 128, 128, 128, 128, 254, 124,		// 228
    10, 124, 254, 131, 131, 131, 131, 131, 131, 130, 0,		// 229
    10, 124, 254, 131, 131, 131, 131, 131, 131, 130, 0,		// 230
    0,		// 231
    0,		// 232
    0,		// 233
    0,		// 234
    0,		// 235
    0,		// 236
    0,		// 237
    0,		// 238
    0,		// 239
    0,		// 240
    0,		// 241
    0,		// 242
    0,		// 243
    0,		// 244
    0,		// 245
    0,		// 246
    0,		// 247
    0,		// 248
    0,		// 249
    0,		// 250
    0,		// 251
    2, 255, 255,		// 252
    0,		// 253
    0,		// 254
    0,		// 255
  };

#endif
Aperçu police horloge

j’obtiens , alors l’affichage suivant.

Affichage Horloge format XL

Ci dessous le code complet

// Tuto affichage double taille Horloge
// Byfeel 2019
// ****************************
// Exemple affichage  horloge synchronisé via NTP
//  sur 4 module de 4 Matrices Led 72xx
//
// Selon Module , il faudra brancher les matrices de deux façon differentes
// * Modules ( type FC16 ou ICSstation ) - Type ZigZag
//  n n-1 n-2 ... n/2+1   <- Matrice haute
//  n/2 ... 3  2  1  0    <- Matrice basse
//
// * Modules (Parola ou Generic )  - type S
//  n/2+1 ... n-2 n-1 n   -> Matrice haute
//  n/2 ... 3  2  1  0    <- Matrice basse

// Bibliotheque à inclure
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include "Font_Clock.h"
#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
//****************************************************
// En fonction de vos matrices , si probléme         *
// d'affichage ( inversé , effet miroir , etc .....) *
// ***************************************************
// matrix   - decocher selon config matrix    ********
//#define HARDWARE_TYPE MD_MAX72XX::FC16_HW        //***
//#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW    //***
#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW //***
//#define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW   //***
// ***************************************************
// Taille des deux zones
#define MAX_ZONES 2
#define ZONE_SIZE 8
#define MAX_DEVICES (MAX_ZONES * ZONE_SIZE)
// Définition de la zone inferieur et de la zone superieur
#define ZONE_UPPER  1
#define ZONE_LOWER  0
// gestion des effets
#define PAUSE_TIME 0
#define SCROLL_SPEED 60
// Branchement des matrices
#define CLK_PIN   14  // SCK (D5 wemos D1 ou mini )
#define DATA_PIN  13  // MOSI ( D7 wemos D1 ou mini )
#define CS_PIN    15  // SS ( GPIO 15 sur D1  ou D8 sur Mini )

const char *ssid     = "Votre SSID";
const char *password = "Votre password";

WiFiUDP ntpUDP;

// By default 'pool.ntp.org' is used with 60 seconds update interval and
// no offset
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 7200, 60000);

//variable pour inversion zone superieur selon module
bool invertUpperZone = false;  // Type ICS ou FC16

// HARDWARE SPI
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// définition des chaines de stockage pour les zones inf et sup
char *msgH; 
char msgL[15]; // un buffer de 15 caractères au max

// Message a afficher
String Msg="00:00";

// chaine decalage
void createHString(char *pH, char *pL)
{
  for (; *pL != '\0'; pL++)  *pH++ = *pL | 0x80;   // decalage caractére en positionnant le 8 bit ( 128) à 1
    *pH = '\0'; // termine la chaine
}

void getDisplayClock(char *psz, bool f = true)
// Code pour affichage time
{
  sprintf(psz, "%02d%c%02d", timeClient.getHours(), (f ? ':' : ' '), timeClient.getMinutes());

}

void setup() {
    WiFi.begin(ssid, password);

  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
    //Serial.print ( "." );
  }

  timeClient.begin();
  
// transfére de la chaine String dans la chaine inférieur  
  Msg.toCharArray( msgL,15);
  uint8_t max = 0;
  // Selon modele des matrices - inversion de l'affichage ( true si Generic ou Parola )
  invertUpperZone = (HARDWARE_TYPE == MD_MAX72XX::GENERIC_HW || HARDWARE_TYPE == MD_MAX72XX::PAROLA_HW);
 
//calcul taille champs à afficher et allocation mémoire
    if (strlen(msgL) > max) max = strlen(msgL);
     msgH = (char *)malloc(sizeof(char)*(max + 2));

  // initialisation des Zones
  P.begin(MAX_ZONES);

  // Création des deux Zones pour les deux moitiés d'affichage
  P.setZone(ZONE_LOWER, 0, ZONE_SIZE - 1);
  P.setZone(ZONE_UPPER, ZONE_SIZE, MAX_DEVICES-1);
  // police de caractére à afficher
  P.setFont(numeric7SegDouble);
  
  // Selon type module inversion ou non de la zone supérieur 
  if (invertUpperZone)
  {
    P.setZoneEffect(ZONE_UPPER, true, PA_FLIP_UD);
    P.setZoneEffect(ZONE_UPPER, true, PA_FLIP_LR);
  }
}

void loop() {
  timeClient.update();
   static uint32_t  lastTime = 0; // millis() memory
  static bool flasher = false;  // seconds passing flasher
  
  P.displayAnimate();
// l'animation commence
  if (P.getZoneStatus(ZONE_LOWER) && P.getZoneStatus(ZONE_UPPER))
  {
     if (millis() - lastTime >= 1000)
    {
      lastTime = millis();
      getDisplayClock(msgL, flasher);
       createHString(msgH, msgL);  // fabrique la chaine Supérieur
      flasher = !flasher;
    }
    
     //P.displayClear();
     
    P.displayZoneText(ZONE_LOWER, msgL, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);
    P.displayZoneText(ZONE_UPPER, msgH, PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);

  P.synchZoneStart();
  }

}

A vous de jouer , pour vous créer une horloge ou un bandeau de notification de taille XL !
Et pourquoi pas un Notifheure de taille XL ?

25 commentaires sur “Affichage XL pour Matrice LED 72xx”

Les commentaires sont fermés.