AeroTempo : Différence entre versions

De fablabo
Aller à : navigation, rechercher
(2 révisions intermédiaires par le même utilisateur non affichées)
Ligne 23 : Ligne 23 :
 
Automate.jpg|Le schéma de l'automate d'états finis de l'AéroTempo.
 
Automate.jpg|Le schéma de l'automate d'états finis de l'AéroTempo.
 
</gallery>
 
</gallery>
 +
 +
Le code source commenté à héberger sur une carte Arduino Uno ou Duomilanove :
 +
<code>
 +
/******************************************************
 +
  AeroTempo : Temporisateur pour aérateur de toilettes
 +
  Principe : 1) A la détection de l'apparition de la lumière dans les toilettes :
 +
              2) - mise en route d'une première temporisation t1,
 +
              3) - mise en route du ventilagteur/extracteur via un relai 220v
 +
              4) A la disparition de la lumière :
 +
              5) - mise en route d'une seconde temporisation t2,
 +
              6) - extinction du ventilateur.
 +
    Version V0 : Montage initial pour test(POC), t1 = 1 min., t2 = 2 min. fixées en dur dans le code
 +
                Utilisation d'un écran LCD inspiré de l'exemple Hello Word de la librairie LyquidCryqtal de l'ID Arduino
 +
                The circuit:
 +
              * LCD VSS pin (1) to ground             
 +
              * LCD Vdd pin (2) to 5V             
 +
              * 10K resistor (j'ai mis un potentiomètre pour régler le contraste :
 +
              *    ends to +5V and ground
 +
              *    wiper to LCD VO pin (3)
 +
              * LCD RS pin (4) to digital pin 12 Arduino
 +
              * LCD R/W pin (5) to ground
 +
              * LCD Enable pin (6) to digital pin 11
 +
              * LCD DB4 pin (11) to digital pin 5
 +
              * LCD DB5 pin (12) to digital pin 4
 +
              * LCD DB6 pin (13) to digital pin 3
 +
              * LCD DB7 pin (14) to digital pin 2
 +
    Version V0a : Reprise du code de l'exemple Hello Word de la librairie LyquidCryqtal de l'IDE Arduino
 +
    Version V0b : Intégraion de la LDR (selon mon cours au MDC) et intégration du relai
 +
              Le Circuit :
 +
              * LDR en série avec R1k entre +5v et Gnd
 +
              * Point milieu avec A0
 +
              * Relay +5v et Gnd et In1 avec broche 7
 +
    Version V0c : Mise en place des deux temporisations (en dur dans le code)
 +
              * t1 => délai d'attente après l'établissement de la lumière avant déclenchement de l'aérateur
 +
              *    (pour éviter le déclenchement sur une simple ouverture de porte de courte durée)
 +
              * t2 => temps de fonctionnement de l'aérateur après l'extinction de la lumière
 +
              * Recours à un automate d'états finis cf.
 +
              * https://forum.arduino.cc/t/programmation-automate-fini-machine-a-etat/452532/5
 +
    Version V0d :
 +
              - Mise en place d'un reset matériel
 +
              * Le circuit :
 +
              *  R2k entre la broche 8 et le Reset
 +
              *  /!\ Attention à ne pas utiliser la broche 13 qui est en PullUp et repasse à 0 à chaque Reset,
 +
              *  donc le premier Soft Reset déclenche une infinité de Reset => la carte reste bloquée et ne redémarre pas !
 +
              - Passage de l'affichage en pourcentage de luminosité :
 +
                        0% Nuit noire (1023 lu sur la LDR)
 +
                      100% Pleine lumière (0 lu sur la LDR)
 +
              - Mise en place d'un mode Run et d'un mode Test :
 +
                      qui permet une modification des valeurs des tempos
 +
                      Changement de mode par un PushButton à bascule sur la broche 9
 +
    Version V0e :
 +
              - Le mode initial et après chaque reset est Run
 +
              - Renommage du mode Test en mode Test (t)
 +
              - Affichage de la tempo à rebours (décompte) pendant les états etT1 et etT2
 +
*******************************************************************************/
 +
// include the library code:
 +
#include <LiquidCrystal.h>
 +
