#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <math.h>
// -------------------------------------------------------------------
// 1. DÉFINITIONS DES BROCHES ET COMPOSANTS
// -------------------------------------------------------------------
const int JOY_SEL_PIN = 2; // Bouton Select - Broche Numérique 2 (INPUT_PULLUP)
const int JOY_HORZ_PIN = A0; // Axe X (Horizontal / L-R)
const int JOY_VERT_PIN = A1; // Axe Y (Vertical / U-D)
// Adresses I2C des LCDs
LiquidCrystal_I2C lcd_menu(0x27, 20, 4); // LCD1 (Axe X)
LiquidCrystal_I2C lcd_rapport(0x26, 20, 4); // LCD2 (Bouton SEL)
LiquidCrystal_I2C lcd_infos(0x20, 20, 4); // LCD3 (Axe Y)
// -------------------------------------------------------------------
// 2. VARIABLES GLOBALES DE STABILISATION ET MÉMOIRE
// -------------------------------------------------------------------
// Variables pour le Debouncing du Bouton SEL
int val_sel = HIGH;
unsigned long dernierChangementTemps = 0;
const long delaiDebounce = 50;
// Variables de Mémoire pour l'Anti-Scintillement
// Nous utilisons maintenant des chaînes de caractères pour les états précédents des axes
String state_horz_precedent = "";
String state_vert_precedent = "";
int val_sel_precedent_bouton = HIGH;
// Seuils pour définir les directions
const int TOLERANCE_ANALOGUE = 5; // Bruit résiduel
const int SEUIL_MOUVEMENT = 400; // Valeur seuil pour détecter un mouvement (1023 - 400 = 623)
// -------------------------------------------------------------------
// 3. FONCTION DE LISSAGE (ANTI-BRUIT ANALOGIQUE)
// -------------------------------------------------------------------
int lireAxeLisse(int pinAnalogique) {
const int numLectures = 10;
long total = 0;
for (int i = 0; i < numLectures; i++) {
total += analogRead(pinAnalogique);
delay(1);
}
return total / numLectures;
}
// -------------------------------------------------------------------
// SETUP
// -------------------------------------------------------------------
void setup() {
Wire.begin();
Serial.begin(9600);
pinMode(JOY_SEL_PIN, INPUT_PULLUP);
// Initialisation des LCDs
lcd_menu.init(); lcd_menu.backlight();
lcd_menu.setCursor(0, 0); lcd_menu.print("AXE X:");
lcd_infos.init(); lcd_infos.backlight();
lcd_infos.setCursor(0, 0); lcd_infos.print("AXE Y:");
lcd_rapport.init(); lcd_rapport.backlight();
lcd_rapport.setCursor(0, 0); lcd_rapport.print("BOUTON SEL:");
}
// -------------------------------------------------------------------
// LOOP
// -------------------------------------------------------------------
void loop() {
// --- 1. Lecture et Lissage des Axes Analogiques ---
int val_horz = lireAxeLisse(JOY_HORZ_PIN);
int val_vert = lireAxeLisse(JOY_VERT_PIN);
// --- 2. Lecture et Debouncing du Bouton Numérique ---
int lecture_brute_sel = digitalRead(JOY_SEL_PIN);
if (lecture_brute_sel != val_sel_precedent_bouton) {
dernierChangementTemps = millis();
}
if ((millis() - dernierChangementTemps) > delaiDebounce) {
if (lecture_brute_sel != val_sel) {
val_sel = lecture_brute_sel;
}
}
val_sel_precedent_bouton = lecture_brute_sel;
// =========================================================
// 3. CONVERSION DES VALEURS ANALOGIQUES EN DIRECTIONS (TEXTE)
// =========================================================
// --- Détermination de l'état Vertical (Axe Y) ---
String state_vert;
if (val_vert < SEUIL_MOUVEMENT) {
state_vert = "HAUT (UP)";
} else if (val_vert > (1023 - SEUIL_MOUVEMENT)) {
state_vert = "BAS (DOWN)";
} else {
state_vert = "CENTRE";
}
// --- Détermination de l'état Horizontal (Axe X) ---
String state_horz;
if (val_horz < SEUIL_MOUVEMENT) {
state_horz = "GAUCHE (LEFT)";
} else if (val_horz > (1023 - SEUIL_MOUVEMENT)) {
state_horz = "DROITE (RIGHT)";
} else {
state_horz = "CENTRE";
}
// =========================================================
// 4. LOGIQUE D'AFFICHAGE ANTI-SCINTILLEMENT (TEXTE)
// =========================================================
// --- Affichage Axe X (LCD_Menu) ---
if (state_horz != state_horz_precedent) {
lcd_menu.setCursor(0, 1);
lcd_menu.print(" "); // Effacer la ligne entière
lcd_menu.setCursor(0, 1);
lcd_menu.print(state_horz);
state_horz_precedent = state_horz;
}
// --- Affichage Axe Y (LCD_Infos) ---
if (state_vert != state_vert_precedent) {
lcd_infos.setCursor(0, 1);
lcd_infos.print(" "); // Effacer la ligne entière
lcd_infos.setCursor(0, 1);
lcd_infos.print(state_vert);
state_vert_precedent = state_vert;
}
// --- Affichage Bouton Select (LCD_Rapport) ---
if (val_sel != val_sel_precedent_bouton) {
lcd_rapport.setCursor(0, 1);
lcd_rapport.print(" ");
lcd_rapport.setCursor(0, 1);
// CORRECTION DE L'AFFICHAGE (INVERSION POUR VOTRE PRÉFÉRENCE)
if (val_sel == LOW) { // Si LOW est lu (physiquement APPUYÉ)
lcd_rapport.print("RELACHE");
} else { // Si HIGH est lu (physiquement RELACHÉ)
lcd_rapport.print("** APPUYE **");
}
}
// =========================================================
// 5. LOGIQUE DE NAVIGATION DE VOTRE MENU (Utilisez les variables state_horz et state_vert)
// =========================================================
// Événement Vertical (Haut/Bas)
if (state_vert == "HAUT (UP)" && state_vert != state_vert_precedent) {
// Le mouvement HAUT est stable et vient d'être activé (pour déclencher une seule action)
// Ajoutez ici votre logique de menu (ex: move_cursor_up();)
}
else if (state_vert == "BAS (DOWN)" && state_vert != state_vert_precedent) {
// Logique BAS
}
// Événement Horizontal (Gauche/Droite)
if (state_horz == "GAUCHE (LEFT)" && state_horz != state_horz_precedent) {
// Logique GAUCHE
}
else if (state_horz == "DROITE (RIGHT)" && state_horz != state_horz_precedent) {
// Logique DROITE
}
// Événement Bouton Select
if (val_sel == LOW && val_sel != val_sel_precedent_bouton) {
// Le bouton vient d'être physiquement APPUYÉ
// Logique Confirmer/Entrer
}
delay(10);
}Relais
Vibreur
Relais
Granules
Lcd_Menu
Lcd_Rapport
Lcd_Infos