Timer
Dans la section précédente, nous avons vu comment réagir à un événement produit par un GPIO grâce aux interruptions. Une autre source fréquente d’interruptions est le timer. Avec LibOpenCM3, nous devions choisir un timer parmi ceux disponibles sur la cible et configurer tous les registres. Mbed OS propose des interfaces de haut niveau pour gérer les timers de manière plus simple.
Classe Ticker
Commençons par le premier cas d’utilisation d’un timer : effectuer une tâche périodiquement avec une période donnée.
Pour cela, Mbed OS offre la classe Ticker
. L’exemple ci-dessous fait clignoter une LED avec une période de 1 seconde
(500 ms éteinte et 500 ms allumée).
timer_blink.cpp | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
La ligne 11 crée une instance de Ticker
(flipper
) et à la ligne 12, on lui attache la routine toggle
qui sera appelée toutes les 500 millisecondes.
Nous utilisons un callback
(vu dans la section précédente) pour passer la LED en paramètre à la fonction toggle
.
Notez comment est définie la période à la ligne 12. En C++, les intervalles de temps sont souvent de type std::chrono::duration
.
Le suffixe ms
indique des millisecondes. On aurait aussi pu écrire 0.5
qui exprime l’intervalle en secondes, mais l’utilisation
d’un préfixe est plus expressive. Pour voir la liste des suffixes disponibles et pour plus d’information, consultez cppreference.com.
Exercice Timer/1
Quel(s) mécanismes(s) de C++ permet(tent) de simplement ajouter un suffixe ms
à une durée pour un temps en millisecondes ?
Solution
- La surcharge de l’opérateur
""ms
(User defined literals) - La classe
std::chrono::duration
utilise aussi le concept des Templates, pour la représentation interne de la durée, mais ce n’est pas directement lié à la question du suffixe.
Il est important de bien apprécier l’avantage d’avoir une unité associée à un nombre. Si on n’utilise un type simple (tel que int
ou float
), le risque
est grand de ne plus savoir si le nombre représente des secondes, des millisecondes ou des microsecondes. En utilisant des
classes et en donnant systématiquement des unités, on réduit grandement le risque d’erreurs.
L’importance des unités en informatique
En 1999, la NASA à perdu le “Mars Climate Orbiter” à cause d’une confusion d’unités. La sonde a voyagé pendant 7 mois pour disparaître avant même d’entrer en orbite autour de Mars.
La sonde a soit été détruite dans l’atmosphère martienne, soit elle est sortie de sa trajectoire et est entré dans une orbite autour du Soleil. La cause de cet échec – qui coûta 125 millions de dollars à la NASA – était que les ingénieurs de Lockheed (le fabricant des moteurs de freinage de la sonde) utilisaient des unités anglo-saxonnes alors que les ingénieurs de NASA utilisaient des unités métriques.
Le temps du noyau
Attention
La technique présentée ici est donnée à titre indicatif et ce n’est pas la technique recommandée pour mesurer un temps. Nous verrons une meilleure méthode dans la section suivante.
Mbed OS est un système d’exploitation et le noyau de Mbed OS à la notion du temps qui passe. On peut interroger le noyau pour mesurer le temps qui s’écoule dans un programme :
timer_measure_kernel.cpp | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
La ligne 5 interroge le temps actuel du noyau (en millisecondes et sur 64 bits), la ligne 6 attend 100 millisecondes, puis la ligne 7 lit le nouveau temps actuel du noyau. Le temps écoulé est la différence entre les deux temps.
Exercice Timer/2
Quel est le défaut de cette solution ?
Solution
Le nom de la méthode indique bien que nous mesurons des millisecondes, mais aucune unité n’est attachée au résultat.
Classe Timer
Le programme ci-dessus fonctionne, mais avec Mbed OS, la mesure du temps se fait plutôt avec la classe Timer
:
timer_measure_timer.cpp | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
A la ligne 7 nous créons une instance t
d’un timer
, à la ligne 8 nous démarrons le chronomètre et à la ligne 10 nous stoppons le chronomètre.
Nous obtenons la durée en microsecondes avec la méthode elapsed_time()
. Nous pouvons le convertir en millisecondes avec la méthode
duration_cast<milliseconds>()
. La méthode count()
1 retourne une valeur numérique.
Pour plus d’information concernant les timers, consultez la documentation de Mbed OS.
Exercice
Exercice Timer/3
Modifiez le code du clignotement de la LED (timer_blink.cpp
) pour garder la LED allumée pendant 250 millisecondes et éteinte pendant 750 millisecondes.
Solution
#include "mbed.h"
constexpr int kLedOn = 0;
constexpr int kLedOff = 1;
class MyDevice {
public:
MyDevice(PinName led) : led_(led, kLedOff), counter_{0} {};
void handler()
{
if (counter_ == 0) {
led_ = kLedOn;
} else if (counter_ == 1) {
led_ = kLedOff;
}
if (counter_ >= 3) {
counter_ = 0;
} else {
counter_++;
}
}
private:
DigitalOut led_;
int counter_;
};
int main()
{
MyDevice device(PE_0);
Ticker flipper;
flipper.attach(callback(&device, &MyDevice::handler), 250ms);
while (true) {
asm("nop");
}
}