Arduino, KeyPad, gestion des rebonds, suite
Par Michel Billaud, jeudi 28 mai 2015 à 19:15 :: Bidouilles :: #76 :: rss
Quand on joue avec le clavier (voir article précédent) on tombe de suite sur le problème des rebonds sur les boutons. Quand on appuie sur un bouton, le contact n'est pas très stable pendant un petit moment. L'idée est d'ignorer ces oscillations pendant un moment, et que ça soit la classe Keypad
qui s'en occupe.
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; } }
Commentaires
Aucun commentaire pour le moment.
Ajouter un commentaire
Les commentaires pour ce billet sont fermés.