// initialize the library by associating any needed LCD interface pin
 +
// with the arduino pin number it is connected to
 +
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
 +
const int LdrAnalogIn = A0;
 +
const int RelayPin = 7;  // Broche IN1 du relay qui pilote l'aérateur
 +
const int ModePin = 9;  // Broche du PushButton de changement de Mode
 +
const String FirmWareVersion = "v0e"; // Version du FirmWare pour l'affichage
 +
 +
int LdrValue = 0;                // Valeur lue sur la LDR (Valeur faible = forte luminosité)
 +
int Col = 0;                      // Numéro de la colonne pour l'écriture sur l'écran LCD (entre 0 et 15)
 +
unsigned long TimeStamp = 0;      // Top Chrono pour suivre l'écoulement des délais t1 et t2
 +
unsigned long timer = 0;          // Permet l'affichage du temps qui s'écoule
 +
 +
int t1;            // Tempo (en secondes) entre détection de la lumière et mise en route de l'aérateur
 +
int t2;            // Tempo (en secondes) entre extinction de la lumière et arrêt de l'aérateur
 +
unsigned long T;    // Tempo (en secondes) entre deux Reset de la carte
 +
 +
// Création de l'afficheur LCD1604
 +
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
 +
 +
// Définition des deux modes de fonctionnement
 +
enum :boolean {Test, Run} mode;
 +
 +
// Définition des 4 états de l'automate
 +
enum :byte {etOff,etT1,etOn,etT2} etat;
 +
 +
// Définition des 4 événements
 +
boolean evLightOn() {          // Apparition de la lumière
 +
  // Lecture de la luminosité
 +
  LdrValue = analogRead(LdrAnalogIn);
 +
  lcd.setCursor(0,1);                    // On place le curseur en début de ligne 1
 +
  lcd.print(100-int(LdrValue/10.23));    // On affiche le pourcentage de luminosité à partir de la valeur lue sur la LDR : (0<LDR<1023)
 +
  lcd.print("% ");                        // Pour effacer l'unité au cas où la valeur diminue d'un ordre de grandeur.
 +
  if (LdrValue < 500) {
 +
    return true;
 +
  } else {
 +
    return false;
 +
  }
 +
}
 +
 +
boolean evLightOff() {          // Disparition de la lumière
 +
  return !evLightOn();
 +
}
 +
 +
boolean evT1Out() {            // Fin de la tempo T1
 +
  if (millis()/1000 - TimeStamp > t1) {
 +
    return true;
 +
  } else {
 +
    return false;
 +
  }
 +
}
 +
 +
boolean evT2Out() {            // Fin de la tempo T2
 +
  if (millis()/1000 - TimeStamp > t2) {
 +
    return true;
 +
  } else {
 +
    return false;
 +
  }
 +
}
 +
 +
// Cette fonction effectue un effaçage du Timer
 +
// quelque soit sa longueur ( entre 1 et 5 caractères)
 +
void effaceTimer() {
 +
  lcd.setCursor(11,1);
 +
  lcd.print("    ");
 +
}
 +
 +
// Cette fonction effectue un Reset matériel
 +
void pushReset() {
 +
  int resetPin = 8;                //!\\ ne pas utiliser la broche 13 cf. commentaires en intro
 +
  pinMode(resetPin, OUTPUT);      // active la broche en sortie (OUTPUT) ce qui déclenche le reset
 +
}
 +
 +
void setup() {
 +
  // Détermination des modes pour les broches
 +
  pinMode(LdrAnalogIn,INPUT);
 +
  pinMode(RelayPin,OUTPUT);
 +
  pinMode(ModePin,INPUT);
 +
 +
  // Initialisation de la liaison série
 +
  Serial.begin(115200);
 +
 
 +
  // Paramétrage du LCD : Nb de colonnes, Nb de lignes
 +
  lcd.begin(16, 2);
 +
  // Affichage de la version du FirmWare.
 +
  lcd.print("AeroTempo");
 +
  lcd.setCursor(7,1);
 +
  lcd.print(FirmWareVersion);
 +
 +
  // Initialisation de l'automate
 +
  etat = etOff;
 +
  TimeStamp = 0;
 +
  mode = Run;
 +
  Serial.println("AeroTempo");
 +
}
 +
 +
