Problem with a constant variable and the millis function

Hello.

I am currently 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)
-it 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.

However, I have a problem with the detection of day and night via the solar cell.

There is a Boolean variable "JourVrai" which makes it possible to detect whether it is day or night: if the voltage at the terminals of the solar cell is less than 1V, the variable is equal to FALSE and it is NIGHT. If, on the contrary, the voltage is greater than or equal to 1V, it is DAY and the variable is equal to true.

Usually, when I turn my lamp on or off to simulate day or night, my LCD screen displays "Day" or "Night" when appropriate. The problem is that when I feed my program when it is daylight, for a very short time, the LCD screen displays "night" before displaying "day".

However, this minimal detail is very restrictive for the rest of my program.

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);

  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif

  // 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();

  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;
  }
  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)  // s'il fait nuit
  {
    if (!PorteFermee) //  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
      AUTO_Fermeture = true;
      AutoFermerMoteur ();
    }
    else   // mais 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
      AUTO_Fermeture = false;
    }
  }

  if (JourVrai)   //  s'il fait jour
  {
    if (!PorteOuverte) //  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
      AUTO_Fermeture = false;
    }
    else  // mais la porte est en position ouverte...
    {
      Etat_ouverture_auto = 0; //on affecte la variable à 0
      Etat_fermeture_auto = 0; //on affecte la variable à 0
      AUTO_Fermeture = false;
    }
  }

  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);

    debugTxtVar(temps_fermeture_auto , temps_fermeture_auto);

  }
}//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 AutoFermerMoteur () { //va faire fermer le moteur automatiquement au bout de 10 s

  temps_fermeture_auto = temps_actuel;//on réinitialise le temps passé à 0 ms
  temps_actuel = millis ();
  if ((temps_actuel - temps_fermeture_auto) >= 10000ul && AUTO_Fermeture)
  {
    digitalWrite(RelayPin1, LOW); //le relais 1 est actif
    digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
  }
}

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


// 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;
}

As you can see, I use the millis function for most of the functions in my program.

For example, the task_mesure_tensions function allows me to measure the voltage across the solar cell every 250 ms.

For that, I assigned the global variable "temps_mesures" to 0, while the variable "temps_actuel" allows to display the current time passed since the feeding of the assembly.

With the help of an if condition, we make sure that there is a difference of 250ms between "temps_actuel" and "temps_mesures".

Once this delay has passed, the value of "temps_mesures" is assigned to the current value of "current_time" in order to reset their difference to 0, to wait in the loop for it to reach 250 ms, and so on.

My goal is to make the door close automatically with the AutoCloseMotor () function.

As a reminder, it had to start if the door is not in the closed position AND if it "True Day" = FALSE, that is to say it starts to get dark. I would like that as soon as it starts to get dark, we start a 10 second delay, and if it is still dark without interruption, we start to automatically close the door.

If it changes again during these 10 seconds, the auto-closing program is canceled. It only takes dark again to reset the 10 second timer again.

The problem is that because of the fault displaying "night" when supplying the assembly during the "day" (with a desk lamp to simulate), the program acts as if the automatic closing conditions were already respected.

As a result, the timer has already started, and even if the program is updated, it continues to run without being reset to 0.

And then, if at startup I leave the light on for 10 seconds and turn it off, the door will automatically close immediately when I don't want to do that.

It was then that I made changes in my program that I showed you:

void AutoFermerMoteur () { //va faire fermer le moteur automatiquement au bout de 10 s

  temps_fermeture_auto = temps_actuel;//on réinitialise le temps passé à 0 ms
  temps_actuel = millis ();
  if ((temps_actuel - temps_fermeture_auto) >= 10000ul && AUTO_Fermeture)
  {
    digitalWrite(RelayPin1, LOW); //le relais 1 est actif
    digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
  }

I actually want that when we start the AutoFermerMoteur function, the constant "temps_fermeture_auto" takes the same value as "temps_actuel" and does not change in order to create a difference of 10 seconds.

I then carried out a test and displayed the data on the serial monitor by starting the program on DAY:

image

I manage to have the value of "temps_fermeture_auto" assigned to the "temps_actuel" value when the conditions are met and I turn off the light.

The problem is that "temps_fermeture_auto" always continues to take the same value of "temps_actuel" instead of remaining constant.

Anyone have a solution for me please?

Thank you in advance .

hysteresis ?

Delay execution until condition has been true for X secs in my tutorial on How to write Timers and Delays in Arduino
Can used to avoid day/night/day problems due to passing shadows etc.

What does feed mean?

I have a automated plant watering system. When first energized, the system will start and run the pump, which is a bad thing. I had the value of the variable that held the moisture level set at 0% at initialization. When the program started up it 'sees' 0% moisture and fired up the pump. I changed the initialization value to 100%. Which meant at startup the pump did not immediately energize and flood my plants.

Hello !

I tried your link with the MillisDelay.h library, and it works! I manage to get the door closed 10 seconds after it's dark if it's still open!

I will now try to have the door open automatically in the same way if it is daylight for 10 seconds and the door is closed.

Thank you so much !