Publié par Prof. Jean DEMARTINI sous licence Creative Commons BY-SA.
Le développement de procédures synchrones sur Arduino n’est pas très facile. La bibliothèque de base ne permet pas de réaliser des horloges logicielles non-bloquantes pour déclencher des actions associées à différentes périodes d’échantillonnage. De telles horloges permettent une programmation « event-driven synchrone » non bloquante. Un autre article montrera comment réaliser une programmation « event-driven asynchrone » déterministe non bloquante.
Cahier des charges
Une horloge software est caractérisée par :
- une période (ici en millisecondes) déclenchant des « tics » (événements d’horloge) à intervalles réguliers,
- une phase (en millisecondes) avant le premier « tic »,
- une fonction de callback (action périodique) dont l’appel est déclenché à chaque « tic ».
Implémentation
/*** * Implementation of software clocks based on * the system clock millis(). * * That idea can be extended to faster software clocks based * on the system clock micros(). ***/ class Clock { private: unsigned int phase; unsigned int period; unsigned long counter; void (*callback)(void); public: void setup(int, int, void(*)(void)); int tick(void); }; void Clock::setup(int p, int f, void (*cb)(void)) { period = p; phase = f; counter = millis(); callback = cb; } int Clock::tick() { int s = (millis() - counter) > phase; if (s) { /*** * the clock event triggers. * the callback function. ***/ phase = period; counter = millis(); callback(); return 1; } return 0; }
Exemple d’application
La commande d’un moteur pas à pas nécessite de créer des signaux de commande périodiques mais déphasés.
/*** * Producing the 4 phases for a step motor control. ***/ ... const int ledPin1 = 13; const int ledPin2 = 7; const int ledPin3 = 8; const int ledPin4 = 9; Clock c1, c2, c3, c4; /*** * callback functions */ void blink1() { digitalWrite(ledPin1, !digitalRead(ledPin1)); } void blink2() { digitalWrite(ledPin2, !digitalRead(ledPin2)); } void blink3() { digitalWrite(ledPin3, !digitalRead(ledPin3)); } void blink4() { digitalWrite(ledPin4, !digitalRead(ledPin4)); } void setup() { pinMode(ledPin1, OUTPUT); pinMode(ledPin2, OUTPUT); pinMode(ledPin3, OUTPUT); pinMode(ledPin4, OUTPUT); digitalWrite(ledPin1, LOW); digitalWrite(ledPin2, LOW); digitalWrite(ledPin3, LOW); digitalWrite(ledPin4, LOW); /*** * Building of the different clocks. * The callback functions are activated. */ c1.setup(5, 1, &blink1); c2.setup(5, 2, &blink2); c3.setup(5, 3, &blink3); c4.setup(5, 4, &blink4); } void loop() { /*** * put here a call to the tick method of each clocks. * When time of period elapse, the callback function * is automatically called. * * Its a kind of clocked software interrupts. * * It is possible to use a master hardware clock to tick all the other ones. */ c1.tick(); c2.tick(); c3.tick(); c4.tick(); ... /*** main part of the application ***/ }
En rassemblant toutes les parties
/*** * Implementation of software clocks based on * the system clock millis(). * * That idea can be extended to faster software clocks based * on the system clock micros(). ***/ const int ledPin1 = 13; const int ledPin2 = 7; const int ledPin3 = 8; const int ledPin4 = 9; class Clock { private: unsigned int phase; unsigned int period; unsigned long counter; void (*callback)(void); public: void setup(int, int, void(*)(void)); int tick(void); }; void Clock::setup(int p, int f, void (*cb)(void)) { period = p; phase = f; counter = millis(); callback = cb; } int Clock::tick() { int s = (millis() - counter) > phase; if (s) { /*** * the clock event triggers. * the callback function. ***/ phase = period; counter = millis(); callback(); return 1; } return 0; } Clock c1, c2, c3, c4; /*** * callback functions */ void blink1() { digitalWrite(ledPin1, !digitalRead(ledPin1)); } void blink2() { digitalWrite(ledPin2, !digitalRead(ledPin2)); } void blink3() { digitalWrite(ledPin3, !digitalRead(ledPin3)); } void blink4() { digitalWrite(ledPin4, !digitalRead(ledPin4)); } void setup() { pinMode(ledPin1, OUTPUT); pinMode(ledPin2, OUTPUT); pinMode(ledPin3, OUTPUT); pinMode(ledPin4, OUTPUT); digitalWrite(ledPin1, LOW); digitalWrite(ledPin2, LOW); digitalWrite(ledPin3, LOW); digitalWrite(ledPin4, LOW); /*** * Building of the different clocks. * The callback functions are activated. */ c1.setup(5, 1, &blink1); c2.setup(5, 2, &blink2); c3.setup(5, 3, &blink3); c4.setup(5, 4, &blink4); } void loop() { /*** * put here a call to the tick method of each clocks. * When time of period elapse, the callback function * is automatically called. * * Its a kind of clocked software interrupts. * * It is possible to use a master clock to tick all the other ones. */ c1.tick(); c2.tick(); c3.tick(); c4.tick(); }