Variable problem with switch case

Hello.

I am currently in an internship and I am working on a project for an opening and closing system for a henhouse. I have to program a guillotine type door, which opens and closes according to the direction of rotation of the motor driven by relays, in automatic mode.

HIGH and LOW sensors are integrated to designate the door open and close limits, which have normally open contacts. These contacts close when they detect a magnet hanging on the door, allowing the motor to be stopped 1 second after the contacts close and to stop the door.

I managed to program the manual mode of the door with the help of a RIGHT button included in the LCD display which also shows data on the screen. In this manual mode, by pressing the button:
-the door closes until the DOWN sensor (+1 second)

  • she pauses for 3 seconds
    -the door opens up to the UP sensor (+1 second)
    -end of the manual door test.

Now I'm looking to have the door open and close automatically depending on the time of day. I am using a solar cell to sense ambient light and convert it to voltage.

Here I would like to program a threshold of 1V to determine if it is day or night.

I also added Boolean variables to denote the state of the door (closed, not closed, open, not open), and I use the millis () function for timers, and state machines for my programs.

This is what I did:

//moteur + relais + LCD + cellule + capteurs

// LCD Keypad Shield

// Modif 15

#include <LiquidCrystal.h>

// Création de l'objet lcd (avec les différents ports numériques qu'il utilise)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//variables
int lcd_key     = 0;
int adc_key_in  = 0;
int TensionBAS  = 0;
int TensionHAUT  = 0;
float TensionCelluleSolaire = 0;
float TensionMoteur = 0;

//constantes
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5


#define RelayPin1 2 //le port numérique D2 est connecté au relais 1
#define RelayPin2 3 //le port numérique D3 est connecté au relais 2
#define CapteurBAS 11 //le port numérique D11 est connecté au capteur BAS
#define CapteurHAUT 12 //le port numérique D12 est connecté au capteur HAUT

