|
Les Timers |
Utiliser les timers de l’ESP32 en code Arduino
Dans cette page, nous allons explorer le fonctionnement d’un timer sur l’ESP32 en utilisant du code Arduino. Nous verrons comment configurer et utiliser un timer de manière efficace, en utilisant des exemples pratiques pour vous aider à comprendre les concepts de base. Nous allons découvrir les étapes pour configurer un timer sur l’ESP32, avec les paramètres importants pour un fonctionnement optimal. C’est parti 😊.
Le fonctionnement d’un timer sur l’ESP32
Le fonctionnement théorique du timer n’est pas présenté dans cet article pour éviter de le surcharger. Si vous débutez et que vous ne connaissez pas le fonctionnement interne d’un timer, je vous encourage fortement à lire l’article théorique sur son fonctionnement . Il vous permettra de mieux comprendre comment choisir les valeurs des paramètres pour l’utiliser dans votre code Arduino.
Configurer et utiliser un timer de l’ESP32 avec du code Arduino
Voici le code squelette minimal pour utiliser un timer sur l’ESP32 avec du code Arduino. Il permet de déclencher une interruption dès que le timer atteint la valeur seuil threshold que l’on appelle communément l’autoreload .
|
void IRAM_ATTR timer_isr() { // This code will be executed every 1000 ticks, 1ms } void setup() { Serial.begin(115200); uint8_t timer_id = 0; uint16_t prescaler = 80; // Between 0 and 65 535 int threshold = 1000000; // 64 bits value (limited to int size of 32bits) timer = timerBegin(timer_id, prescaler, true); timerAttachInterrupt(timer, &timer_isr, true); timerAlarmWrite(timer, threshold, true); timerAlarmEnable(timer); } void loop() { } |
Sélection et configuration basique du timer
On définit un objet hw_timer_t en dehors de la fonction setup() pour pouvoir y accéder depuis différentes fonctions. La fonction timerBegin(uint8_t id, uint16_t prescaler, bool countUp) permet de configurer le timer :
Sur l’ESP32 il y a 4 timers complètement indépendants, on les choisit via un id compris entre 0 et 3. Ensuite, on choisit ensuite le prescaler que l’on veut appliquer au signal d’horloge du timer. Sur l’ESP32, c’est l’horloge APB_CLK cadencée à 80 MHz qui est utilisée.
Avertissement: Si vous utilisez des librairies externes dans votre code, elles utilisent peut-être des timers. Dans ce cas il faut faire attention de ne pas choisir un qui est déjà utilisé par celles-ci, sinon votre programme aura assurément des bugs !
Sur la plupart des exemples disponibles, un prescaler de 80 est appliqué pour avoir une période de comptage de 1 µs. À partir d’une période du timer en microsecondes, on pourra directement connaître la valeur de l’autoreload correspondante sans faire de calcul compliqué :
autoreload = Ttimer x 106 ou Ttimer = autoreload x 10-6
L’argument countUp précise dans quel sens on veut compter : true dans l’ordre croissant, false dans l’ordre décroissant.
Configurer l’alarme et le déclenchement d’une routine d’interruption
On attache au timer une interruption qui sera déclenchée à chaque fois que la valeur seuil sera dépassée avec timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge) .
Il faut mettre dans l’argument du milieu le nom de la routine d’interruption qui sera exécutée (ici timer_isr() ). On peut également choisir si l’interruption se déclenche au front montant ou descendant: on opte en général pour un front montant pour les timers.
La valeur seuil du compteur est définie par timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload) . On active le mode autoreload en mettant autoreload à true : une fois que le timer a dépassé la valeur alarm_value , il recommence à compter à partir de zéro et la fonction d’interruption est déclenchée.
Note: Avec un prescaler de 80, la valeur de alarm_value correspond directement à la période globale du timer en microsecondes.
Une fois que le timer a été complètement configuré, on peut l’activer avec son alarme avec timerAlarmEnable(timer) .
Si on exécute ce code, la fonction timer_isr() sera exécutée toutes les secondes. Puisque la fonction est vide dans ce code “squelette”, il ne se passera rien concrètement. Je vous propose une version qui fait clignoter la LED bleue de l’ESP32 sur la broche GPIO2 .
Code blink avec uniquement un timer
Voici le fameux “blink” récrit en utilisant uniquement un timer hardware qui se fera clignoter la LED bleue toutes les secondes :
|
hw_timer_t * timer = NULL; volatile uint8_t led_state = 0; void IRAM_ATTR timer_isr(){ led_state = ! led_state; digitalWrite(PIN_LED, led_state); } void setup() { Serial.begin(115200); pinMode(PIN_LED, OUTPUT); uint8_t timer_id = 0; uint16_t prescaler = 80; int threshold = 1000000; timer = timerBegin(timer_id, prescaler, true); timerAttachInterrupt(timer, &timer_isr, true); timerAlarmWrite(timer, threshold, true); timerAlarmEnable(timer); } void loop() { // put your main code here, to run repeatedly } |
On utilise le mot-clé volatile pour la variable led_state pour forcer le compilateur à ne pas faire d’optimisation. En effet, pour le compilateur, la fonction timer_isr () n’est jamais appelée dans le code car elle est appelée via une interruption externe (que le compilateur n’a pas connaissance).
Sans l’attribut volatile , le compilateur pourrait retirer la variable qui n’est a priori pas utilisée pour libérer de l’espace mémoire. En mettant le keyword volatile , on force le compilateur à ne pas prendre en compte cette variable pour l’optimisation.
Pour faire clignoter la LED, on utilise ici une petite astuce pour inverser l’état de la LED avec l’opérateur ! . Quand on l’utilise sur une variable, tous les zéros dans sa représentation binaire sont remplacés par des 1 (et vice-versa).
Ainsi la valeur de led_state sera inversée à chaque entrée dans la routine d’interruption : 0b0000000 → 0b11111111 → 0b0000000 … Puisque la fonction digitalWrite() regarde la valeur que du premier bit, on aura bien une alternance entre des 0 et 1.
Note: On rajoute l’attribut IRAM_ATTR lors de la déclaration de la fonction, pour indiquer au compilateur de charger l’ensemble du code de la routine d’interruption dans la RAM interne de l’ESP32, pour qu’elle s’exécute plus rapidement.
Avec ce programme, la LED bleue se met à clignoter, sans utiliser la fonction loop() , qui peut être utilisée pour faire d’autres tâches.
Créé avec HelpNDoc Personal Edition: Créez sans effort des fichiers PDF cryptés et protégés par mot de passe