void loop() {
 +
 
 +
  // Reglage du Bug d'affichage : Cetrainment un parasite sur la broche 11 (Enable) qui reset l'afficheur
 +
  digitalWrite(11,LOW);
 +
 
 +
  // Détection du changement de mode entre Run et Test
 +
  if (digitalRead(ModePin) == HIGH) {
 +
    Serial.print(mode + " Bip ");
 +
 +
    if (mode == Test) {
 +
      mode = Run;
 +
    } else {
 +
      mode = Test;
 +
    }
 +
    Serial.println(mode);
 +
  }
 +
 +
  // Détermination des paramètres de tempo selon le mode (Run ou Test)
 +
  switch (mode) {
 +
    case Test :
 +
      t1 = 5;
 +
      t2 = 10;
 +
      T = 50;
 +
      break;
 +
     
 +
    case Run :
 +
      t1 = 60;
 +
      t2 = 300;
 +
      T = 86400;
 +
      break;
 +
  }
 +
 
 +
  // Coeur de l'automate d'états finis
 +
  switch (etat) {
 +
    case etOff :
 +
      lcd.setCursor(13,0);        // On place le curseur en bout de ligne 0
 +
      lcd.print("Off");            // On affiche l'état
 +
      digitalWrite(RelayPin,HIGH);  // On arrète l'aérateur
 +
      if (evLightOn()) {            // la lumière est-elle allumée ?
 +
        TimeStamp = millis()/1000;  // On note le top départ de t1
 +
        etat = etT1;                // l'automate change d'état     
 +
      }
 +
      timer = (millis()/1000 - TimeStamp);
 +
      break;
 +
     
 +
    case etT1 :
 +
      lcd.setCursor(13,0);        // On place le curseur en bout de ligne 0
 +
      lcd.print(" T1");          // On affiche l'état
 +
      if (evLightOff()) {        // la lumière est-elle éteinte ?
 +
        TimeStamp = 0;
 +
        etat = etOff;            // l'automate change d'état
 +
      } else if (evT1Out()){      // le délai de t1 est-il expiré ?
 +
                                  //  (i.e. la lumière est-elle établie depuis suffisamment longtemps (t1 secondes)
 +
        TimeStamp = 0;
 +
        etat = etOn;              // l'automate change d'état
 +
      }
 +
      timer = t1-(millis()/1000 - TimeStamp);   
 +
      break;
 +
     
 +
    case etOn :
 +
      lcd.setCursor(13,0);        // On place le curseur en bout de ligne 0
 +
      lcd.print(" On");            // On affiche l'état
 +
      digitalWrite(RelayPin,LOW);  // On met en route l'aérateur
 +
      if (evLightOff()) {          // la lumière est-elle éteinte ?
 +
        TimeStamp = millis()/1000; // On note le top départ de t2
 +
        etat = etT2;              // l'automate change d'état
 +
      }
 +
      timer = (millis()/1000 - TimeStamp);     
 +
      break;
 +
     
 +
    case etT2 :
 +
      lcd.setCursor(13,0);          // On place le curseur en bout de ligne 0
 +
      lcd.print(" T2");            // On affiche l'état
 +
      if (evT2Out()) {              // le délai T2 est-il expiré ?
 +
                                    //  (i.e. la lumière est-elle éteinte depuis suffisamment longtemps (t2 secondes)
 +
        TimeStamp = 0;
 +
        etat = etOff;                // l'automate change d'état
 +
      } else if (evLightOn()) {
 +
        TimeStamp = 0;              // On reset le TimeStamp
 +
        etat = etOn;
 +
      }
 +
      timer = t2 - (millis()/1000 - TimeStamp);
 +
      break;
 +
  } // fin du switch case sur l'état de l'automate
 +
 
 +
  // Détermination de la colone où débute l'affichage du Timer
 +
  //timer = (millis()/1000 - TimeStamp);
 +
  if (timer < 10) {
 +
    Col = 15;
 +
  } else if (timer < 100) {
 +
    Col = 14;
 +
  } else if (timer < 1000) {
 +
    Col = 13;
 +
  } else if (timer < 10000) {
 +
    Col = 12;
 +
  } else if (timer < 100000) {
 +
    Col = 11;
 +
  }
 +
 
 +
  // Affichage du mode
 +
  lcd.setCursor(12,0);
 +
  if (mode == Test) {
 +
    lcd.print("t");
 +
  } else {
 +
    lcd.print("r");
 +
  }
 +
 
 +
  // Affichage du timer
 +
  effaceTimer();
 +
  lcd.setCursor(Col,1);
 +
  lcd.print(timer);
 +
 +
  // Reset régulier bout T secondes
 +
  if (millis()/1000  > T) {
 +
    pushReset();
 +
  }
 +
 +
  Serial.println(digitalRead(ModePin));
 +
}
 +
