Bonjour.
Je suis actuellement en stage et je travaille sur un projet de système d'ouverture et de fermeture pour poulailler. Je dois programmer une porte de type guillotine, qui s'ouvre et qui se ferme selon le sens de rotion du moteur piloté par des relais, en mode automatique.
Des capteurs HAUT et BAS sont intégrés pour désigner les limites d'ouverture et de fermeture de la porte, qui possèdent des contacts normalement ouverts. Ces contacts se ferment lorsqu'il détectent un aimant accroché à la porte, ce qui permet d'arrêter le moteur 1 seconde après que les contacts se ferment et pour arrêter la porte.
Je suis parvenu à programmer le mode manuel de la porte avec l'aide d'un bouton RIGHT inclûs dans l'afficheur LCD qui affiche également des données à l'écran. Dans ce mode manuel, en appuyant sur le bouton:
-la porte se ferme jusqu'au capteur BAS (+1 seconde)
-elle effectue une pause de 3 secondes
-la porte s'ouvre jusqu'au capteur HAUT (+1 seconde)
-fin du test manuel de la porte.
A présent, je cherche à faire ouvrir et fermer automatiquement la porte selon la période de la journée. J'utilise une cellule solaire pour détecter la luminosité ambiante et la convertir en tension.
Ici, j'aimerais programmer un seuil de 1V pour déterminer s'il fait jour ou nuit.
J'ai également ajouté des variables booléennes pour désigner l'état de la porte (fermée, non fermée, ouverte, non ouverte), et j'utilise la fonction millis() pour les temporisations, et des machines à états pour mes programmes.
Voilà ce que j'ai fait:
//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;
}
Pour l'instant, j'essaie d'effectuer un test de fermeture automatique, où s'il fait nuit mais que la porte n'est pas complétement fermée, cela lance une temporisation de 10 secondes où, une fois écoulée, permet de faire fermer la porte.
J'utilise également le moniteur série pour faire afficher mes données:
Comme prévu, la variable Etat_fermeture_auto passe à 1 lorsqu'il fait nuit mais que la porte n'est pas encore fermée.
Cependant, après 10 secondes, la variable reste à 1 au lieu d'être affecté à 2 pour fermer la porte.
J'utilise une switch case pour cette fonction de mon programme, mais également pour la fonction task_fonctionnement_manuel pour le test manuel de la porte, où Etat_fonctionnement_manuel passe bien à 1 à l'appui du bouton, ce qui fait fermer la porte.
Comment ça se fait ?
Aurais-je fait une erreur quelque part ? Est-ce liée à la temporisation de 10 secondes ?
J'ai besoin d'aide SVP