Interruption pour sortir de la machine à états

Bonjour,
Alors je vous avoue avoir chercher mais je ne trouve franchement pas la réponse ou alors je ne comprends rien aux interruptions.

Je suis sur Mega2560 et avant j'ai testé mes pins d'interruptions grâce à un topic du forum.
Donc ma pin 21 correspond bien.

Mon soucis est le suivant, lorsque mon interrupteur (sur pin 21 nommé securite) passe en LOW
Mon programme blocage ne se lance pas.
Je ne sais pas si c'est le fait d’être dans void programme qui m'empeche cela j'avais compris que l'interruption fonctionne dans tout les cas.

Voici le code (brouillon)

#include "LiquidCrystal.h"
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int entree_menus = 49;
int commande_monter = 50;
int commande_retour = 51;
const int securite = 21;
int contact_moteur = 22;
enum : byte {
  BUTTON_NONE, 
  BUTTON_UP,    
  BUTTON_DOWN,  
  BUTTON_LEFT,  
  BUTTON_RIGHT, 
  BUTTON_SELECT,
  PROGRAMME_EN_ATTENTE,
  PROGRAMME_MONTEE,
  PROGRAMME_ARRET_MONTEE,
  PROGRAMME_SECURITE,
  PROGRAMME_RETOUR_AUTO
}
etat = PROGRAMME_EN_ATTENTE;

void setup() {
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.write("Digital Dock");
  delay (1000);
  lcd.setCursor(0, 1);
  lcd.write("v1.11");
  delay(5000);
  pinMode(commande_monter, INPUT);
  pinMode(commande_retour, INPUT);
  pinMode(securite, INPUT);
  attachInterrupt(digitalPinToInterrupt(securite), blocage, LOW);
  pinMode(contact_moteur, OUTPUT);
  lcd.clear();
 
}

void loop()
{ 
programme();
}

void blocage() 
{
  lcd.setCursor(0, 0);
  lcd.print("SECURITES       ");
  lcd.setCursor(0, 1);
  lcd.print("P1              ");
  digitalWrite(contact_moteur,LOW);
}

/*---------LECTURE--DES--BOUTONS--DU--KEYPAD------------*/
/*byte getPressedButton() {
int value = analogRead(A0);
  if (value < 50)
    return BUTTON_RIGHT;
  else if (value < 250)
    return BUTTON_UP;
  else if (value < 410)
    return BUTTON_DOWN;
  else if (value < 550)
    return BUTTON_LEFT;
  else if (value < 850)
    return BUTTON_SELECT;
  else
    return BUTTON_NONE;
}*/

void programme()
{
  static unsigned long lancement_retour;
  int tempo_retour_automatique;
  tempo_retour_automatique = 8000ul;

switch (etat) {
    case PROGRAMME_EN_ATTENTE:
      if ((digitalRead(securite) == HIGH)&&(digitalRead(commande_monter) == HIGH)) {
        lcd.setCursor(0, 0);
        lcd.print("MONTER          ");
        lcd.setCursor(0, 1);
        lcd.print("                ");
        digitalWrite(contact_moteur,HIGH);
        etat = PROGRAMME_MONTEE;
      }
      if (digitalRead(securite) == LOW){
        lcd.setCursor(0, 0);
        lcd.print("SECURITES       ");
        lcd.setCursor(0, 1);
        lcd.print("P1              ");
        digitalWrite(contact_moteur,LOW);
        etat = PROGRAMME_SECURITE;
      }
      if ((digitalRead(securite) == HIGH)&&(digitalRead(commande_retour) == HIGH)){
        lcd.setCursor(0, 0);
        lcd.print("RETOUR          ");
        lcd.setCursor(0, 1);
        lcd.print("AUTOMATIQUE     ");
        digitalWrite(contact_moteur,HIGH);
        lancement_retour = millis();
        etat = PROGRAMME_RETOUR_AUTO;
      }      
      break;
      
    case PROGRAMME_MONTEE:
      if ((digitalRead(securite) == HIGH)&&(digitalRead(commande_monter) == HIGH)){
        digitalWrite(contact_moteur,HIGH);
        etat = PROGRAMME_ARRET_MONTEE;
      }
      break;
      
    case PROGRAMME_ARRET_MONTEE:
      if ((digitalRead(securite) == HIGH)&&(digitalRead(commande_monter) == LOW)) {
        lcd.clear();
        digitalWrite(contact_moteur,LOW);
        etat = PROGRAMME_EN_ATTENTE;
      }
      break;

    case PROGRAMME_SECURITE:
      if (digitalRead(securite) == HIGH) {
        lcd.clear();
        etat = PROGRAMME_EN_ATTENTE;
      }
      break; 
       
    case PROGRAMME_RETOUR_AUTO:
      if (digitalRead(commande_retour) == HIGH) {
        digitalWrite(contact_moteur,HIGH);
        etat = PROGRAMME_EN_ATTENTE;
      }
      if (digitalRead(securite) == LOW){
        lcd.setCursor(0, 0);
        lcd.print("SECURITES       ");
        lcd.setCursor(0, 1);
        lcd.print("P1              ");
        digitalWrite(contact_moteur,LOW);
        etat = PROGRAMME_SECURITE;
      }
      else {
        if (millis() - lancement_retour >= tempo_retour_automatique) {
          digitalWrite(contact_moteur,LOW);
          lcd.clear();
          etat = PROGRAMME_EN_ATTENTE;
        }
      }
       break; 
}
}

