/****************************************************************************************************************************************
*   Projet Chronomètre et minuteur cyclique avec LCD 20X4 réalisé par:  Daniel Talbot Technicien                                         *
*   Pour Ez-Weekend-Project au Club Technique des Laurentides                                                                            *
*   Dans le cadre du programme C.I.P.A.D. (Cours d'initiation à la Programmation Arduino pour Débutant(e)s) gratuit et sans inscription. *
*   Copiez ce lien pour accéder à la vidéo concernant ce projet                                                                          *
*   https://youtu.be/iNi0kXjC6-A                                                                                                         *
*    ou celui-ci pour accéder à toutes les leçons déjà publiées...                                                                       *
*   https://www.youtube.com/playlist?list=PLoffRtP427acSg1FbpFuH_g5ptz-aovFN                                                             *
*                                                                                                                                        *
 ****************************************************************************************************************************************/
#include <LiquidCrystal_I2C.h>
// déclaration des variables LCD
LiquidCrystal_I2C lcd1(0x25, 20, 4), lcd2(0x26, 20, 4),  lcd3(0x27, 16, 2);

// déclaration des variables associées aux broches du contrôle joystick
const int btn_Select = 2, btn_Horz = A1, btn_Vert = A2 ;

/// déclaration des variables associées aux valeurs des positions du joystick
int select_Value = 0, horz_Value = 0, vert_Value = 0;

// Tableau de 7 chaines de caractères indexé de 0 à 7, 7 étant la valeur nulle pour fermer le tableau.
char* btn_press[7] = {"Select",                // index [0]
                      "                   ",   // index [1]
                      "Haut",                  // index [2]
                      "bas",                   // index [3]
                      "Gauche             ",   // index [4]
                      "              Droite",  // index [5]
                      "                    "   // index [6]
                     };                        // index [7]


// nouvelles variables
char msg1[20];  // réserve 20 espaces en mémoire tempon pour la variable msg1 de type char
char symbol;    // Déclare le type char à la variable symbol
int compteur_H, compteur_V; // variable compteur des boutons Horizontal et Vertical
int ascii = 32; // initialise à 32 la variable nommée ascii de type integer.
int speed = 1000; // délais imposé à la fonction loop () (0 ms = très rapide, 1000ms = lent, 5000ms = très lent)
// Fin de l'entête déclarative.===================================================

void setup() { // Initialisation.
  lcd1.init(); lcd2.init(); lcd3.init();  //Initialise les 3 afficheurs LCD I2C
  lcd1.backlight(); lcd2.backlight(); lcd3.backlight(); // Active le rétroéclairage des 3 afficheurs LCD I2C
  pinMode(btn_Select, INPUT_PULLUP); // Mode INPUT_PULLUP pour le bouton central "Select"

  lcdPrintCenter("Fn_Joystick()", 1, 0);  delay(2000);
  lcdPrintCenter("Print to Center", 1, 1); delay(2000);
  lcdPrintRight("Print to Right", 1, 2); delay(2000);
  lcdPrintLeft("Print to Left", 1, 3); delay(2000);
  lcd1.clear(); delay(2000); 
  lcdPrintCenter("Fn_Joystick()", 1, 0);
}

void loop() {  //Exécution: Placez votre code principal ici, à exécuter de manière répétée :
  // Balaie en boucle l'état des boutons du Joystick.
  select_Value = digitalRead(btn_Select);
  horz_Value = analogRead(btn_Horz);
  vert_Value = analogRead(btn_Vert);

  Fn_DisplayLCD2(); // Affiche sur lcd2 la valeur des boutons select, Horz et Vert Avant et après chaque pression.
  Fn_Joystick(); // Appel de la fonction perso "Fn_Joystick" dont le rôle est d'identifier le bouton pressé.

  lcdPrintCenter(String(compteur_H), 1, 2); // Affiche la valeur de compteur au centre de la 3e ligne de lcd1
  lcdPrintCenter("speed: " + String(speed) + "ms", 1, 3); // Affiche la vitesse de rafraîchissement au centre de la 4e ligne de lcd1
  Fn_DisplayLCD3();
}

/***********************************************************************************
  Fonction lcdPrintCenter(1er paramètre, 2e paramètre, 3e paramètre).
  Fonction lcdPrintCenter(texte à afficher, choix de l'écran lcd, No de la ligne).
 **********************************************************************************/