</code>

Version du 26 décembre 2021 à 19:19


Temporisateur d'aérateur de toilettes

JoliAfficheur.jpg

Contributeur·ice·s

Statut du projet

Fonctionnel

Statut de la publication

Brouillon

License

CC-by-sa-3.0 - Creative Commons Attribution CC-by-sa-3.0 France

Inspiration

Fichiers source

AeroTempoV0e.ino

Machines

Matériaux

Lien




Cet article décrit la réalisation d'un temporisateur pour aération de toilettes. Le principe est de détecter l'entrée dans les toilettes pas l'allumage de la lumière. Cet allumage déclenche une première temporisation à l'issue de laquelle, si la lumière ne s'éteint pas, l'aérateur se déclenche pour une seconde temporisation. A l'issue de cette seconde temporisation, si la lumière ne se rallume pas, l'aérateur s'éteint.

Techniquement, l'AéroTempo est basé sur un automate d'états finis à 4 états et 4 transitions.

Les 4 états : Off, T1, On, T2

Les 4 transitions : LightOn, LightOff, FinT1, FinT2

Le schéma de l'automate est le suivant :

Le code source commenté à héberger sur une carte Arduino Uno ou Duomilanove : /******************************************************

  AeroTempo : Temporisateur pour aérateur de toilettes
  Principe : 1) A la détection de l'apparition de la lumière dans les toilettes :
             2) - mise en route d'une première temporisation t1,
             3) - mise en route du ventilagteur/extracteur via un relai 220v
             4) A la disparition de la lumière :
             5) - mise en route d'une seconde temporisation t2,
             6) - extinction du ventilateur.
   Version V0 : Montage initial pour test(POC), t1 = 1 min., t2 = 2 min. fixées en dur dans le code
               Utilisation d'un écran LCD inspiré de l'exemple Hello Word de la librairie LyquidCryqtal de l'ID Arduino
               The circuit:
              * LCD VSS pin (1) to ground               
              * LCD Vdd pin (2) to 5V               
              * 10K resistor (j'ai mis un potentiomètre pour régler le contraste :
              *    ends to +5V and ground
              *    wiper to LCD VO pin (3)
              * LCD RS pin (4) to digital pin 12 Arduino
              * LCD R/W pin (5) to ground
              * LCD Enable pin (6) to digital pin 11
              * LCD DB4 pin (11) to digital pin 5
              * LCD DB5 pin (12) to digital pin 4
              * LCD DB6 pin (13) to digital pin 3
              * LCD DB7 pin (14) to digital pin 2
   Version V0a : Reprise du code de l'exemple Hello Word de la librairie LyquidCryqtal de l'IDE Arduino
   Version V0b : Intégraion de la LDR (selon mon cours au MDC) et intégration du relai
              Le Circuit :
              * LDR en série avec R1k entre +5v et Gnd
              * Point milieu avec A0
              * Relay +5v et Gnd et In1 avec broche 7
   Version V0c : Mise en place des deux temporisations (en dur dans le code)
              * t1 => délai d'attente après l'établissement de la lumière avant déclenchement de l'aérateur
              *    (pour éviter le déclenchement sur une simple ouverture de porte de courte durée)
              * t2 => temps de fonctionnement de l'aérateur après l'extinction de la lumière 
              * Recours à un automate d'états finis cf. 
              * https://forum.arduino.cc/t/programmation-automate-fini-machine-a-etat/452532/5
   Version V0d :
              - Mise en place d'un reset matériel
              * Le circuit :
              *   R2k entre la broche 8 et le Reset
              *   /!\ Attention à ne pas utiliser la broche 13 qui est en PullUp et repasse à 0 à chaque Reset,
              *   donc le premier Soft Reset déclenche une infinité de Reset => la carte reste bloquée et ne redémarre pas !
              - Passage de l'affichage en pourcentage de luminosité :
                       0% Nuit noire (1023 lu sur la LDR)
                     100% Pleine lumière (0 lu sur la LDR)
              - Mise en place d'un mode Run et d'un mode Test :
                     qui permet une modification des valeurs des tempos
                     Changement de mode par un PushButton à bascule sur la broche 9
   Version V0e : 
              - Le mode initial et après chaque reset est Run
              - Renommage du mode Test en mode Test (t)
              - Affichage de la tempo à rebours (décompte) pendant les états etT1 et etT2 
*******************************************************************************/

