/********************************************************************************
* PN_TIB_Deux_voies_COMPLET.ino *
********************************************************************************
* Ce programme est dans le domaine public. *
* Dernière mise a jour : 19 avril 2025 *
* DEUX VOIES(une verte et une bleue) *
* Les poussoirs sont les ILS : DEUX SECONDES ENTRE CHAQUE APPUI. *
* DELAI CLIGNOTEMENT AVANT FERMETURE : 4 secondes (ligne 20) *
* INITIALISATION VOIE 1 ET VOIE 2 OCCUPEES !!! *
*******************************************************************************/
#include <Servo.h>
#include <LightDimmer.h>
LightDimmer feuPN;
Servo servo1;
Servo servo2;
// Variables utilisateur pour reglage du mouvement des barrieres
// -------------------------------------------------------------
unsigned long delaiFermeture = 4000; // Regle le delai entre clignotement LED
// et fermeture barrieres - entre 2000 et 8000 mais 0 sur TIB (pas de delai)
int speedServo = 30; // Regle la vitesse de mouvement des barrieres
// Variables non utilisateur
// -------------------------
const byte ILS=2; // Entree pour voie 1
const byte ILS2=3; // Entree pour voie 2
const byte LED = 6;
const byte S1=4; // sortie pour le servomoteur 1
const byte S2=8; // sortie pour le servomoteur 2
unsigned int compteur = 1; // compteur d evenements (survol ILS)
unsigned int compteur2 = 1; // compteur d evenements survol ILS2
// Initialisation avec un train sur voie 1 ET voie 2
volatile static boolean etatZonePN = true;
volatile static boolean old_etatZonePN = false; // etat anterieur de la zone
volatile static bool etatZoneZ1 = true;
volatile static bool etatZoneZ2 = true;
volatile static bool oldetatZoneZ1 = true;
volatile static bool oldetatZoneZ2 = true;
volatile static unsigned long old_top_debutISR; // Date anterieure d appel ISR
unsigned long old_top = 0; // variable pour afficher donnees utiles
volatile static unsigned long old_top_debutISR2; // Date anterieure d appel ISR
unsigned long old_top2 = 0; // variable pour afficher donnees utiles
int posServo = 90; // position courante a initialiser imperativement FERMEE
int posOuvert = 0; // barriere a 10° de la verticale
int posFerme = 90; // barriere a l'horizontale (90° de la verticale)
unsigned long topAttente = 0; // top pris au début franchissement de la zone PN
void changeEtatZ1() { // routine d'interruption (ISR)
unsigned long top_debutISR = millis(); // date appel ISR
if((top_debutISR - old_top_debutISR) > 2000) {
// 2 secondes au moins entre execution ISR
etatZoneZ1 = !etatZoneZ1; // etat passe a etat oppose
old_top_debutISR = top_debutISR; // initialisation date anterieure d appel ISR
}
} // fin de ISR
void changeEtatZ2() { // routine d'interruption (ISR)
unsigned long top_debutISR2 = millis(); // date appel ISR
if((top_debutISR2 - old_top_debutISR2) > 2000) {
// 2 secondes au moins entre execution ISR
etatZoneZ2 = !etatZoneZ2; // etat passe a etat oppose
old_top_debutISR2 = top_debutISR2; // initialisation date anterieure d appel ISR
}
} // fin de ISR
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // Communication avec le moniteur
Serial.println("Voie 1 occupée Voie 2 occupée Zone PN occupée");
pinMode (ILS, INPUT_PULLUP);
pinMode (LED_BUILTIN, OUTPUT);
// changeEtat est la routine d'interruption sur l'entree ILS ou ILS2
// elle est declenchee par un front descendant
attachInterrupt (digitalPinToInterrupt(ILS), changeEtatZ1, FALLING);
attachInterrupt (digitalPinToInterrupt(ILS2), changeEtatZ2, FALLING);
digitalWrite (LED_BUILTIN, LOW);
feuPN.begin(LED, HIGH); // LED s allume avec etat haut
servo1.attach(S1);
servo2.attach(S2);
// initialisation des barrieres en position fermee
servo1.write(posFerme); // barriere 1 FERMEE apres initialisation
servo2.write(posFerme); // barriere 2 FERMEE apres initialisation
delay(2000);
digitalWrite (LED_BUILTIN, HIGH); // Indique fin de setup
} // fin de setup
void loop() {
// put your main code here, to run repeatedly:
// Traitement des deux zones pour deduire etatZonePN
if(etatZoneZ1 == false && etatZoneZ2 == false) {
etatZonePN = false;
}
if(etatZoneZ1 == true || etatZoneZ2 == true) {
etatZonePN = true;
}
// Traitement des feux et des barrieres
if(etatZonePN == false) {
old_etatZonePN = etatZonePN;
digitalWrite (LED_BUILTIN, LOW); // eteint LED de controle de la zone PN
feuPN.stopBlink(); // arrete le clignotement des feux de PN
feuPN.off(); // eteint les feux de PN
// ouverture barriere
if(posServo > posOuvert) {
posServo = posServo - 1;
servo1.write(posServo);
servo2.write(posServo);
delay(speedServo);
} // fin du test sur position des servos
} // fin du test sur etat de la Zone du PN -> false
if(etatZonePN == true) {
if(etatZonePN != old_etatZonePN) {
topAttente = millis(); // prend un top d'entree dans zone PN
old_etatZonePN = etatZonePN;
} // fin du deuxieme if
digitalWrite (LED_BUILTIN, HIGH); // allume LED de controle de la zone PN
feuPN.startBlink(); // commence le clignotement
// fermeture barriere après attente
if(millis() - topAttente > delaiFermeture) {
if(posServo < posFerme) {
posServo = posServo + 1;
servo1.write(posServo);
servo2.write(posServo);
delay(speedServo);
} // fin du test sur position des servos
} // fin du test sur delai avant fermeture
} // fin du test sur etat de la Zone du PN -> true
LightDimmer::update();
// Affichage de la zone PN
if(etatZoneZ1 != oldetatZoneZ1 || etatZoneZ2 != oldetatZoneZ2) {
if(etatZoneZ1 == true) {
Serial.print("Voie 1 occupée ");
if(etatZoneZ2 == true) {
Serial.print("Voie 2 occupée ");
}
if(etatZoneZ2 == false) {
Serial.print("Voie 2 libre ");
}
} // Fin Z1 occupée
if(etatZoneZ1 == false) {
Serial.print("Voie 1 libre ");
if(etatZoneZ2 == true) {
Serial.print("Voie 2 occupée ");
}
if(etatZoneZ2 == false) {
Serial.print("Voie 2 libre ");
}
} // Fin Z1 libre
oldetatZoneZ1 = etatZoneZ1;
oldetatZoneZ2 = etatZoneZ2;
if(etatZoneZ1 == false && etatZoneZ2 == false) {Serial.println("Zone PN libre");}
if(etatZoneZ1 == true || etatZoneZ2 == true) {Serial.println("Zone PN occupée");}
} // Fin du if avec OU
} // fin de loop