void lcdPrintCenter(String texte, int lcd, int ligne) {
  // texte.length(); // Défini la longeur de la variable "texte"
  switch (lcd) { // Commute vers l'afficheur correspondant à la variable "lcd"
    case 1: // Sélectionne lcd1.
      lcd1.setCursor((20 - texte.length()) / 2, ligne);  // positionne le curseur au centre de la ligne choisie et soustrait la longeur du text à afficher
      lcd1.print(texte);  // Affiche le texte demandé sur lcd1.
      break; // Quitte la case 1
    case 2:  // Sélectionne lcd2.
      lcd2.setCursor((20 - texte.length()) / 2, ligne);  // positionne le curseur au centre de la ligne choisie et soustrait la longeur du text à afficher
      lcd2.print(texte); // Affiche le texte demandé sur lcd2.
      break; // Quitte la case 2
    case 3: // Sélectionne lcd3.
      lcd3.setCursor((16 - texte.length()) / 2, ligne);  // positionne le curseur au centre de la ligne choisie et soustrait la longeur du text à afficher
      lcd3.print(texte); // Affiche le texte demandé sur lcd3.
      break; // Quitte la case 3
  }  // Quitte la fonction switch.
}  // Quitte la fonction lcdPrintCenter(texte à afficher, choix de l'écran lcd, No de la ligne).

/***********************************************************************************
  Fonction lcdPrintLeft(1er paramètre, 2e paramètre, 3e paramètre).
  Fonction lcdPrintLeft(texte à afficher, choix de l'écran lcd, No de la ligne).
 **********************************************************************************/
void lcdPrintLeft(String texte, int lcd, int ligne) {
  switch (lcd) { // Commute vers l'afficheur correspondant à la variable "lcd"
    case 1: // Sélectionne lcd1.
      lcd1.setCursor(0, ligne);  // positionne le curseur à gauche de la ligne choisie
      lcd1.print(texte);  // Affiche le texte demandé sur lcd1.
      break; // Quitte la case 1
    case 2:  // Sélectionne lcd2.
      lcd2.setCursor(0, ligne);  // positionne le curseur à gauche de la ligne choisie
      lcd2.print(texte); // Affiche le texte demandé sur lcd2.
      break; // Quitte la case 2
    case 3: // Sélectionne lcd3.
      lcd3.setCursor(0, ligne);  // positionne le curseur à gauche de la ligne choisie
      lcd3.print(texte); // Affiche le texte demandé sur lcd3.
      break; // Quitte la case 3
  }  // Quitte la fonction switch.
} // Quitte la fonction lcdPrintLeft(texte à afficher, choix de l'écran lcd, No de la ligne).

/***********************************************************************************
  Fonction lcdPrintRight(1er paramètre, 2e paramètre, 3e paramètre).
  Fonction lcdPrintRight(texte à afficher, choix de l'écran lcd, No de la ligne).
 **********************************************************************************/
void lcdPrintRight(String texte, int lcd, int ligne) {
  // texte.length() Défini la longeur de la variable "texte"
  switch (lcd) { // Commute vers l'afficheur correspondant à la variable "lcd"
    case 1: // Sélectionne lcd1.
      lcd1.setCursor(20 - texte.length(), ligne); // positionne le curseur à 20 de la ligne choisie et soustrait la longeur du text à afficher
      lcd1.print(texte);  // Affiche le texte demandé sur lcd1.
      break; // Quitte la case 1
    case 2:  // Sélectionne lcd2.
      lcd2.setCursor(20 - texte.length(), ligne);  // positionne le curseur à 20 de la ligne choisie et soustrait la longeur du text à afficher
      lcd2.print(texte); // Affiche le texte demandé sur lcd2.
      break; // Quitte la case 2
    case 3: // Sélectionne lcd3.
      //int displayCharLength = 16;
      // int offset = (displayCharLength - texte.length());
      lcd3.setCursor(16 - texte.length(), ligne);  // positionne le curseur à 16 de la ligne choisie et soustrait la longeur du text à afficher
      lcd3.print(texte); // Affiche le texte demandé sur lcd3.
      break; // Quitte la case 3
  }  // Quitte la fonction switch.
} // Quitte la fonction lcdPrintRight(texte à afficher, choix de l'écran lcd, No de la ligne).