#define debugTxtVar(myParameterText, variableName) \
  Serial.print(#myParameterText " = "); \
  Serial.println(variableName);

#define debugTxtVar2(myParameterText1, variableName1, myParameterText2, variableName2) \
  Serial.print(#myParameterText1 " = "); \
  Serial.print(variableName1); \
  Serial.print(" " #myParameterText2 " = "); \
  Serial.println(variableName2);

int Etat_fonctionnement_manuel = 0;
int Etat_fermeture_auto = 0;
int Etat_ouverture_auto = 0;

unsigned long temps_fonctionnement_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;
unsigned long temps_mesures = 0;
unsigned long temps_serie = 0;
unsigned long temps_actuel;

boolean JourVrai;   // indique si c'est le jour ou la nuit
boolean PorteOuverte = false; // indique si la porte est en position ouverte ou non
boolean PorteFermee = false; // indique si la porte est en position fermee ou non
boolean Test_manuel_demarrage = false; //indique si le test manuel de la porte est en cours ou non
boolean AUTO_Fermeture = false; //indique si la fermeture automatique de la porte est en cours ou non
boolean AUTO_Ouverture = false; //indique si l'ouverture automatique test manuel de la porte est en cours ou non

void setup()
{
  // On met les pin de chaque relais en sortie
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);

  // On met les pin de chaque capteur en entrée
  pinMode(CapteurBAS, INPUT);
  pinMode(CapteurHAUT, INPUT);

  Serial.begin(9600);// ouvre le port série et fixe le debit de communication à 9600 bauds

  lcd.begin(16, 2);              // Démarrage de l'écran
  lcd.setCursor(0, 0);           // Positionnement du curseur au début
  lcd.print("Test porte"); // Message

}

void loop()
{ 
  // Sous traite les différentes tâches
  lcd_key = read_LCD_buttons();  // Lecture des touches
  task_mesure_tensions();
  task_fonctionnement_manuel();
  task_fermeture_auto();

  switch (lcd_key)               // Action en cas de touche pressée
  {
    case btnRIGHT: //en appuyant sur le bouton RIGHT
      {
        if (Etat_fonctionnement_manuel == 0 && PorteOuverte) {
          Etat_fonctionnement_manuel = 1; //on affecte la variable à 1
          Test_manuel_demarrage = true;
        }
        break;
      }
  }

  if ( digitalRead(CapteurBAS) == LOW  )//lorsque le contact du capteur BAS est fermé...
      {
        PorteFermee = true; //la porte est en position fermée
      }
      
  else 
       {
        PorteFermee = false; //la porte n'est pas en position fermée
       }

  if ( digitalRead(CapteurHAUT) == LOW  )//lorsque le contact du capteur HAUT est fermé...
      {
        PorteOuverte = true; //la porte est en position ouverte
      }

  else
      {
        PorteOuverte = false; //la porte n'est pas en position ouverte
      }

  if (TensionCelluleSolaire < 1.0 )
    { // une tension basse signifie qu'il commence à faire sombre
      JourVrai = false; //la variable passe à false lorsqu'il fait nuit
    }

  else 
      //{ // une tension haute signifie que le soleil se lève
      JourVrai = true;  //la variable passe à true lorsqu'il fait jour      
    //}

  if (!JourVrai && !PorteFermee) // s'il fait nuit mais la porte n'est pas en position fermée...
      {
        Etat_fermeture_auto = 1; //on affecte la variable à 1
        Etat_ouverture_auto = 0; //on affecte la variable à 0
      }

  if (!JourVrai && PorteFermee) // s'il fait nuit et la porte est en position fermée...
      {
        Etat_fermeture_auto = 0; //on affecte la variable à 0
        Etat_ouverture_auto = 0; //on affecte la variable à 0
      }

  if (JourVrai && !PorteOuverte) // s'il fait jour mais la porte n'est pas en position ouverte...
      {
        Etat_ouverture_auto = 1; //on affecte la variable à 1
        Etat_fermeture_auto = 0; //on affecte la variable à 0
      }

  if (JourVrai && PorteOuverte) // s'il fait jour et la porte est en position ouverte...
      {
        Etat_ouverture_auto = 0; //on affecte la variable à 0
        Etat_fermeture_auto = 0; //on affecte la variable à 0
      }

  temps_actuel = millis(); //fonction non bloquante qui indique le temps passé en millisecondes

  if ( (temps_actuel - temps_serie) >= 1000ul )//la boucle se réinitialise à chaque seconde
  {
    temps_serie = temps_actuel;

    //affiche les différentes données sur le moniteur série

    debugTxtVar2(TensionCelluleSolaire , TensionCelluleSolaire, TensionMoteur , TensionMoteur);

    debugTxtVar(JourVrai , JourVrai);

    debugTxtVar2(Etat_fonctionnement_manuel , Etat_fonctionnement_manuel, Test_manuel_demarrage , Test_manuel_demarrage);

    debugTxtVar2(AUTO_Fermeture , AUTO_Fermeture, Etat_fermeture_auto , Etat_fermeture_auto);

    debugTxtVar2(AUTO_Ouverture , AUTO_Ouverture, Etat_ouverture_auto , Etat_ouverture_auto);

    debugTxtVar2(PorteOuverte , PorteOuverte, PorteFermee , PorteFermee);

    debugTxtVar(temps_actuel , temps_actuel);
  }
}//loop

void task_mesure_tensions()//permet de prendre des mesures de tensions et d'afficher des données sur l'écran LCD
{
  temps_actuel = millis();//fonction non bloquante qui indique le temps passé en millisecondes

  if ( (temps_actuel - temps_mesures) >= 250ul ) //la boucle se réinitialise toutes les 250 ms
  {
    temps_mesures = temps_actuel;

    // Transforme la mesure (nombre entier) en tension via un produit en croix
    int CelluleSolaireCAN = analogRead(A1); // Mesure la tension aux bornes de la cellule solaire
    int MoteurCAN = analogRead(A2); // Mesure la tension consommée par le moteur

    float TensionV1 = (float)CelluleSolaireCAN * (5.0 / 1023.0);
    float TensionV2 = (float)MoteurCAN * (5.0 / 1023.0);

    lcd.setCursor(0, 1);           // Positionnement du curseur début de ligne

    //affiche les différentes données sur l'écran LCD

    if (JourVrai)
    {
      lcd.print("jour"); //affiche "jour"
    }
    else if (!JourVrai)
    {
      lcd.print("nuit"); //affiche "nuit"
    }

    lcd.print(" M");
    lcd.print(Etat_fonctionnement_manuel); //affiche la valeur de la variable

    lcd.print(" F");
    lcd.print(Etat_fermeture_auto); //affiche la valeur de la variable

    lcd.print(" O");
    lcd.print(Etat_ouverture_auto); //affiche la valeur de la variable

    TensionCelluleSolaire = TensionV1;

    TensionMoteur = TensionV2;

  }//if

}//task_mesure_tensions

void FermerMoteur() {//fait tourner le moteur dans un sens pour fermer la porte
  digitalWrite(RelayPin1, LOW); //le relais 1 est actif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
}

void ArretMoteur() {//met le moteur en pause et stoppe la porte
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
}

void OuvrirMoteur() {//fait tourner le moteur dans l'autre sens pour ouvrir la porte
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, LOW); //le relais 2 est actif
}

void task_fonctionnement_manuel()//permet d'activer le test de fonctionnement manuel de la porte
{
  temps_actuel = millis();//fonction non bloquante qui indique le temps passé en millisecondes

  switch ( Etat_fonctionnement_manuel )
  {
    case    1:
      // Après l'appui du bouton, le moteur tourne dans un sens et la porte commence à se fermer...
      FermerMoteur();
      temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
      Etat_fonctionnement_manuel++;// on incrémente la variable de 1

      break;

    case    2:
      if (PorteFermee) //lorsqu'on détecte la porte en position fermée...
      {
        //on lance une temporisation d'une seconde pour être sûr qu'elle soit bien fermée
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        Etat_fonctionnement_manuel++;// on incrémente la variable de 1

      }//if

      break;

    case    3:
      if ((temps_actuel - temps_fonctionnement_manuel) >= 1000ul) //une fois la temporisation achevée...
      {
        //...le moteur se met en pause et la porte s'arrête
        ArretMoteur();
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        Etat_fonctionnement_manuel++;// on incrémente la variable de 1

      }//if

      break;

    case    4:
      if ( (temps_actuel - temps_fonctionnement_manuel) >= 3000ul )
      {
        // une fois les 3 secondes de pause passées, on ouvre la porte
        OuvrirMoteur();
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        Etat_fonctionnement_manuel++;// on incrémente la variable de 1

      }//if

      break;

    case    5:
      if (PorteOuverte) //lorsqu'on détecte la porte en position ouverte...
      {
        //on lance une temporisation d'une seconde pour être sûr qu'elle soit bien ouverte
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        Etat_fonctionnement_manuel++;// on incrémente la variable de 1

      }//if

      break;

    case    6:
      if ( (temps_actuel - temps_fonctionnement_manuel) >= 1000ul )//une fois la temporisation achevée...
      {
        //...le moteur se met en pause et la porte s'arrête
        ArretMoteur();
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        Etat_fonctionnement_manuel = 0;//on affecte la variable à 0
        Test_manuel_demarrage = false; //le test manuel de la porte est terminé

      }//if

      break;  

  }//switch

}//task_fonctionnement_manuel

void task_fermeture_auto//permet de fermer la porte automatiquement
()//permet d'activer le test de fonctionnement manuel de la porte
{
  temps_actuel = millis();//fonction non bloquante qui indique le temps passé en millisecondes

  switch ( Etat_fermeture_auto)
  {
    case    1:
    if ( (temps_actuel - temps_fermeture_auto) >= 10000ul )
    {
      // Au bout de 10 secondes...
      temps_fermeture_auto = temps_actuel;//on réinitialise le temps passé à 0 ms
      Etat_fermeture_auto++;// on incrémente la variable de 1
    }
      break;

    case    2:     
        //on ferme la porte indéfiniment
        FermerMoteur();
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
      break;

  }//switch

}//task_fermeture_auto

// Fonction de lecture des touches
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);   // Lecture du port analogique

  // Les valeurs qui suivent doivent être adaptées au shield
  if (adc_key_in > 1000) return btnNONE;   // En principe 1023 quand aucune touche n'est pressée
  if (adc_key_in < 50)   return btnRIGHT;     // 0
  if (adc_key_in < 195)  return btnUP;        // 99
  if (adc_key_in < 380)  return btnDOWN;      // 255
  if (adc_key_in < 555)  return btnLEFT;      // 409
  if (adc_key_in < 790)  return btnSELECT;    // 640

  return btnNONE;
}

