/*************************************************
BLOCK AUTOMATIQUE 2 CANTONS
Version événementielle correcte
*************************************************/
enum Signal { GREEN, YELLOW, RED };
// ================= STRUCTURE CANTON =================
struct Canton {
// Entrées
int occV;
int occA;
int occS;
int lib;
// Sorties zones
int zoneV;
int zoneA;
int zoneS;
// Signal
int sigR;
int sigJ;
int sigV;
// Etats occupation
bool zV_occ = false;
bool zA_occ = false;
bool zS_occ = false;
// mémoires anti-rebond
bool lastV = HIGH;
bool lastA = HIGH;
bool lastS = HIGH;
bool lastLib = HIGH;
// mémoires front montant approche
bool prevApproach = false;
bool frontApproach = false;
// état signal
Signal sig = GREEN;
// demande d'arrêt (événementielle)
bool stopRequest = false;
};
// ================= DECLARATION CANTONS =================
// -------- B1 --------
Canton B1 = {
22,23,24,25, // occV, occA, occS, lib
30,31,32, // zoneV, zoneA, zoneS
40,41,42 // signal R,J,V
};
// -------- B2 --------
Canton B2 = {
26,27,28,29,
33,34,35,
43,44,45
};
// ========================================================
void setup() {
Serial.begin(9600);
Serial.println("Systeme 2 cantons - logique evenementielle");
setupCanton(B1);
setupCanton(B2);
}
void loop() {
readCanton(B1);
readCanton(B2);
computeLogic();
updateCanton(B1);
updateCanton(B2);
delay(50);
}
// ================= SETUP =================
void setupCanton(Canton &c){
pinMode(c.occV, INPUT_PULLUP);
pinMode(c.occA, INPUT_PULLUP);
pinMode(c.occS, INPUT_PULLUP);
pinMode(c.lib , INPUT_PULLUP);
pinMode(c.zoneV, OUTPUT);
pinMode(c.zoneA, OUTPUT);
pinMode(c.zoneS, OUTPUT);
pinMode(c.sigR, OUTPUT);
pinMode(c.sigJ, OUTPUT);
pinMode(c.sigV, OUTPUT);
// zones alimentées au départ
digitalWrite(c.zoneV, HIGH);
digitalWrite(c.zoneA, HIGH);
digitalWrite(c.zoneS, HIGH);
}
// ================= LECTURE =================
void readCanton(Canton &c){
bool r;
// ---- Zone V ----
r = digitalRead(c.occV);
if(c.lastV == HIGH && r == LOW) c.zV_occ = true;
c.lastV = r;
// ---- Zone A (approche) ----
r = digitalRead(c.occA);
if(c.lastA == HIGH && r == LOW) c.zA_occ = true;
c.lastA = r;
// Détection front montant approche
c.frontApproach = (!c.prevApproach && c.zA_occ);
c.prevApproach = c.zA_occ;
// ---- Zone S ----
r = digitalRead(c.occS);
if(c.lastS == HIGH && r == LOW) c.zS_occ = true;
c.lastS = r;
// ---- Libération ----
r = digitalRead(c.lib);
if(c.lastLib == HIGH && r == LOW){
c.zV_occ = false;
c.zA_occ = false;
c.zS_occ = false;
}
c.lastLib = r;
}
// ================= OCCUPATION =================
bool cantonOccupe(Canton &c){
return (c.zV_occ || c.zA_occ || c.zS_occ);
}
// ================= LOGIQUE =================
void computeLogic(){
// -------- SIGNAL B2 --------
if(cantonOccupe(B2))
B2.sig = RED;
else
B2.sig = GREEN;
// -------- SIGNAL B1 --------
if(B2.sig == RED)
B1.sig = RED;
else
B1.sig = GREEN;
// =====================================================
// LOGIQUE EVENEMENTIELLE DEMANDE D'ARRET B1
// =====================================================
// Si B2 occupé ET front montant approche B1
if(B2.sig == RED && B1.frontApproach){
B1.stopRequest = true;
Serial.println("Demande arret B1");
}
// Si B2 libéré → réarmement
if(B2.sig == GREEN){
B1.stopRequest = false;
}
}
// ================= SORTIES =================
void updateCanton(Canton &c){
// Zone pleine vitesse toujours alimentée
digitalWrite(c.zoneV, HIGH);
// ----- Cas spécifique B1 -----
if(&c == &B1){
if(c.stopRequest){
digitalWrite(c.zoneA, LOW);
digitalWrite(c.zoneS, LOW);
} else {
digitalWrite(c.zoneA, HIGH);
digitalWrite(c.zoneS, HIGH);
}
}
else{
// B2 zones toujours alimentées pour l’instant
digitalWrite(c.zoneA, HIGH);
digitalWrite(c.zoneS, HIGH);
}
updateSignal(c);
}
// ================= SIGNAL =================
void updateSignal(Canton &c){
digitalWrite(c.sigR, c.sig == RED);
digitalWrite(c.sigJ, c.sig == YELLOW);
digitalWrite(c.sigV, c.sig == GREEN);
}