void Fn_Joystick() {
  // commutateur d'affichage sur l'écran lcd1. Affiche la position du bouton pressé.
  switch (select_Value) { // commute vers la case correspondant à la valeur du bouton Select.
    case 0: lcdPrintCenter(btn_press[select_Value], 1, 2);  // 0 lorsque pressé.
      // réinitialisation de toutes les valeurs à leur valeurs par défaut.
      lcdPrintCenter("Reset all values", 1, 1); speed = 1000; compteur_H = 0; ascii = 32;
      delay(2000); // conserve le message "Reset all values" affiché pendant 2 secondes
      break; // Quitte la case 0
    case 1: lcdPrintCenter(btn_press[select_Value], 1, 2); break; // 1 par défaut
  } // Quitte switch(select_Value)
  
  switch (vert_Value) { // commute vers la case correspondant à la valeur du bouton vertical.
    case 0: lcdPrintCenter(btn_press[2], 1, 1); // Si pressé Haut affiche "haut" au centre de la 2e ligne
      speed = speed - 100;
      if (speed <= 0) {
        speed = 0; //Limite la valeur minimale à 10ms
      } // fin de la condition if()
      break; // Quitte la case 0
    case 512: // si aucun bouton pressé
      lcdPrintCenter(btn_press[1], 1, 1); // efface la 2e ligne
      lcdPrintCenter(btn_press[1], 1, 3); // efface la 4e ligne
      break; // Quitte la case 512
    case 1023: lcdPrintCenter(btn_press[3], 1, 3); // si pressé bas affiche "bas" au centre de la 4e ligne.
      speed = speed + 100; // incrémente la variable speed par step de 100
      break; // Quitte la case 1023
  } // Quitte switch (vert_Value)

  switch (horz_Value) { // commute vers la case correspondant à la valeur du bouton Horizontal.
    case 0: lcdPrintCenter(btn_press[4], 1, 2); // Si pressé Gauche affiche "Gauche" à gauche de la 3e ligne
      compteur_H--; // compteur descendant du bouton horizontal gauche
      if (compteur_H < 0) { 
        compteur_H = 0; // Limite la valeur minimale de compteur à 0.
      }
      ascii--; // décrémente de 1 la variable ascii
      if (ascii < 32) { 
        ascii = 32;// Limite la valeur minimale de ascii à 32.
      }
      break; // Quitte la case 0
    case 512: delay(500); lcdPrintCenter(btn_press[6], 1, 2); // si aucun bouton pressé efface la 3e ligne
      break; // Quitte la case 512

    case 1023: lcdPrintCenter(btn_press[5], 1, 2); // Si pressé Droite affiche "Droite" à droite de la 3e ligne
      compteur_H++; // Incrémente de 1 compteur_H (bouton horizontal droite)
      ascii++;    // Incrémente de 1 la variable ascii 
      //NOTE: ascii de 32 à 127. (premier caractère visible à 33 jusqu'à 127)
      if (ascii >= 127) { // Note: sans cette limite d'autres caractères seront visibles de 162 à 255.
        ascii = 127;  // Limite la valeur maximale ascii à 127.
      }
      break; // Quitte la case 1023
  }  // quitte switch (horz_Value)
}

void Fn_DisplayLCD2() {
  lcd2.setCursor(0, 0); lcdPrintCenter("Joystick value ", 2, 0); // entête de LCD2.
  lcd2.setCursor(0, 1); lcd2.print("SELECT: "); lcd2.print(select_Value);
  lcd2.setCursor(0, 2); lcd2.print("HORZ: "); lcd2.print(horz_Value);
  lcd2.print("     ");  //efface l'ancienne valeur Horizontale
  lcd2.setCursor(0, 3); lcd2.print("VERT: "); lcd2.print(vert_Value);
  lcd2.print("     ");  //efface l'ancienne valeur verticale
}

void Fn_DisplayLCD3() { 
  symbol = ascii;  // défini la position (ascii type integer) à symbol (type char) dans le tabeau ASCII 
  sprintf(msg1, "ASCII: %3d/127", ascii); // formatage et mise en mémoire tampon du texte msg1 à afficher
  lcdPrintLeft(String(msg1), 3, 0); // affichage à gauche de msg1 incluant la variable changeante "ascii" sur la première ligne de lcd3
  lcdPrintLeft("Symbole: " + String(symbol), 3, 1); // affichage à gauche du mot "Symbole : " incluant le caractère ASCII sur la 2e ligne de lcd3
  delay(speed); // temporisation (Vitesse d'exécution de la fonction loop) 
}
$abcdeabcde151015202530354045505560fghijfghij