BUT Mesures Physiques · IUT Aix-Marseille · 2026-2027

Exemple : afficher une valeur sur la matrice LED

Le programme de base pour l'écran du ModuleAir : toutes les 2 secondes, une valeur de CO2 tirée au hasard, et un carré vert, orange ou rouge selon le niveau. Aucun capteur ni Wi-Fi : il suffit de la carte et de l'écran.

Code de l'exemple du guide IUT-AMU-08 « Afficher du texte et des couleurs sur la matrice LED », v1.1 du 2026-10-01. Les explications sont dans le PDF.

Mise en route

  1. Téléchargez le projet (bouton vert), décompressez-le. Dans VS Code, onglet PlatformIO, Open Project, choisissez le dossier décompressé.
    Ou créez un projet PlatformIO (carte Espressif ESP32 Dev Module, framework Arduino) et remplacez ses fichiers par ceux ci-dessous, avec le bouton Copier.
  2. Vérifiez que la carte est enfichée sur l'entrée (IN) du panneau et que le panneau est alimenté en 5 V.
  3. Téléversez (Upload), puis ouvrez le moniteur série (Monitor, 115200 bauds).

Couleurs fausses (rouge affiché en bleu…) ? Dans setupDisplay(), remplacez RRBBGG par RRGGBB : l'ordre des couleurs dépend du modèle de panneau (P2.5 ou P3). La carte redémarre quand l'écran est très lumineux ? Baissez setBrightness().

Le projet

Télécharger le projet IUT-AMU-08-exemple-v1.1.zip
platformio.ini
[env:moduleair]
platform = espressif32 @ 7.1.3
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
    2dom/PxMatrix LED MATRIX library @ 1.8.2
    adafruit/Adafruit GFX Library @ 1.11.11
src/main.cpp
// Exemple : toutes les 2 s, une valeur de CO2 et un carré coloré selon le niveau.
#include <Arduino.h>
#include <PxMatrix.h>

// Broches de la carte ModuleAir vers le connecteur HUB75 de l'écran
#define P_LAT 25
#define P_A   17
#define P_B   33
#define P_C   4
#define P_D   12
#define P_E   15
#define P_OE  16

PxMATRIX display(64, 32, P_LAT, P_OE, P_A, P_B, P_C, P_D, P_E);

// L'écran n'allume que 2 lignes sur 32 à la fois : il faut le redessiner sans
// arrêt, toutes les 4 ms. Un timer réveille une tâche qui s'en charge, en
// parallèle du reste du programme. Ce bloc se recopie tel quel.
hw_timer_t* timer = NULL;
SemaphoreHandle_t refreshSem;

void IRAM_ATTR onTimer() {
  BaseType_t woken = pdFALSE;
  xSemaphoreGiveFromISR(refreshSem, &woken);
  if (woken) portYIELD_FROM_ISR();
}

void refreshTask(void* param) {
  for (;;) {
    if (xSemaphoreTake(refreshSem, portMAX_DELAY)) {
      display.display(30);  // durée d'allumage de chaque ligne, en µs
    }
  }
}

void setupDisplay() {
  display.begin(16);                // balayage 1/16
  display.setDriverChip(SHIFT);
  display.setColorOrder(RRBBGG);    // couleurs inversées ? essayez RRGGBB
  display.setBrightness(255);       // luminosité : 0 à 255, ici le maximum
  display.clearDisplay();

  refreshSem = xSemaphoreCreateBinary();
  xTaskCreatePinnedToCore(refreshTask, "refresh", 2048, NULL,
                          configMAX_PRIORITIES - 1, NULL, 0);  // priorité max, cœur 0
  timer = timerBegin(0, 80, true);      // 80 MHz / 80 : un tic par µs
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 4000, true);   // toutes les 4000 µs, en boucle
  timerAlarmEnable(timer);
}

void setup() {
  setupDisplay();
}

void loop() {
  // Fausse mesure, tirée au hasard : à remplacer par la lecture du MH-Z19.
  int co2 = random(400, 2001);  // entre 400 et 2000 ppm

  // Couleur selon le niveau de CO2
  uint16_t color;
  if (co2 < 800) {
    color = display.color565(0, 255, 0);    // vert : air correct
  } else if (co2 < 1500) {
    color = display.color565(255, 120, 0);  // orange : aérer
  } else {
    color = display.color565(255, 0, 0);    // rouge : aérer vite
  }

  display.clearDisplay();                   // on efface, puis on redessine tout

  // Un petit texte en haut à gauche (x = 1, y = 0)
  display.setTextSize(1);                   // caractères de 6 x 8 pixels
  display.setTextColor(display.color565(0, 255, 255));
  display.setCursor(1, 0);
  display.print("CO2 (ppm)");

  // La valeur en grand, dans la couleur du niveau
  display.setTextSize(2);                   // caractères de 12 x 16 pixels
  display.setTextColor(color);
  display.setCursor(1, 12);
  display.print(co2);

  // Un carré de 10 x 10 pixels de la même couleur, à droite
  display.fillRect(52, 14, 10, 10, color);

  delay(2000);  // l'image reste affichée pendant l'attente, grâce au timer
}