tu devrais limiter ta routine d'interruption à modifier une variable (passer de 0 à 1 par ex.)
Cette variable, qui doit être déclarée volatile,

volatile int temoin_interruption = 0;

est testée dans la boucle principale du programme. Si le programme la voit mise à 1, il fait ce qu'il a à faire (blocage), puis il remet cette variable à zéro.

Mais attention : avec cette technique, le programme termine la tâche encours avant de s'apercevoir qu'il y a eu une interruption. A voir si c'est critique ou pas.

Comment le voit tu? Que se passe-t-il? D'après ce que je vois si si il se lance, il affiche SECURITE P1, mais qui peut être détruit immédiatement par le programme principal qui lui aussi fait des affichages.
C'est les affichages qui sont longs. Si on est interrompu pendant qu'il exécute

if ((digitalRead(securite) == HIGH)&&(digitalRead(commande_monter) == HIGH)) {
        lcd.setCursor(0, 0);
        lcd.print("MONTER          ");
        lcd.setCursor(0, 1);
        lcd.print("                ");
        digitalWrite(contact_moteur,HIGH);
        etat = PROGRAMME_MONTEE;
      }

il y a de forte chances que ce soit pendant l'affichage et le digitalWrite(contact_moteur,LOW); de l'interruption sera suivi du digitalWrite(contact_moteur,HIGH); de loop. Du coup cette sortie ne va pas être bas en cas d'interruption.

En tout cas avoir un programme principal et un programme d'interruption qui positionne tous deux le curseur va faire des erreurs. Dans la portion de code ci dessus quand le programme principal positionne le curseur, il se peut que le programme soit interrompu et que le curseur soit déplacé. On peut difficilement avoir le programme principal et l'interruption agir sur la même variable (ici la position du curseur).

A voir aussi si l'affichage sur le LCD utilise ou pas les interruptions, par exemple si il utilise le bus SPI...

Une autre solution qui peut être utilisée dans ton cas est d'interdire les interruptions pendant les phases d'écriture du programme principal, c'est à dire pendant chaque morceau du type

if ((digitalRead(securite) == HIGH)&&(digitalRead(commande_monter) == HIGH)) {
        lcd.setCursor(0, 0);
        lcd.print("MONTER          ");
        lcd.setCursor(0, 1);
        lcd.print("                ");
        digitalWrite(contact_moteur,HIGH);
        etat = PROGRAMME_MONTEE;
      }

Ainsi, deux affichages différents et deux mises à jour de la même variable (contact_moteur doit effectivement être volatile) ne pourrait se faire en même temps. A condition bien sûr que le LCD n'utilise pas les interruptions!

De toutes façon si le LCD utilise les interruption, pendant l'interruption, on ne doit pas utiliser le LCD car en entrant dans une interruption (securite), on désactive toutes les interruptions (LCD). On peut faire autrement, mais c'est plus compliqué.

On est d'accord, il faut limiter ce qui est fait sous interruption au strict minimum.
Une fonction() qui peut être appelée sans risques sous interruption, pendant même qu'elle est en cours d'exécution dans le programme principal, s'appelle une fonction ré-entrante.
Rien ne dit que les appels au LCD ou à Serial le soient.

La machine à état est un code qui ne fonctionne pas avec interruption. Pour passer d'un état à l'autre, on a une condition. L'ai l'impressions que pout "sortir" de la machine à état, il vaudrait mieux employer "interruption pour changer d'état dans une machine à état".
Dans ce cas, la seule chose que l'inter doit faire est:
etat = PROGRAMME_SECURITE;
(etet étant volatile) et c'est la machine à état qui doit gérer le reste.

Bonjour merci pour vos retours je vais essayer en restant dans la machine à état.

un système de sécurité qui raconte sa vie avant d'agir.
Il y a du souci à se faire.....

1 Like

en complément,

il ya t'il une résistance de pullup sur cette entrée?

Concernant la sécurité aucun soucis comme indiqué c'est un arrêt d'urgence, donc il coupe le 24v de mon contacteur mécaniquement.

Pour la résistance le montage est pull down.

Cordialement

ce que veut dire fdufnews, c'est que si il y a urgence, on commence par agir (digitalWrite), et ensuite on avertit. Juste pour faire propre.

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