For now, I am trying to perform an automatic closing test, where if it is dark but the door is not completely closed, it starts a 10 second time delay where, once elapsed, allows you to do close the door.

I also use the serial monitor to display my data:

image

As expected, the Etat_fermeture_auto variable changes to 1 when it is dark but the door is not yet closed.

image

However, after 10 seconds the variable remains at 1 instead of being assigned to 2 to close the door.

I use a switch case for this function of my program, but also for the task_fonctonnement_manuel function for the manual test of the door, where Etat_fonctionnement_manuel goes to 1 when the button is pressed, which closes the door.

How come ?

Did I make a mistake somewhere? Is it related to the 10 second timeout?

I need help please

Have you checked for any bouncing in your end stops?

What do you mean ?

When you hit your CapteurBAS, digitalRead(CapteurBAS) might go quickly to HIGH and LOW for a short while before becoming stable

That’s called bouncing due to mechanical construct of the switch.

I don't think so ... The manual run program works fine with the sensors, so I don't think it comes from there ...

Do you think my program is badly written somewhere?

it's hard for me to follow this code. one reason is the french variable names, but also because there are so many if statements

i believe i see the if statements for the lower and upper sensors

if ( digitalRead(CapteurBAS) == LOW  )

why have separate tests which set a boolean true/false? regardless of whether it is the upper or lower sensor, wouldn't it make sense just to turn any motor off. the presumably existing variable indicating either the direction of the motor or whether to move the door up/down can be used to indicate at least the desired position assuming it gets there and the mechanism didn't jam (may need to wait for the door sensor at the starting position to clear)