// include the library code:

  1. include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin // with the arduino pin number it is connected to const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2; const int LdrAnalogIn = A0; const int RelayPin = 7; // Broche IN1 du relay qui pilote l'aérateur const int ModePin = 9; // Broche du PushButton de changement de Mode const String FirmWareVersion = "v0e"; // Version du FirmWare pour l'affichage

int LdrValue = 0; // Valeur lue sur la LDR (Valeur faible = forte luminosité) int Col = 0; // Numéro de la colonne pour l'écriture sur l'écran LCD (entre 0 et 15) unsigned long TimeStamp = 0; // Top Chrono pour suivre l'écoulement des délais t1 et t2 unsigned long timer = 0; // Permet l'affichage du temps qui s'écoule

int t1; // Tempo (en secondes) entre détection de la lumière et mise en route de l'aérateur int t2; // Tempo (en secondes) entre extinction de la lumière et arrêt de l'aérateur unsigned long T; // Tempo (en secondes) entre deux Reset de la carte

// Création de l'afficheur LCD1604 LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// Définition des deux modes de fonctionnement enum :boolean {Test, Run} mode;

// Définition des 4 états de l'automate enum :byte {etOff,etT1,etOn,etT2} etat;

// Définition des 4 événements boolean evLightOn() { // Apparition de la lumière

 // Lecture de la luminosité
 LdrValue = analogRead(LdrAnalogIn);
 lcd.setCursor(0,1);                     // On place le curseur en début de ligne 1
 lcd.print(100-int(LdrValue/10.23));     // On affiche le pourcentage de luminosité à partir de la valeur lue sur la LDR : (0<LDR<1023)
 lcd.print("% ");                        // Pour effacer l'unité au cas où la valeur diminue d'un ordre de grandeur.
 if (LdrValue < 500) {
   return true;
 } else {
   return false;
 }

}

boolean evLightOff() { // Disparition de la lumière

 return !evLightOn();

}

boolean evT1Out() { // Fin de la tempo T1

 if (millis()/1000 - TimeStamp > t1) {
   return true;
 } else {
   return false;
 }

}

boolean evT2Out() { // Fin de la tempo T2

 if (millis()/1000 - TimeStamp > t2) {
   return true;
 } else {
   return false;
 }

}

// Cette fonction effectue un effaçage du Timer // quelque soit sa longueur ( entre 1 et 5 caractères) void effaceTimer() {

 lcd.setCursor(11,1);
 lcd.print("     "); 

}

// Cette fonction effectue un Reset matériel void pushReset() {

 int resetPin = 8;                //!\\ ne pas utiliser la broche 13 cf. commentaires en intro
 pinMode(resetPin, OUTPUT);       // active la broche en sortie (OUTPUT) ce qui déclenche le reset

}

void setup() {

 // Détermination des modes pour les broches
 pinMode(LdrAnalogIn,INPUT);
 pinMode(RelayPin,OUTPUT);
 pinMode(ModePin,INPUT);
 // Initialisation de la liaison série
 Serial.begin(115200);
 
 // Paramétrage du LCD : Nb de colonnes, Nb de lignes
 lcd.begin(16, 2);
 // Affichage de la version du FirmWare.
 lcd.print("AeroTempo");
 lcd.setCursor(7,1);
 lcd.print(FirmWareVersion);
 // Initialisation de l'automate
 etat = etOff;
 TimeStamp = 0;
 mode = Run;
 Serial.println("AeroTempo");

}

