Ci dessous un exemple : une pendule qui affiche les heures/minutes/secondes.

Mode d'emploi

  • pour régler appuyer d'abord sur SELECT. Il apparait HH sous les heures, qui indique le mode "modification des heures"
  • avec les flèches GAUCHE et DROITE on navigue entre les modes "modif. minutes" et "modif. secondes"
  • dans ces modes, on augmente/diminue la valeur par UP/DOWN
  • on revient en mode normal par SELECT

Lire le code

On remarque nettement le découplage total entre

  • la gestion du clavier, qui se passe intégralement dans la fonction Keypad::getButton(),
  • la programmation de l'horloge, qui est dans loop()

Le code

// une pendule

 
 #define VERSION "v8"
 
 #include <LiquidCrystal.h>
 
 typedef unsigned long time_t;
 
 class Keypad {
 public:
   enum Button { 
     RIGHT, UP, DOWN, LEFT, SELECT, NONE, ERROR
   };
 
 protected:
   int m_pin;
   time_t m_bounce_timeout;
   Button m_last_button;
   int m_bounce_delay;
 
 public:  
   Keypad(int pin) : 
     m_pin(pin), m_bounce_timeout (0), m_last_button (NONE), m_bounce_delay (500)
   {  }  
 
   void setBounceDelay(int delay) {
     m_bounce_delay = delay;
   }
 
   Button getButton() {
     static const int values [] 
       = { 
       50, 195, 380, 555, 790     
     };
     // acquisition        
     int value = analogRead(m_pin);
     
     // quel bouton ?
     int b = 0;
     for (; b <= NONE; b++) {
       if (value <= values[b])
         break;
     }  
     Button current = (Button) b;
 
     // élimination des rebonds
     time_t now = millis();
     Button pushed = NONE;
 
      if ( ((current != NONE) 
            && (     (m_last_button == NONE) 
                     || (m_last_button != current)))
         || 
            ((m_last_button != NONE)
             && (now > m_bounce_timeout) )  ) 
     {  // une aspirine ?
         pushed = m_last_button = current;
         m_bounce_timeout = now + m_bounce_delay;
     }
 
     return pushed;
   }  
 };
 
 // ======================
 
 LiquidCrystal lcd ( 8,9, 4,5,6,7 );
 Keypad keypad(0);
 
 long int shift = 0;
 
 enum STATES  {  NORMAL, SET_HH, SET_MM, SET_SS } 
                       state = NORMAL;
 
 const char * states[] = {
   "Clock " VERSION, "hh", "   mm", "      ss"
 };
 
 void setup() {
   lcd.begin(16,2);
 }
 
 char * fmt(int value, int digits)
 {
   static char tmp[10];
   char *p = tmp+9;
   *p = '\0';
   for(int j=0; j<digits; j++) {
     *--p = value % 10 + '0';
     value /= 10;
   }
   return p;
 }
 
 // ===================
 void display() {
   lcd.clear();
   long elapsed = (millis() / 1000) + shift;
   while (elapsed < 0L)
     elapsed += 24*60*60L;
 
   int s = elapsed % 60L;
   int m = (elapsed / 60L) % 60L;
   int h = (elapsed / 3600L) % 24L;
   lcd.print(fmt(h,2));
   lcd.print(":");
   lcd.print(fmt(m,2));
   lcd.print(":");
   lcd.print(fmt(s,2));
   lcd.setCursor(0,1);
   lcd.print(states[state]);
 }
 
 // =====================
 
 time_t display_timeout = 0;
 
 void loop() {
   static const int delta[] = 
   {  0,  3600, 60, 1 };
 
   time_t now = millis();
 
   switch (keypad.getButton()) {
     case Keypad::SELECT :
     state = (state == NORMAL) ? SET_HH : NORMAL;
     break;
     case Keypad:: LEFT :
     if (state == SET_MM || state == SET_SS)
       state = (STATES)(state-1);
     break;
     case Keypad:: RIGHT :
     if (state == SET_HH || state == SET_MM) 
       state = (STATES)(state+1);
     break;
     case Keypad::UP :
     shift += delta[state]; 
     break;
     case Keypad::DOWN :
     shift -=  delta[state]; 
   default:
     break;
   }
 
   if (now >= display_timeout) {
     display();
     display_timeout = now + 500;
   }
 }