it looks like there is more than just code to recognize day/night time and control the motor. it would make sense (to me) that that code can be in a function invoked by loop() to monitor for day/night time as well as stop the door

and if there's a separate function for doing that stuff, there can be functions for other sub-functions of you code so that loop() is simply a small number of function calls.

breaking the code up into sub-function units would improve readability, maintainability and testability.

i hope you understand what i'm trying to say.

I speak French but I agree, too many states that makes code confusing.

also

  // On met les pin de chaque capteur en entrée
  pinMode(CapteurBAS, INPUT);
  pinMode(CapteurHAUT, INPUT);

==> do you have external pull-up or pull-down?

the door state should be 1 variable only that can be in 5 states CLOSED, OPEN, AJAR, CLOSING, OPENING

the motor state can be deduced from the door state (closing = moving down, opening = moving up otherwise it's at rest)

I don't get why you have some waiting time - for example when the door is fully closed, why would you keep the motor running for another 1s ?

your state machine should just test the possible transitions depending on the door status and trigger the right actions and state changes (as you speak French, check out my tutorial)

this part could be better written with an if

  switch (lcd_key)               // Action en cas de touche pressée
  {
    case btnRIGHT: //en appuyant sur le bouton RIGHT
      {
        if (Etat_fonctionnement_manuel == 0 && PorteOuverte) {
          Etat_fonctionnement_manuel = 1; //on affecte la variable à 1
          Test_manuel_demarrage = true;
        }
        break;
      }
  }

-->

if (lcd_key == btnRIGHT)  {            //en appuyant sur le bouton RIGHT
  if (Etat_fonctionnement_manuel == 0 && PorteOuverte) {
    Etat_fonctionnement_manuel = 1; //on affecte la variable à 1
    Test_manuel_demarrage = true;
  }
}

When is a door not a door? When it's a jar.

That totally does not translate into French.

Srsly, though, what is the meaning of the state AJAR?

a7

The door is stuck in the middle and motor is off. (power outage or whatever and you restart the system, the door is ajar)
(Got the joke, indeed it does not translate)

THX, I see.

I threw the whole thing at google translate, just to see what happens.

One gets a surprisingly good translation! It won't compile for a variety of reasons. A few:

Some variables went bad

  pinMode (Sensor UP, INPUT);

and the translation of "case" into "box" gives the switch statements a new look

void manual_function () // allows to activate the manual function test of the door
{
  actual_time = millis (); // non-blocking function which indicates the time spent in milliseconds

  switch (manual_operation_status)
  {
    box 1:
      // After pressing the button, the motor turns in one direction and the door starts to close ...
      CloseMotor ();
      manual_time_time = current_time; // we reset the time spent to 0 ms
      Manual_state ++; // we increment the variable by 1

      break;

    box 2:
      if (DoorClosed) // when the door is detected in the closed position ...
      {
        // we start a one second delay to be sure that it is properly closed
        manual_time_time = current_time; // we reset the time spent to 0 ms
        Manual_state ++; // we increment the variable by 1

      } // if

      break;
…

I have no idea upon what samples this was based, I was very happy to see a distinct accommodation for the code mixed with prose.

a7

here is a version that does what the TO wants

//moteur + relais + LCD + cellule + capteurs

// LCD Keypad Shield
#include <LiquidCrystal.h>

// Création de l'objet lcd (avec les différents ports numériques qu'il utilise)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define debugTxtVar(myParameterText, variableName) \
        Serial.print(#myParameterText " " #variableName"="); \
        Serial.println(variableName); 

//variables
int lcd_key     = 0;
int adc_key_in  = 0;
int TensionBAS  = 0;
int TensionHAUT = 0;

//constantes
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

#define RelayPin1 2 //le port numérique D2 est connecté au relais 1
#define RelayPin2 3 //le port numérique D3 est connecté au relais 2
#define CapteurBAS 11 //le port numérique D11 est connecté au capteur BAS
#define CapteurHAUT 12 //le port numérique D12 est connecté au capteur HAUT

int state_relais_manuel = 0;
int state_fermeture_auto = 0;
int state_ouverture_auto = 0;
int state_seuil_ensoleillement;

unsigned long temps_mesures = 0;
unsigned long temps_relais_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;

unsigned long temps_actuel;
unsigned long temps_fermeture_start;


boolean itIsDay;   // c_est_le_jour;
boolean manualTestStarted = false;

const byte manuel_stateMachineIdle0 = 0;
const byte manuel_startClosingDoor1 = 1;
const byte manuel_waitForSensorDownClosed2 = 2;
const byte manuel_openDoorAfterWaiting3 = 3;
const byte manuel_waitForSensorDoorUp4 = 4;
const byte manuel_waitAndStopStateMachine5 = 5;

const byte autoclose_Start = 10;
const byte autoclose_waitSomeTime1 = 1;
const byte autoclose_wait_SensorDownclosed2 = 2;
const byte autoclose_wait_someTime3 = 3;
const byte autoclose_idle0 = 0;

const byte autoOpenStart = 10;
const byte autoOpen_waitSomeTime1 = 1;
const byte autoOpen_wait_SensorOpened2 = 2;
const byte autoOpen_wait_someTime3 = 3;
const byte autoOpen_idle0 = 0;


// Fonction de lecture des touches
int read_LCD_buttons() { //permet de contrôler les boutons de l'afficheur LCD

  adc_key_in = analogRead(0);   // Lecture du port analogique

  // Les valeurs qui suivent doivent être adaptées au shield
  if (adc_key_in > 1000) return btnNONE;   // En principe 1023 quand aucune touche n'est pressée
  if (adc_key_in < 50)   return btnRIGHT;     // 0
  if (adc_key_in < 195)  return btnUP;        // 99
  if (adc_key_in < 380)  return btnDOWN;      // 255
  if (adc_key_in < 555)  return btnLEFT;      // 409
  if (adc_key_in < 790)  return btnSELECT;    // 640

  return btnNONE;
}

void setup() {
  Serial.begin(115200);
  Serial.println("setup-Start");
  // On met les pin de chaque relais en sortie
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);

  pinMode(CapteurBAS, INPUT);
  pinMode(CapteurHAUT, INPUT);

  lcd.begin(16, 2);            // Démarrage de l'écran
  lcd.setCursor(0, 0);         // Positionnement du curseur au début
  lcd.print("Mesure tension"); // Message
}

void printToLCD() {

 // lcd.print("L");

  if (itIsDay) 
  {
    lcd.print("jour"); //affiche la valeur de l'état de la cellule solaire
  }
  else if (!itIsDay) 
  {
    lcd.print("nuit"); //affiche la valeur de l'état de la cellule solaire
  }

  lcd.print(" F");
  lcd.print(state_fermeture_auto); //affiche la valeur de l'état de la fermeture automatique

  lcd.print(" O");
  lcd.print(state_ouverture_auto); //affiche la valeur de l'état de l'ouverture automatique

  lcd.print(" M");
  lcd.print(state_relais_manuel); //affiche la valeur de l'état du mode manuel de la porte

} // printToLCD

void task_mesure_tensions() { //permet de prendre des mesures de tensions et d'afficher des données sur l'écran LCD
  // Transforme la mesure (nombre entier) en tension via un produit en croix
  int solarCellADC = analogRead(A1); // Mesure la tension aux bornes de la cellule solaire
  int motorADC     = analogRead(A2); // Mesure la tension consommée par le moteur

  float solarCellVoltage = (float)solarCellADC * (5.0 / 1023.0);
  
  debugTxtVar("1 " ,solarCellVoltage);
  float motorVoltage     = (float)motorADC     * (5.0 / 1023.0);

  // Affiche la mesure de la tension sur l'écran LCD et attends 250 ms
  lcd.setCursor(0, 1);           // Positionnement du curseur début de ligne

  if (solarCellVoltage < 1.0) 
  { // une tension basse signifie qu'il commence à faire sombre
    if (itIsDay) { // s'il s'asit d'un changement d'état jour-nuit
      itIsDay = false; //la variable passe à false lorsqu'il fait nuit
      // démarrer la machine à état pour fermer automatiquement la porte
      state_fermeture_auto = autoclose_Start; 
    }
  }
  
  else if (solarCellVoltage >= 1.0)
  { // une tension haute signifie que le soleil se lève
      if (!itIsDay) { // s'il s'asit d'un changement d'état nuit-jour
        itIsDay = true;  //la variable passe à true lorsqu'il fait jour
        // démarrer la machine à état pour ouvrir automatiquement la porte
        state_ouverture_auto = autoOpenStart;
      }
  }  
}

void RunMotorClosing() {
  digitalWrite(RelayPin1, LOW); //le relais 1 est actif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
  Serial.println("RunMotorClosing()");
}

void MotorStop() {
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
  Serial.println("RunMotorStop()");
}

void RunMotorOpening() {
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, LOW); //le relais 2 est actif
  Serial.println("RunMotorOpening()");
}


void task_relais_manuel() { //permet d'activer le test de fonctionnement manuel de la porte
  // if values of a variable shall be re-used the variable must be defined GLOBAL
  temps_actuel = millis();
  debugTxtVar("task_relais_manuel " ,state_relais_manuel);

  switch ( state_relais_manuel )
  {
    case manuel_startClosingDoor1 :
      // Après l'appui du bouton, le moteur tourne dans un sens et la porte commence à se fermer...
      RunMotorClosing();
      temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
      state_relais_manuel = manuel_waitForSensorDownClosed2; // the names already explain what happends
      break;

    case manuel_waitForSensorDownClosed2 :
      if ( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
      { //...le moteur se met en pause et la porte s'arrête pendant 3 secondes...
        MotorStop();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_openDoorAfterWaiting3; // the names already explain what happends
      }
      break;

    case manuel_openDoorAfterWaiting3 :
      if ( (temps_actuel - temps_relais_manuel) >= 3000ul )
      { //une fois la pause finie, le moteur tourne dans l'autre sens et la porte commence à s'ouvrir...
        RunMotorOpening();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_waitForSensorDoorUp4; // the names already explain what happends
      }
      break;

    case manuel_waitForSensorDoorUp4 :
      if ( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
      { // ...le moteur se met en pause et la porte s'arrête pendant 3 secondes
        MotorStop();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_waitAndStopStateMachine5; // the names already explain what happends
      }
      break;

    case manuel_waitAndStopStateMachine5 :
      if ( (temps_actuel - temps_relais_manuel) >= 3000ul )
      { //reviens à l'état initial après 3 secondes de pause
        state_relais_manuel = manuel_stateMachineIdle0; // the names already explain what happends
      }
      break;

    case manuel_stateMachineIdle0 :
      manualTestStarted = false; // manual cycle finished reset variable to false
      break;
  }//switch

}//task_relais_manuel



void task_fermeture_auto() { //permet d'activer la fermeture automatique de la porte avec le seuil de luminosité
  // if values of a variable shall be re-used the variable must be defined GLOBAL
  temps_actuel = millis();
  
  debugTxtVar("task_fermeture_auto " ,state_fermeture_auto);

  switch ( state_fermeture_auto )
  {
    case autoclose_Start :
      // just store snapshot of time then go on with next state
      temps_fermeture_start = temps_actuel;
      state_fermeture_auto = autoclose_waitSomeTime1;
      break;
      
    case autoclose_waitSomeTime1 :
      // standard use of non-blocking timing with millis is:
      // calculate difference between actual time and a snapshot of time that marks the begin of a waiting-time
      // if difference becomes                 BIGGER than the waiting-time the if-condition becomes true
      if ( (temps_actuel - temps_fermeture_start) > 10000)
      { //tant que les 10 secondes ne se soient pas découlées...
        state_fermeture_auto = autoclose_wait_SensorDownclosed2;
      }
      break;

    case autoclose_wait_SensorDownclosed2 :
      RunMotorClosing();
      if ( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
      { // le moteur se met en pause et la porte s'arrête.
        debugTxtVar("10: if ( digitalRead(CapteurBAS) == LOW  is true " ,state_fermeture_auto);
        MotorStop();
        temps_fermeture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
        state_fermeture_auto = autoclose_wait_someTime3; 
      }
      break;

    case autoclose_wait_someTime3 :
      if ( (temps_actuel - temps_fermeture_auto) >= 3000ul )
      { //laisse la porte fermée et remet la variable à l'état initial.
        state_fermeture_auto = autoclose_idle0;
        debugTxtVar("11: if ( (temps_actuel - temps_fermeture_auto) >= 3000ul  is true " ,state_fermeture_auto);
      }
      break;

    case autoclose_idle0:
      // just do nothing
      debugTxtVar("12: autoclose_idle0 " ,state_fermeture_auto);
      break;
  } //switch

} //task_fermeture_auto



void task_ouverture_auto() { //permet d'activer l'ouverture automatique de la porte avec le seuil de luminosité
  // if values of a variable shall be re-used the variable must be defined GLOBAL
  temps_actuel = millis();
  debugTxtVar("task_ouverture_auto" ,state_ouverture_auto);

  switch ( state_ouverture_auto )
  {
    case autoOpenStart :
      temps_fermeture_auto = temps_actuel;
      state_ouverture_auto = autoOpen_waitSomeTime1;
      break;
      
    case autoOpen_waitSomeTime1 :
      //if ( (temps_actuel - temps_fermeture_auto) < 10000ul)
      if ( (temps_actuel - temps_fermeture_auto) > 10000ul)
      { //tant que les 10 secondes ne se soient pas découlées...
        state_ouverture_auto = autoOpen_wait_SensorOpened2;
      }
      break;

    case autoOpen_wait_SensorOpened2 :
      RunMotorOpening();
      if ( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
      { // le moteur se met en pause et la porte s'arrête.
        MotorStop();
        temps_ouverture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
        state_ouverture_auto = autoOpen_wait_someTime3;
      }
      break;

    case autoOpen_wait_someTime3 :
      if ( (temps_actuel - temps_ouverture_auto) >= 3000ul )
      { //laisse la porte ouverte et remet la variable à l'état initial.
        state_ouverture_auto = autoOpen_idle0; //la variable repasse à 0
      }
      break;

    case autoOpen_idle0 :
      // just do nothing
      break;
  } //switch

} //task_ouverture_auto



void loop() {
  delay(1000);
  task_mesure_tensions();
  printToLCD();

  lcd_key = read_LCD_buttons();  // Lecture des touches
  // Sous traite les différentes tâches
  switch (lcd_key)               // Action en cas de touche pressée
  {
    case btnRIGHT: //en appuyant sur le bouton RIGHT
      {
        if (!manualTestStarted) { // if this is a stateCHANGE
          manualTestStarted = true;
          state_relais_manuel = manuel_startClosingDoor1;
        }
        break;
      }
  }

  // running through manual mode or auto-mode should be mutually exclusive
  if (manualTestStarted) {
    task_relais_manuel();
  }

  // running through manual mode or auto-mode should be mutually exclusive
  if (!manualTestStarted) {
    // if lightsensor detects sunrise and doorsensor does not yet report door opened
    if (itIsDay && !digitalRead(CapteurHAUT) ) {
      task_ouverture_auto(); // open door
    }
  
    // if lightsensor detects night and doorsensor does not yet report door closed
    if (!itIsDay && !digitalRead(CapteurBAS) ) {
      task_fermeture_auto(); // close door
    }
  }  
} // end of function loop

best regards Stefan