Ignorer et passer au contenu

Livraison offerte à partir de 50€ d'achats, livrée sous 48h !

Livraison à partir de seulement 2.50€ !

Contents Menu Expand Light mode Dark mode Auto light/dark mode

Utiliser les timers de l’ESP32 en code Arduino

(Mis à jour le 23/01/2023)

Dans cet article, 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 threashold que l’on appelle communément l’autoreload .

hw_timer_t * timer = NULL;

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 = T_{timer}\times10^{6}\space ou \space T_{timer} = autoreload\times10^{-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 .

Incrémenter une variable et générer des flags

La routine d’interruption doit s’exécuter le plus rapidement possible pour éviter de trop perturber le programme principal. Ainsi on utilise communément des flags qui changeront d’état (en général un booléen : true ou false ) dans l’isr . Ces changements seront ensuite traités dans la boucle principale :

hw_timer_t * timer = NULL;
volatile boolean tick_flags = false;

void IRAM_ATTR timer_isr() {
  tick_flags = true;
}

void setup

Cette section est réservée aux abonnés. Il vous reste 78% à découvrir.

Devenir membre premium

Déjà abonné ? Connectez-vous

Utilisations avancées des timers sur l’ESP32 en code Arduino

Utiliser des sémaphores pour gérer l’accès lecture/écriture à une variable partagée

C’est une bonne pratique d’encadrer le code de l’interruption d’un timer dans un sémaphore pour gérer l’accès aux variables globales. Cela permet de prédire le fonctionnement du programme quand la routine d’interruption et le programme principal veulent écrire au même moment la même variable. Puisque le code Arduino pour ESP32 utilise freeRTOS en tant qu’OS en temps réel, les sémaphores sont déjà intégrés : il ne reste qu’à les utiliser directement dans notre programme :

Cette section est réservée aux abonnés. Il vous reste 94% à découvrir.

Devenir membre premium

Déjà abonné ? Connectez-vous