Exemple : lire le NextPM toutes les 10 secondes
Le programme de base pour le capteur de particules : toutes les 10 secondes, il lit l'état du NextPM, puis les PM1, PM2.5 et PM10 (moyennes 10 s), la température et l'humidité, et affiche tout sur le moniteur série. Même code pour ModuleAir et NebuleAir.
Code de l'exemple du guide IUT-AMU-04 « Lire le capteur de particules NextPM », v1.0 du 2026-10-01. Les explications sont dans le PDF.
Mise en route
- 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. - Vérifiez les broches du NextPM sur votre carte (tableau du guide, partie 2) : sur les cartes 2026, RX = GPIO 39 et TX = GPIO 32.
- Téléversez (Upload), puis ouvrez le moniteur série (Monitor, 115200 bauds).
Le capteur ne répond pas (erreur Modbus 0xE2) ? Vérifiez la parité : SERIAL_8E1, pas SERIAL_8N1. Les deux premières minutes, les valeurs sont sous-estimées : le ventilateur monte en régime.
Le projet
Télécharger le projet IUT-AMU-04-exemple-v1.0.zip[env:esp32]
platform = espressif32 @ 7.1.3
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
4-20ma/ModbusMaster @ 2.0.1
// Exemple : lire le NextPM toutes les 10 s et afficher les mesures et son état.
#include <Arduino.h>
#include <ModbusMaster.h>
// Branchement du NextPM sur l'UART n°1 de l'ESP32 (cartes 2026 : ModuleAir et NebuleAir)
#define NEXTPM_RX 39 // l'ESP32 reçoit sur GPIO 39 (fil TX du capteur)
#define NEXTPM_TX 32 // l'ESP32 émet sur GPIO 32 (fil RX du capteur)
// Registres Modbus du NextPM
#define REG_STATUS 0x13 // état du capteur : codes d'erreur
#define REG_PM1 0x38 // moyennes 10 s (tests) ; en production, moyennes 60 s :
#define REG_PM25 0x3A // PM1 = 0x44, PM2.5 = 0x46, PM10 = 0x48
#define REG_PM10 0x3C
#define REG_HUM 0x6A // humidité interne, en centièmes de %
#define REG_TEMP 0x6B // température interne, en centièmes de °C
// Signification des 8 bits du registre d'état (bit 0 en premier)
const char* STATUS_BITS[8] = {
"veille", "mode degrade", "demarrage en cours", "humidite trop forte",
"erreur capteur T/HR", "erreur ventilateur", "erreur memoire", "erreur laser"
};
// Bits qui rendent la mesure inutilisable : démarrage, humidité, ventilateur, laser
#define STATUS_CRITICAL 0xAC
HardwareSerial nextpmSerial(1); // UART n°1 de l'ESP32
ModbusMaster nextpm;
// Une valeur PM occupe 2 registres de 16 bits (poids faible d'abord), en
// millièmes de µg/m³. Renvoie -1 si le capteur n'a pas répondu.
float readPM(uint16_t reg) {
if (nextpm.readHoldingRegisters(reg, 2) != nextpm.ku8MBSuccess) {
return -1;
}
uint32_t raw = ((uint32_t)nextpm.getResponseBuffer(1) << 16) | nextpm.getResponseBuffer(0);
return raw / 1000.0;
}
void setup() {
Serial.begin(115200);
nextpmSerial.begin(115200, SERIAL_8E1, NEXTPM_RX, NEXTPM_TX); // 8E1 : parité paire !
nextpm.begin(1, nextpmSerial); // adresse Modbus 1
}
void loop() {
// 1) Lire l'état en premier : il dit si le capteur répond, et si la mesure est fiable.
uint8_t result = nextpm.readHoldingRegisters(REG_STATUS, 1);
if (result != nextpm.ku8MBSuccess) {
Serial.print("Pas de reponse du NextPM (erreur Modbus 0x");
Serial.print(result, HEX);
Serial.println(") : branchement ? broches ? parite 8E1 ?");
delay(10000);
return;
}
uint8_t status = nextpm.getResponseBuffer(0) & 0xFF;
Serial.print("Etat : ");
Serial.print(status);
if (status == 0) {
Serial.println(" (tout va bien)");
} else {
for (int bit = 0; bit < 8; bit++) {
if (status & (1 << bit)) {
Serial.print(" [");
Serial.print(STATUS_BITS[bit]);
Serial.print("]");
}
}
Serial.println();
}
// 2) Mesure inutilisable : on ne lit pas les PM.
if (status & STATUS_CRITICAL) {
Serial.println("Mesure non fiable, ignoree");
delay(10000);
return;
}
// 3) Les particules (moyennes sur 10 s) et la température / humidité internes
float pm1 = readPM(REG_PM1);
float pm25 = readPM(REG_PM25);
float pm10 = readPM(REG_PM10);
Serial.print("PM1 = "); Serial.print(pm1);
Serial.print(" PM2.5 = "); Serial.print(pm25);
Serial.print(" PM10 = "); Serial.print(pm10);
Serial.println(" ug/m3");
if (nextpm.readHoldingRegisters(REG_TEMP, 1) == nextpm.ku8MBSuccess) {
float temp = (int16_t)nextpm.getResponseBuffer(0) / 100.0; // peut être négative
Serial.print("T = "); Serial.print(temp); Serial.print(" C ");
}
if (nextpm.readHoldingRegisters(REG_HUM, 1) == nextpm.ku8MBSuccess) {
float hum = nextpm.getResponseBuffer(0) / 100.0;
Serial.print("HR = "); Serial.print(hum); Serial.print(" %");
}
Serial.println();
delay(10000); // le NextPM met à jour ses valeurs toutes les 10 s
}