Mesure et Affichage OLED de la vitesse JGB37-520 équipé d’un codeur avec ESP32
Description :
Ce projet consiste à concevoir un tachymètre numérique de précision pour un motoréducteur de type JGB37-520. L’objectif est de mesurer en temps réel la vitesse de rotation (en RPM) et la position de l’axe de sortie, puis d’afficher ces données sur un écran OLED compact.
Le système est piloté par un ESP32, choisi pour sa capacité à gérer des signaux haute fréquence grâce à ses modules matériels internes.
Le montage repose sur quatre éléments clés :
- Le Moteur JGB37-520 : Un moteur à courant continu 12V équipé d’un réducteur (ratio 1:19) et d’un encodeur magnétique à effet Hall (11 pôles).
- L’Unité de Contrôle (ESP32) : Utilise le périphérique PCNT (Pulse Counter) pour compter les impulsions de l’encodeur sans charger le processeur.
- L’Interface de Visualisation : Un écran OLED SSD1306 (128×32) communiquant en I2C pour un affichage clair et instantané.
- Le Contrôle de Vitesse : Un potentiomètre permet de faire varier la vitesse du moteur via un signal PWM envoyé au driver moteur.
Prérequis :
- 1 x Carte ESP32
- 1 x Potentiomètre 10KΩ
- 1 x JGB37-520 (12V 530 tr/min)
- 1 x DRV8871
- 1 x 0.91 inch OLED I2C Display 128 x 32 Pixels
- 1 x Breadboard
Version IDE :
- Arduino IDE 2.3.5
Bibliothèque :
- Adafruit_GFX.h (version: 1.12.6)
- Adafruit_SSD1306.h (version: 2.5.16)
- Adafruit BusIO (version: 1.17.4)
Vidéo de démonstration :
Schéma de câblage :


Code :
// --- BIBLIOTHÈQUES ---
#include <Wire.h> // Gère la communication I2C (pour l'écran)
#include <Adafruit_GFX.h> // Bibliothèque de base pour les graphismes
#include <Adafruit_SSD1306.h> // Pilote spécifique pour l'écran OLED SSD1306
#include "driver/pcnt.h" // Module "Pulse Counter" interne de l'ESP32 (compteur matériel)
// --- CONFIGURATION ÉCRAN ---
#define SCREEN_WIDTH 128 // Largeur de l'écran en pixels
#define SCREEN_HEIGHT 32 // Hauteur de l'écran en pixels
// Création de l'objet "display" (le -1 signifie qu'il n'y a pas de bouton Reset externe)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// --- DÉFINITION DES BROCHES (PINS) ---
const int PIN_ENC_A = 14; // Signal A de l'encodeur (canal de comptage)
const int PIN_ENC_B = 33; // Signal B de l'encodeur (détermine le sens)
const int PIN_PWM = 25; // Sortie vers le driver moteur (vitesse)
const int PIN_DIR = 26; // Sortie vers le driver moteur (sens de rotation)
const int PIN_POT = 34; // Entrée analogique du potentiomètre
// --- PARAMÈTRES TECHNIQUES ---
const float RESOLUTION = 209.0; // Nombre de "ticks" pour 1 tour complet de l'axe de sortie
int16_t last_count = 0; // Stocke la position précédente pour calculer la vitesse
unsigned long prev_ms = 0; // Stocke le temps du dernier calcul
void setup() {
Serial.begin(921600); // Initialise la console série à haute vitesse
// Initialisation de l'écran OLED sur l'adresse I2C 0x3C
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for(;;); // Si l'écran ne répond pas, on bloque le programme ici
}
display.clearDisplay(); // Efface la mémoire de l'écran
display.setTextColor(SSD1306_WHITE); // Définit la couleur du texte
// --- CONFIGURATION DU COMPTEUR MATÉRIEL (PCNT) ---
pcnt_config_t pcnt_config = {
.pulse_gpio_num = PIN_ENC_A, // Pin qui envoie les impulsions
.ctrl_gpio_num = PIN_ENC_B, // Pin qui contrôle le sens (+ ou -)
.lctrl_mode = PCNT_MODE_REVERSE, // Inverse le compte si B est LOW
.hctrl_mode = PCNT_MODE_KEEP, // Garde le compte si B est HIGH
.pos_mode = PCNT_COUNT_INC, // Compte (+1) sur chaque front montant de A
.neg_mode = PCNT_COUNT_DIS, // Ne fait rien sur le front descendant (Mode x1)
.counter_h_lim = 32767, // Limite haute du compteur (16 bits)
.counter_l_lim = -32768, // Limite basse
.unit = PCNT_UNIT_0, // Utilise l'unité 0 de l'ESP32
.channel = PCNT_CHANNEL_0, // Canal 0 de cette unité
};
pcnt_unit_config(&pcnt_config); // Applique la configuration
// Filtre anti-parasites : ignore les signaux plus courts que 1000 cycles d'horloge
pcnt_set_filter_value(PCNT_UNIT_0, 1000);
pcnt_filter_enable(PCNT_UNIT_0);
pcnt_counter_clear(PCNT_UNIT_0); // Met le compteur à zéro
pcnt_counter_resume(PCNT_UNIT_0); // Démarre le comptage matériel
pinMode(PIN_PWM, OUTPUT); // Configure la broche PWM en sortie
pinMode(PIN_DIR, OUTPUT); // Configure la broche Direction en sortie
}
void loop() {
// --- COMMANDE DU MOTEUR ---
int pot = analogRead(PIN_POT); // Lit le potentiomètre (0 à 4095)
int vit = map(pot, 0, 4095, 0, 255); // Transforme la valeur pour le moteur (0 à 255)
analogWrite(PIN_PWM, vit); // Envoie le signal de vitesse au moteur
digitalWrite(PIN_DIR, LOW); // Définit un sens de rotation fixe
// --- CALCUL ET AFFICHAGE (Toutes les 200ms) ---
unsigned long now = millis(); // Récupère le temps actuel
if (now - prev_ms >= 200) { // Si 200ms se sont écoulées :
int16_t current_count = 0;
pcnt_get_counter_value(PCNT_UNIT_0, ¤t_count); // Lit le compteur matériel
int16_t delta = current_count - last_count; // Nombre de ticks depuis 200ms
float dt_min = (now - prev_ms) / 60000.0; // Convertit le temps en minutes
float rpm = abs((delta / RESOLUTION) / dt_min); // Calcule les Tours Par Minute (RPM)
// --- MISE À JOUR DE L'ÉCRAN OLED ---
display.clearDisplay(); // Efface l'écran avant de dessiner
display.setTextSize(3); // Texte très gros pour les chiffres
display.setCursor(10, 5); // Positionne le curseur (X=10, Y=5)
display.print((int)rpm); // Affiche la valeur entière des RPM
display.setTextSize(1); // Texte plus petit pour l'unité
display.print(" RPM"); // Affiche " RPM" juste après le chiffre
display.display(); // Envoie réellement l'image à l'écran
last_count = current_count; // Sauvegarde la position pour le prochain tour
prev_ms = now; // Sauvegarde le temps pour le prochain tour
}
}
