ESP32 : interruptions et timer

Bonjour,

Je précise que je suis débutant.
J'utilise ce type de carte avec 1 relais intégré : ESP32 + relais + alimentation 230V AC intégrés + capteurs – F1ATB
Mon besoin est le suivant :

  • appuie sur "bouton" (bouton physique de la carte) : activation de relais1 (relais physique de la carte) et de LedRouge (LED physique de la carte))
  • après une temporisation : désactivation de relais1 et de LedRouge
    La fonction d'interruption "relais1Interrupt" est présente pour gérer le changement d'état de ce dernier (LOW vers HIGH).
    En effet, ce relais peut être activé indépendamment par un autre mécanisme (que l'appuie du bouton) et dans ce cas il faut allumer la Led
    Quand la temporisation est écoulé il faut désactiver le relais et la Led.

Voici le code :

#define bouton 0   // GPIO du bouton (GPIO0)
#define relais1 16   // GPIO du relais 1 (GPIO16)
#define LedRed 12
volatile int tempoDuration = 8000; // Durée de la tempo en millisecondes (10 secondes)

volatile int compteurBoutonInterrupt = 0;
volatile int compteurRelais1Interrupt = 0;
volatile int compteurstopTempo = 0;

hw_timer_t *timerRelais1 = NULL;

// Fonction pour afficher l'heure actuelle
void printCurrentTime() {
  unsigned long currentMillis = millis();
  unsigned long hours = (currentMillis / 3600000) % 24;
  unsigned long minutes = (currentMillis / 60000) % 60;
  unsigned long seconds = (currentMillis / 1000) % 60;
  unsigned long milliseconds = currentMillis % 1000;
  ets_printf("%02lu:%02lu:%02lu.%03lu : ", hours, minutes, seconds, milliseconds);
}

// Fonction de gestion de l'interruption de l'enfoncement du bouton
void IRAM_ATTR boutonInterrupt() {
  printCurrentTime();

  compteurBoutonInterrupt++;
	digitalWrite(relais1, HIGH); // Activer le relais
  String message = "Nombre de déclenchements de boutonInterrupt : " + String(compteurBoutonInterrupt) + "\n";
  ets_printf(message.c_str());
}

// Fonction de gestion de l'interruption du relais (passage de OFF à ON)
void IRAM_ATTR relais1Interrupt() {
  printCurrentTime();

  compteurRelais1Interrupt++;
	digitalWrite(LedRed, HIGH); // Allumer la LED
	timerAlarmWrite(timerRelais1, tempoDuration * 1000, false);
	timerAlarmEnable(timerRelais1); // Activer le temporisateur
  String message = "Nombre de déclenchements de relais1Interrupt : " + String(compteurRelais1Interrupt) + "\n";
  ets_printf(message.c_str());
}

// Fonction de gestion de l'interruption de temporisation
 void IRAM_ATTR stopTempo() {
  printCurrentTime();

  compteurstopTempo++;
  digitalWrite(relais1, LOW); // Désactiver le relais
  digitalWrite(LedRed, LOW); // Eteindre la Led
  String message = "Nombre de déclenchements de stopTempo : " + String(compteurstopTempo) + "\n";
  ets_printf(message.c_str());
}


void setup() {
  Serial.begin(115200);
  pinMode(bouton, INPUT_PULLUP);
  pinMode(relais1, OUTPUT);
  pinMode(LedRed, OUTPUT);
  digitalWrite(relais1, LOW);
    
  attachInterrupt(digitalPinToInterrupt(bouton), boutonInterrupt, RISING);
  attachInterrupt(digitalPinToInterrupt(relais1), relais1Interrupt, RISING);
  timerRelais1 = timerBegin(0, 80, true);
  timerAttachInterrupt(timerRelais1, &stopTempo, true);
}

void loop() {

}

Ce code fonctionne très bien mais une seule fois après reboot de l'ESP32.
Si j'appuie une fois sur le bouton, le relais et la Led sont activés puis désactivés après la temporisation (de 8 secondes ici).
Si j'appuis une deuxième fois, le relais et la LED ne sont plus activés car la fonction d'interruption "stopTempo" est immédiatement activée après l'activation du relais.

Sortie du moniteur série :

00:00:01.290 : Nombre de déclenchements de boutonInterrupt : 1
00:00:01.290 : Nombre de déclenchements de relais1Interrupt : 1
00:00:08.045 : Nombre de déclenchements de stopTempo : 1
00:00:10.454 : Nombre de déclenchements de boutonInterrupt : 2
00:00:10.454 : Nombre de déclenchements de relais1Interrupt : 2
00:00:10.455 : Nombre de déclenchements de stopTempo : 2

On voit ci-dessus que lors du 2ème appuie, l'arrêt de la tempo est immédiat contrairement au 1er appuie.

J'ai retourné le problème dans tous les sens et je ne comprends pas.
Merci pour votre aide.

Cdt,

La première question à se poser ici est : "as-tu vraiment besoin d'interruptions ?"
Une machine à états pourrait peut-être faire le job.

Ensuite, si tu veux vraiment utiliser les interruptions, il faut réduire le contenu des fonctions d'interruption au strict minimum : par exemple changer une variable booléenne :

void IRAM_ATTR fonction_ISR() {
  flag = !flag;
}

avec flag qui est une variable booléenne globale.
C'est ensuite dans la loop (ou dans une fonction appelée par la loop) que tu vas traiter les conséquences du changement de valeur du flag.

Bonjour,

Merci pour ta réponse rapide.
A la question : "as-tu vraiment besoin d'interruptions ?" : assurément non, je vais d'ailleurs être contraint de faire autrement, ma problématique n'est pas complexe. Je suis parti naturellement sur des interruptions pour approfondir sur ce sujet et mon projet est devenu un exercice mais j'y ai déjà passé beaucoup de temps et à ce rythme là j'y suis encore dans 5 ans ;-).
Bref, ma logique me semblait implacable, j'aurai aimé comprendre pourquoi ça ne fonctionne qu'une seule fois. Peut-être un jour je comprendrais mais là il faut que j'avance :-).
Encore merci pour ta réponse.
Cdt,

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.