void loop() {

  // Reglage du Bug d'affichage : Cetrainment un parasite sur la broche 11 (Enable) qui reset l'afficheur 
  digitalWrite(11,LOW);
  
  // Détection du changement de mode entre Run et Test
  if (digitalRead(ModePin) == HIGH) {
    Serial.print(mode + " Bip ");
    if (mode == Test) {
     mode = Run;
    } else {
     mode = Test;
    }
    Serial.println(mode);
  }
 // Détermination des paramètres de tempo selon le mode (Run ou Test)
 switch (mode) {
   case Test :
     t1 = 5;
     t2 = 10;
     T = 50;
     break;
     
    case Run :
     t1 = 60;
     t2 = 300;
     T = 86400;
     break;
 }
 
 // Coeur de l'automate d'états finis
 switch (etat) {
   case etOff :
     lcd.setCursor(13,0);         // On place le curseur en bout de ligne 0
     lcd.print("Off");            // On affiche l'état
     digitalWrite(RelayPin,HIGH);  // On arrète l'aérateur
     if (evLightOn()) {            // la lumière est-elle allumée ?
       TimeStamp = millis()/1000;  // On note le top départ de t1
       etat = etT1;                // l'automate change d'état       
     }
     timer = (millis()/1000 - TimeStamp);
     break;
     
   case etT1 :
     lcd.setCursor(13,0);        // On place le curseur en bout de ligne 0
     lcd.print(" T1");           // On affiche l'état
     if (evLightOff()) {         // la lumière est-elle éteinte ?
       TimeStamp = 0;
       etat = etOff;             // l'automate change d'état
     } else if (evT1Out()){      // le délai de t1 est-il expiré ? 
                                 //  (i.e. la lumière est-elle établie depuis suffisamment longtemps (t1 secondes)
       TimeStamp = 0;
       etat = etOn;              // l'automate change d'état
     }
     timer = t1-(millis()/1000 - TimeStamp);     
     break;
     
   case etOn :
     lcd.setCursor(13,0);         // On place le curseur en bout de ligne 0
     lcd.print(" On");            // On affiche l'état
     digitalWrite(RelayPin,LOW);  // On met en route l'aérateur
     if (evLightOff()) {          // la lumière est-elle éteinte ?
       TimeStamp = millis()/1000; // On note le top départ de t2
       etat = etT2;               // l'automate change d'état
     }
     timer = (millis()/1000 - TimeStamp);      
     break;
     
   case etT2 :
     lcd.setCursor(13,0);          // On place le curseur en bout de ligne 0
     lcd.print(" T2");             // On affiche l'état
     if (evT2Out()) {              // le délai T2 est-il expiré ?
                                   //  (i.e. la lumière est-elle éteinte depuis suffisamment longtemps (t2 secondes)
       TimeStamp = 0;
       etat = etOff;                // l'automate change d'état
     } else if (evLightOn()) {
       TimeStamp = 0;               // On reset le TimeStamp
       etat = etOn;
     }
     timer = t2 - (millis()/1000 - TimeStamp);
     break;
 } // fin du switch case sur l'état de l'automate
 
 // Détermination de la colone où débute l'affichage du Timer
 //timer = (millis()/1000 - TimeStamp);
 if (timer < 10) {
   Col = 15;
 } else if (timer < 100) {
   Col = 14; 
 } else if (timer < 1000) {
   Col = 13; 
 } else if (timer < 10000) {
   Col = 12; 
 } else if (timer < 100000) {
   Col = 11; 
 }
 
 // Affichage du mode
 lcd.setCursor(12,0);
 if (mode == Test) {
   lcd.print("t");
 } else {
   lcd.print("r");
 }
 
 // Affichage du timer
 effaceTimer();
 lcd.setCursor(Col,1);
 lcd.print(timer);
 // Reset régulier bout T secondes
 if (millis()/1000  > T) { 
   pushReset();
 }
 Serial.println(digitalRead(ModePin));

}