Construisez une montre numérique Arduino avec machine à états finis
Composants et fournitures
| Composant | Quantité |
|---|---|
| Arduino UNO (ou Mega, compatible shield LCD) | 1 |
| Shield LCD Keypad | 1 |
Applications et services en ligne
- YAKINDU Statechart Tools (gratuit pour usage non commercial)
- Eclipse C++ IDE pour Arduino
À propos du projet
Je vais vous montrer comment créer une montre numérique avec YAKINDU Statechart Tools et l'exécuter sur un Arduino équipé d'un Shield LCD Keypad.
Le modèle original vient de David Harel, qui a publié un article sur l'« extension large du formalisme conventionnel des machines à états et diagrammes d'états » en utilisant l'exemple d'une montre numérique. Je l'ai reconstruit avec YAKINDU (outil de modélisation graphique d'automates avec génération de code C/C++) et ramené à la vie sur Arduino.
Fonctionnement de la montre numérique
Rappelez-vous les montres numériques des années 90 : heure, date, alarmes (×2), chronomètre, bip horaire, rétroéclairage. Trois boutons principaux : On/Off, Mode, Set, plus Light On/Off.
Le bouton Mode fait défiler : Heure → Date → Alarme 1 → Alarme 2 → Activer bip horaire → Chronomètre.
Dans les menus : On/Off configure le mode actif, Set règle l'heure (horloge ou alarmes). Le chronomètre est piloté par Light On (démarrer) et Light Off (arrêter/lap). Un bip horaire et un rétroéclairage sont prévus (non câblés dans cette démo).
La machine à états
(Diagrammes d'états disponibles dans l'article original – trop volumineux pour être reproduits ici)
Le modèle sépare la partie textuelle (définition événements, variables) et graphique (diagramme d'états). Des événements d'entrée : onoff, set, mode, light, light_r. Un événement interne incrémente le temps toutes les 100 ms :
every 100 ms / time += 1
Calcul de l'affichage HH:MM:SS :
display.first = (time / 36000) % 24; // heures
display.second = (time / 600) % 60; // minutes
display.third = (time / 10) % 60; // secondes
Mise à jour LCD via l'opération updateLCD à chaque cycle.
Éléments de modélisation utilisés : CompositeState, History, Sub-Diagrams, ExitNodes… (voir guide utilisateur YAKINDU).
Shield LCD Keypad
Idéal pour projets simples nécessitant affichage et boutons (HMI basique). 5 boutons utilisateur + 1 Reset. Les 5 boutons partagent la broche A0 via un diviseur de tension.
Valeurs lues sur A0 (peuvent varier selon fabricant) :
- Aucun : 1023
- Select : 640
- Left : 411
- Down : 257
- Up : 100
- Right : 0
Seuils pour lecture boutons (anti-rebond logiciel) :
#define NONE 0
#define SELECT 1
#define LEFT 2
#define DOWN 3
#define UP 4
#define RIGHT 5
static int readButton() {
int result = analogRead(0);
if (result < 50) return RIGHT;
if (result < 150) return UP;
if (result < 300) return DOWN;
if (result < 550) return LEFT;
if (result < 850) return SELECT;
return NONE;
}
Interface avec la machine à états
Le code C++ généré fournit des interfaces à implémenter. Il faut connecter les événements d'entrée aux boutons du shield, avec anti-rebond (sinon événements multiples = comportement imprévisible).
Méthode : détection de front descendant (relâchement du bouton). Lecture → attente 80 ms → relecture. Si oldResult != NONE et nouvelle lecture = NONE, le bouton a été pressé puis relâché → on lève l'événement correspondant.
int oldState = NONE;
static void raiseEvents() {
int buttonPressed = readButton();
delay(80);
oldState = buttonPressed;
if (oldState != NONE && readButton() == NONE) {
switch (oldState) {
case SELECT: stateMachine->getSCI_Button()->raise_mode(); break;
case LEFT: stateMachine->getSCI_Button()->raise_set(); break;
case DOWN: stateMachine->getSCI_Button()->raise_light(); break;
case UP: stateMachine->getSCI_Button()->raise_light_r(); break;
case RIGHT: stateMachine->getSCI_Button()->raise_onoff(); break;
}
}
}
Assemblage final
Le programme principal utilise 3 composants :
- La Machine à états
- Un Timer
- Un gestionnaire d'affichage (LCD)
DigitalWatch* stateMachine = new DigitalWatch();
CPPTimerInterface* timer_sct = new CPPTimerInterface();
DisplayHandler* displayHandler = new DisplayHandler();
void setup() {
stateMachine->setSCI_Display_OCB(displayHandler);
stateMachine->setTimer(timer_sct);
stateMachine->init();
stateMachine->enter();
}
long current_time = 0, last_cycle_time = 0;
void loop() {
raiseEvents();
last_cycle_time = current_time;
current_time = millis();
timer_sct->updateActiveTimer(stateMachine, current_time - last_cycle_time);
stateMachine->runCycle();
}
Récupérer l'exemple
Dans l'IDE YAKINDU : File → New → Example → YAKINDU Statechart Examples → Next → Arduino - Digital Watch (C++)
Téléchargez l'IDE : yakindu.org – essai 30 jours, puis licence gratuite pour usage non commercial.
Processus de fabrication
- Conception de machines à états finis : Du concept à l'implémentation
- Créer un système Ambilight spectaculaire pour moniteur avec Arduino
- Dé numérique Arduino sur écran LCD 16x2 – Générateur aléatoire à bouton poussoir
- Construire un dispositif de lévitation ultrasonique avec Arduino – Guide étape par étape
- Construire un Voltmètre Intelligent avec Arduino et Smartphone – Projet DIY Facile
- Moniteur de Fréquence Cardiaque IoT en Temps Réel avec Arduino et MAX30100
- Serveur Web Arduino Uno WiFi : Commander une LED via Navigateur
- Construisez votre propre Tamagotchi Arduino : Un animal de compagnie numérique DIY
- Montre connectée Arduino DIY : Construisez votre propre montre style Apple Watch