BMVU

Toutes les discussions sur l'Arduino !

Modérateur : MOD

Répondre
Avatar du membre
FFayolle
Éloquent
Messages : 382
Enregistré le : mar. 09 mai 2006, 19:55
Localisation : Amiens, Somme, Picardie
Âge : 52

BMVU

Message par FFayolle » lun. 26 août 2019, 13:52

Bonjour,
Ci-dessous le code permettant de simuler le fonctionnement d'un Block Manuel de Voie Unique avec des appareils de block de type Année 1960.
Tout est presque dit dans le code mais plus d'informations sur ce fil.

A noter qu'à l'instant T, l'activation des pédales de voie est simulée mais il sera possible d'y adjoindre un système adhoc (système de détection par exemple). Et il reste à gérer la dimension sonore!!!
Nul doute que l'un d'entre vous va me demander à quoi correspondent T.1, An.1, K,An2, K.Rep1,... Je vous invite à vous reporter au schéma 317 954_14 (Merci EC64).
14.jpg
Et en complément l'infographie d'une face avant (90 par 60mm) d'un appareil de block:
BMVU-FA-Infographie.jpg
BMVU-FA-Infographie.jpg (24.71 Kio) Vu 506 fois
Fabrice

Code : Tout sélectionner

// Name
#define NAME  "BMVU"
#define NAME2 "Block Manuel de Voie Unique type SNCF"
#define NAME3 "IN1547 & SES317-954"

// Version & Copyright
#define VERSION "Version 2.0 (Arduino Mega)"
#define COPYRIGHT "Copyright Fabrice Fayolle, Août 2019"

// Caractéristiques du canton
// X - Canton - Y

// Arduino Mega
// Pin                  -> Utilisé pour                                     -> Connecté à
// 0
// 1
//..
// 4                    -> Position du levier du sémaphore X                  -> Extérieur (système de gestion des enclenchements)
// 5                    -> Verrou du levier du sémaphore X                    -> Extérieur (système de gestion des enclenchements)
// 6                    -> Pédale de voie d'entrée dans le canton (côté X)    -> Extérieur (système de détection)
// 7                    -> Pédale de voie de sortie du canton (côté X)        -> Extérieur (système de détection)
// 8                    -> Position du levier du sémaphore Y                  -> Extérieur (système de gestion des enclenchements)
// 9                    -> Verrou du levier du sémaphore Y                    -> Extérieur (système de gestion des enclenchements)
// 10                   -> Pédale de voie d'entrée (côté Y)                   -> Extérieur (système de détection)
// 11                   -> Pédale de voie de sortie (côté Y)                  -> Extérieur (système de détection)
// ..
// 22 à 32              -> Appareil de block X                                -> E/S (Bouton-poussoir & LED)
// ..
// 42 à 52              -> Appareil de block Y                                -> E/S (Bouton-poussoir & LED)

// Type de connexion
// Bouton-poussoir: Travail à GND
// LED: Commun -

#define Normal HIGH
#define Renverse LOW

// Constantes et variables globales             // Equivalence 317.954_14
boolean Affichage = true;
const int Levier_Semaphore_X = 4;               // L.S1
const int Verrou_Levier_Semaphore_X = 5;
const int Pedale_Entree_X = 6;                  // B1
const int Pedale_Sortie_X = 7;                  // Pg2
const int Levier_Semaphore_Y = 8;
const int Verrou_Levier_Semaphore_Y = 9;
const int Pedale_Entree_Y = 10;
const int Pedale_Sortie_Y = 11;
boolean Canton_Reserve = false;
const unsigned long Delai_Ouverture_Verrou = 5000;

class Appareil
{
  private:
    int BN_BLOCAGE;                             // Blocage
    int BN_TEST;                                // T.1
    boolean REPONSE_ETAT;
    int VT_REPONSE;                             // K.Rep1
    int BN_ANNONCE;                             // An.1
    boolean REDDITION_ETAT;
    int VT_REDDITION;                           // K.L1
    int BN_REDDITION;                           // L1
    boolean ANNONCE_ETAT;
    int VT_ANNONCE;                             // K.An2
    int BN_SONNERIE;                            // ASn.An2
  public:
    void Setup(int indice);
    boolean Blocage();
    boolean Test();
    boolean Reponse();
    void Vt_Reponse();
    boolean Annonce();
    boolean Sonnerie();
    boolean Reddition();
    void Vt_Annonce();
    void Vt_Reddition();
}
;

void Appareil::Setup(int indice)
{
  BN_BLOCAGE = 2 + (indice * 20);
  pinMode(BN_BLOCAGE, INPUT_PULLUP);
  BN_TEST = 3 + (indice * 20);
  pinMode(BN_TEST, INPUT_PULLUP);
  REPONSE_ETAT = LOW;
  VT_REPONSE = 4 + (indice * 20);
  pinMode(VT_REPONSE, OUTPUT);
  digitalWrite(VT_REPONSE, LOW);
  BN_ANNONCE = 5 + (indice * 20);
  pinMode(BN_ANNONCE, INPUT_PULLUP);
  REDDITION_ETAT = LOW;
  VT_REDDITION = 6 + (indice * 20);
  pinMode(VT_REDDITION, OUTPUT);
  digitalWrite(VT_REDDITION, LOW);
  BN_REDDITION = 7 + (indice * 20);
  pinMode(BN_REDDITION, INPUT_PULLUP);
  ANNONCE_ETAT = LOW;
  VT_ANNONCE = 8 + (indice * 20);
  pinMode(VT_ANNONCE, OUTPUT);
  digitalWrite(VT_ANNONCE, LOW);
  BN_SONNERIE = 9 + (indice * 20);
  pinMode(BN_SONNERIE, INPUT_PULLUP);
}

boolean Appareil::Blocage()
{
  boolean resultat = false;
  resultat = !digitalRead(BN_BLOCAGE);
  return resultat;
}

boolean Appareil::Test()
{
  boolean resultat = false;
  if (!digitalRead(BN_TEST))
  {
    delay(100);
    if (!digitalRead(BN_TEST))
    {
      Serial.print("Action: Appui sur le bouton T.1");
      while (!digitalRead(BN_TEST))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

boolean Appareil::Reponse()
{
  boolean resultat = false;
  if ((Blocage() == false) && (Canton_Reserve == false))
  {
    resultat = true;
  }
  return resultat;
}

void Appareil::Vt_Reponse()
{
  REPONSE_ETAT = !REPONSE_ETAT;
  digitalWrite(VT_REPONSE, REPONSE_ETAT);
}

boolean Appareil::Annonce()
{
  boolean resultat = false;
  if (!digitalRead(BN_ANNONCE))
  {
    delay(100);
    if (!digitalRead(BN_ANNONCE))
    {
      Serial.print("Action: Appui sur le bouton An.1");
      while (!digitalRead(BN_ANNONCE))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

void Appareil::Vt_Annonce()
{
  ANNONCE_ETAT = !ANNONCE_ETAT;
  digitalWrite(VT_ANNONCE, ANNONCE_ETAT);
}

boolean Appareil::Sonnerie()
{
  boolean resultat = false;
  if (!digitalRead(BN_SONNERIE))
  {
    delay(100);
    if (!digitalRead(BN_SONNERIE))
    {
      Serial.print("Action: Appui sur le bouton Asn.An.2");
      while (!digitalRead(BN_SONNERIE))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}


boolean Appareil::Reddition()
{
  boolean resultat = false;
  if (!digitalRead(BN_REDDITION))
  {
    delay(100);
    if (!digitalRead(BN_REDDITION))
    {
      Serial.print("Action: Appui sur le bouton L.2");
      while (!digitalRead(BN_REDDITION))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

void Appareil::Vt_Reddition()
{
  REDDITION_ETAT = !REDDITION_ETAT;
  digitalWrite(VT_REDDITION, REDDITION_ETAT);
}

Appareil BlockX;
Appareil BlockY;

void setup()
{
  Serial.begin(9600);
  Serial.println(NAME);
  Serial.println(NAME2);
  Serial.println(NAME3);
  Serial.println("---------------------------------------------------------------------------");
  Serial.print(VERSION); Serial.print(", "); Serial.println(COPYRIGHT);
  Serial.println("---------------------------------------------------------------------------");
  Serial.println("");
  pinMode(Levier_Semaphore_X, INPUT_PULLUP);
  pinMode(Verrou_Levier_Semaphore_X, OUTPUT);
  digitalWrite(Verrou_Levier_Semaphore_X, HIGH);
  pinMode(Pedale_Entree_X, INPUT_PULLUP);
  pinMode(Pedale_Sortie_X, INPUT_PULLUP);
  pinMode(Levier_Semaphore_Y, INPUT_PULLUP);
  pinMode(Verrou_Levier_Semaphore_Y, OUTPUT);
  digitalWrite(Verrou_Levier_Semaphore_Y, HIGH);
  pinMode(Pedale_Entree_Y, INPUT_PULLUP);
  pinMode(Pedale_Sortie_Y, INPUT_PULLUP);
  BlockX.Setup(1);
  BlockY.Setup(2);
  Serial.println("Information: Block Manuel de Voie Unique initialisé");
  Serial.println("");
  Serial.println("----------------------------------------------");
  Serial.println("X ---------------- CANTON ------------------ Y");
  Serial.println("----------------------------------------------");
}

void loop()
{
  unsigned long Horodatage;
  // Rq1: En voie unique, le block manuel est interrompu à la traversée des gares.
  // Rq2: Les manoeuvres effectuées en gare sont protégées par la fermeture du Disque (et non par le commutateur Blocage) obligeant le convoi entrant à se mettre en marche à vue
  // au plus tôt et à s'arrêter à la 1ère aiguille rencontrée
  if (Affichage)
  {
    Serial.println("");
    Serial.println("Attente: Appui sur un des boutons T.1()");
    Serial.println("");
    Affichage = false;
  }
  // Si l'Agent de circulation appuie sur le bouton TEST du block X alors
  if (BlockX.Test())
  {
    Serial.println("(X)");
    // Si rien ne s'y oppose alors
    if (BlockY.Reponse() == true && digitalRead(Levier_Semaphore_X) == Normal )
    {
      Serial.println("-> Voie libre");
      Horodatage = millis();
      // Voyant REPONSE du block X au Vert
      Serial.println("Voyant: K.Rep1(X) -> Vert");
      BlockX.Vt_Reponse();
      // Possibilité d'ouvrir le sémaphore X durant "Delai_Ouverture_Verrou" millisecondes
      // Verrou du levier de manoeuvre du sémaphore X ouvert
      digitalWrite(Verrou_Levier_Semaphore_X, LOW);
      Serial.print("Information: Verrou du L.S1(X) (Ouvert) durant ");
      Serial.print(Delai_Ouverture_Verrou / 1000);
      Serial.println(" secondes");
      while (((millis() - Horodatage) < Delai_Ouverture_Verrou) && Canton_Reserve == false )
      {
        Canton_Reserve = !digitalRead(Levier_Semaphore_X);
        if (Canton_Reserve == true)
        {
          Serial.println("Action: L.S1(X) en position (Renversé)");
          Serial.println("Information: Sémaphore(X) (Ouvert)");
        }
        delay(100);
      }
      // Verrou du levier de manoeuvre du sémaphore X fermé
      digitalWrite(Verrou_Levier_Semaphore_X, HIGH);
      Serial.println("Information: Verrou du L.S1(X) (Fermé)");
      // Voyant REPONSE du block X au Blanc (ou éteint)
      Serial.println("Voyant: K.Rep1(X) -> Blanc (ou Eteint)");
      BlockX.Vt_Reponse();
      // Si le sémaphore X a été ouvert durant le laps de temps défini alors
      if (Canton_Reserve == true)
      {
        // Attente de la l'activation de la pédale de voie d'entrée dans le canton
        // ou de la fermeture du sémaphore X (levier remis en position Normal)
        Affichage = true;
        while ((digitalRead(Pedale_Entree_X) == HIGH) && (digitalRead(Levier_Semaphore_X) == Renverse))
        {
          if (Affichage)
          {
            Serial.println("Attente: Pédale B1(X) activée ou L.S1(X) en position (Normal)");
            Affichage = false;
          }
          delay(100);
        }
        // Attente de la confirmation de la fermeture du sémaphore (levier remis en position Normal par l'Agent de circulation)
        if (digitalRead(Pedale_Entree_X) == LOW)
        {
          Serial.println("Information: Sémaphore(X) (Fermé) par aubinage");
          Serial.println("Information: Pédale B1(X) activée suite au passage du convoi");
          Affichage = true;
          while (digitalRead(Levier_Semaphore_X) == Renverse)
          {
            if (Affichage)
            {
              Serial.println("Attente: L.S1(X) en position (Normal)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("Information : L.S1(X) en position (Normal)");
          // Attente de l'annonce de X à Y par l'Agent de circulation (appui sur le bouton ANNONCE du block X)
          Affichage = true;
          while (!BlockX.Annonce())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton An.1(X)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("(X)");
          Serial.println("-> Convoi annoncé");
          // Voyant REDDITION du block X au Rouge
          Serial.println("Voyant: K.L1(X) -> Rouge");
          BlockX.Vt_Reddition();
          // Voyant ANNONCE du block Y passe au Bleu
          Serial.println("Voyant: K.An2(Y) -> Bleu");
          BlockY.Vt_Annonce();
          // Activation de la sonnerie du block Y tant que l'agent de circulation en Y n'appuie pas sur le bouton SONNERIE
          Jouer_Son(1);
          Serial.println("Information: Sonnerie(Y) -> Marche");
          Affichage = true;
          while (!BlockY.Sonnerie())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton ASn.An.2(Y)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("(Y)");
          Jouer_Son(0);
          Serial.println("Information: Sonnerie(Y) -> Arrêt");
          // Attente de la reddition de Y à X par l'Agent de circulation (appui sur le bouton REDDITION du block Y)
          // une fois la pédale de sortie du canton activée
          Affichage = true;
          while (digitalRead(Pedale_Sortie_Y) == HIGH)
          {
            if (Affichage)
            {
              Serial.println("Attente: Pédale Pg2(Y) activée");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("Action: Pédale Pg2(Y) activée");
          Affichage = true;
          while (!BlockY.Reddition())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton L.2(Y)");
              Affichage = false;
            }
          }
          Serial.println("(Y)");
          Serial.println("-> Convoi réceptionné");
          // Voyant ANNONCE block Y au Blanc (ou Eteint)
          Serial.println("Voyant: K.An2(Y) -> Blanc (ou Eteint)");
          BlockY.Vt_Annonce();
          // Voyant REDDITION du block X au Blanc (ou Eteint)
          Serial.println("Voyant: K.L1(X) -> Blanc (ou Eteint)");
          BlockX.Vt_Reddition();
          // Activation de la sonnerie du block X durant un temps défini
          Jouer_Son(2);
          Serial.println("Information: Sonnerie(X) -> Marche -> Arrêt");
        }
        else
        {
          Serial.println("Action: L.S1(X) en position (Normal)");
          Serial.println("Information: Sémaphore(X) (Fermé)");
          Canton_Reserve = false;
        }
      }
      Canton_Reserve = false;
      Affichage = true;
    }
    else
    {
      Affichage = true;
    }
  }
  // Si l'Agent de circulation appuie sur le bouton TEST du block Y alors
  if (BlockY.Test())
  {
    Serial.println("(Y)");
    // Si rien ne s'X oppose alors
    if (BlockX.Reponse() == true && digitalRead(Levier_Semaphore_Y) == Normal )
    {
      Serial.println("-> Voie libre");
      Horodatage = millis();
      // VoXant REPONSE du block Y au Vert
      Serial.println("VoXant: K.Rep1(Y) -> Vert");
      BlockY.Vt_Reponse();
      // Possibilité d'ouvrir le sémaphore Y durant "Delai_Ouverture_Verrou" millisecondes
      // Verrou du levier de manoeuvre du sémaphore Y ouvert
      digitalWrite(Verrou_Levier_Semaphore_Y, LOW);
      Serial.print("Information: Verrou du L.S1(Y) (Ouvert) durant ");
      Serial.print(Delai_Ouverture_Verrou / 1000);
      Serial.println(" secondes");
      while (((millis() - Horodatage) < Delai_Ouverture_Verrou) && Canton_Reserve == false )
      {
        Canton_Reserve = !digitalRead(Levier_Semaphore_Y);
        if (Canton_Reserve == true)
        {
          Serial.println("Action: L.S1(Y) en position (Renversé)");
          Serial.println("Information: Sémaphore(Y) (Ouvert)");
        }
        delay(100);
      }
      // Verrou du levier de manoeuvre du sémaphore Y fermé
      digitalWrite(Verrou_Levier_Semaphore_Y, HIGH);
      Serial.println("Information: Verrou du L.S1(Y) (Fermé)");
      // VoXant REPONSE du block Y au Blanc (ou éteint)
      Serial.println("VoXant: K.Rep1(Y) -> Blanc (ou Eteint)");
      BlockY.Vt_Reponse();
      // Si le sémaphore Y a été ouvert durant le laps de temps défini alors
      if (Canton_Reserve == true)
      {
        // Attente de la l'activation de la pédale de voie d'entrée dans le canton
        // ou de la fermeture du sémaphore Y (levier remis en position Normal)
        Affichage = true;
        while ((digitalRead(Pedale_Entree_Y) == HIGH) && (digitalRead(Levier_Semaphore_Y) == Renverse))
        {
          if (Affichage)
          {
            Serial.println("Attente: Pédale B1(Y) activée ou L.S1(Y) en position (Normal)");
            Affichage = false;
          }
          delay(100);
        }
        // Attente de la confirmation de la fermeture du sémaphore (levier remis en position Normal par l'Agent de circulation)
        if (digitalRead(Pedale_Entree_Y) == LOW)
        {
          Serial.println("Information: Sémaphore(Y) (Fermé) par aubinage");
          Serial.println("Information: Pédale B1(Y) activée suite au passage du convoi");
          Affichage = true;
          while (digitalRead(Levier_Semaphore_Y) == Renverse)
          {
            if (Affichage)
            {
              Serial.println("Attente: L.S1(Y) en position (Normal)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("Information : L.S1(Y) en position (Normal)");
          // Attente de l'annonce de Y à X par l'Agent de circulation (appui sur le bouton ANNONCE du block Y)
          Affichage = true;
          while (!BlockY.Annonce())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton An.1(Y)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("(Y)");
          Serial.println("-> Convoi annoncé");
          // VoXant REDDITION du block Y au Rouge
          Serial.println("VoXant: K.L1(Y) -> Rouge");
          BlockY.Vt_Reddition();
          // VoXant ANNONCE du block X passe au Bleu
          Serial.println("VoXant: K.An2(X) -> Bleu");
          BlockX.Vt_Annonce();
          // Activation de la sonnerie du block X tant que l'agent de circulation en X n'appuie pas sur le bouton SONNERIE
          Jouer_Son(1);
          Serial.println("Information: Sonnerie(X) -> Marche");
          Affichage = true;
          while (!BlockX.Sonnerie())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton ASn.An.2(X)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("(X)");
          Jouer_Son(0);
          Serial.println("Information: Sonnerie(X) -> Arrêt");
          // Attente de la reddition de X à Y par l'Agent de circulation (appui sur le bouton REDDITION du block X)
          // une fois la pédale de sortie du canton activée
          Affichage = true;
          while (digitalRead(Pedale_Sortie_X) == HIGH)
          {
            if (Affichage)
            {
              Serial.println("Attente: Pédale Pg2(X) activée");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("Action: Pédale Pg2(X) activée");
          Affichage = true;
          while (!BlockX.Reddition())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton L.2(X)");
              Affichage = false;
            }
          }
          Serial.println("(X)");
          Serial.println("-> Convoi réceptionné");
          // VoXant ANNONCE block X au Blanc (ou Eteint)
          Serial.println("VoXant: K.An2(X) -> Blanc (ou Eteint)");
          BlockX.Vt_Annonce();
          // VoXant REDDITION du block Y au Blanc (ou Eteint)
          Serial.println("VoXant: K.L1(Y) -> Blanc (ou Eteint)");
          BlockY.Vt_Reddition();
          // Activation de la sonnerie du block Y durant un temps défini
          Jouer_Son(2);
          Serial.println("Information: Sonnerie(Y) -> Marche -> Arrêt");
        }
        else
        {
          Serial.println("Action: L.S1(Y) en position (Normal)");
          Serial.println("Information: Sémaphore(Y) (Fermé)");
          Canton_Reserve = false;
        }
      }
      Canton_Reserve = false;
      Affichage = true;
    }
    else
    {
      Affichage = true;
    }
  }
}

void Jouer_Son(int Action)
{
  switch (Action)
  {
    case 0:
      // Arrêt de la cloche
      break;
    case 1:
      // Cloche active
      break;
    case 2:
      // Cloche active durant quelques secondes
      break;
    default:
      break;
  }
}

Fabrice Fayolle

Avatar du membre
FFayolle
Éloquent
Messages : 382
Enregistré le : mar. 09 mai 2006, 19:55
Localisation : Amiens, Somme, Picardie
Âge : 52

Re: BMVU

Message par FFayolle » lun. 09 sept. 2019, 17:44

Bonsoir,
Ayant enfin trouvé des LED bicolore Blanc/Vert, Blanc/Bleu et Blanc/Rouge, j'ai donc adapté le code.
Le site proposant des LED bicolore: https://www.pur-led.de/leuchtdioden/duo-led/
Des questions? Des commentaires ?
Fabrice

Code : Tout sélectionner

// Name
#define NAME  "BMVU"
#define NAME2 "Block Manuel de Voie Unique type SNCF (Appareil de block type Année 1960)"
#define NAME3 "IN1547 & SES317-954"

// Version & Copyright
#define VERSION "Version 2.1 (Arduino Mega)"
#define COPYRIGHT "Copyright Fabrice Fayolle, Août 2019"

// Caractéristiques du canton
// X - Canton - Y

// Arduino Mega
// Pin                  -> Utilisé pour                                     -> Connecté à
// 0
// 1
//..
// 4                    -> Position du levier du sémaphore X                  -> Extérieur (système de gestion des enclenchements)
// 5                    -> Verrou du levier du sémaphore X                    -> Extérieur (système de gestion des enclenchements)
// 6                    -> Pédale de voie d'entrée dans le canton (côté X)    -> Extérieur (système de détection)
// 7                    -> Pédale de voie de sortie du canton (côté X)        -> Extérieur (système de détection)
// 8                    -> Position du levier du sémaphore Y                  -> Extérieur (système de gestion des enclenchements)
// 9                    -> Verrou du levier du sémaphore Y                    -> Extérieur (système de gestion des enclenchements)
// 10                   -> Pédale de voie d'entrée (côté Y)                   -> Extérieur (système de détection)
// 11                   -> Pédale de voie de sortie (côté Y)                  -> Extérieur (système de détection)
// ..
// 22 à 32              -> Appareil de block X                                -> E/S (Bouton-poussoir & LED)
// ..
// 42 à 52              -> Appareil de block Y                                -> E/S (Bouton-poussoir & LED)

// Type de connexion
// Bouton-poussoir: Travail à GND (Rq: Entrée Arduino connectée au +5V avec une résistance de 10K (résistance Pull-Up))
// LED: Commun -

#define Normal HIGH
#define Renverse LOW

// Constantes et variables globales             // Equivalence 317.954_14
boolean Affichage = true;
const int Levier_Semaphore_X = 4;               // L.S1
const int Verrou_Levier_Semaphore_X = 5;
const int Pedale_Entree_X = 6;                  // B1
const int Pedale_Sortie_X = 7;                  // Pg2
const int Levier_Semaphore_Y = 8;
const int Verrou_Levier_Semaphore_Y = 9;
const int Pedale_Entree_Y = 10;
const int Pedale_Sortie_Y = 11;
boolean Canton_Reserve = false;
const unsigned long Delai_Ouverture_Verrou = 5000;

class Appareil
{
  private:
    int BN_BLOCAGE;                             // Blocage
    int BN_TEST;                                // T.1
    boolean REPONSE_ETAT;
    int VT_REPONSE_Position_normale;            // K.Rep1
    int VT_REPONSE_Reponse_au_test;             // K.Rep1
    int BN_ANNONCE;                             // An.1
    boolean REDDITION_ETAT;
    int VT_REDDITION_Voie_libre;                // K.L1
    int VT_REDDITION_Voie_occupee;              // K.L1
    int BN_REDDITION;                           // L1
    boolean ANNONCE_ETAT;
    int VT_ANNONCE_Aucun_train_annonce;         // K.An2
    int VT_ANNONCE_Train_annonce;               // K.An2
    int BN_SONNERIE;                            // ASn.An2
  public:
    void Setup(int indice);
    boolean Blocage();
    boolean Test();
    void Vt_Reponse();
    boolean Annonce();
    void Vt_Reddition();
    boolean Sonnerie();
    boolean Reddition();
    void Vt_Annonce();
}
;

void Appareil::Setup(int indice)
{
  BN_BLOCAGE = 2 + (indice * 20);
  pinMode(BN_BLOCAGE, INPUT_PULLUP);
  BN_TEST = 3 + (indice * 20);
  pinMode(BN_TEST, INPUT_PULLUP);
  REPONSE_ETAT = LOW;
  VT_REPONSE_Position_normale = 4 + (indice * 20);
  pinMode(VT_REPONSE_Position_normale, OUTPUT);
  digitalWrite(VT_REPONSE_Position_normale, HIGH);
  VT_REPONSE_Reponse_au_test = 5 + (indice * 20);
  pinMode(VT_REPONSE_Reponse_au_test, OUTPUT);
  digitalWrite(VT_REPONSE_Reponse_au_test, LOW);
  BN_ANNONCE = 6 + (indice * 20);
  pinMode(BN_ANNONCE, INPUT_PULLUP);
  REDDITION_ETAT = LOW;
  VT_REDDITION_Voie_libre = 7 + (indice * 20);
  pinMode(VT_REDDITION_Voie_libre, OUTPUT);
  digitalWrite(VT_REDDITION_Voie_libre, HIGH);
  VT_REDDITION_Voie_occupee = 8 + (indice * 20);
  pinMode(VT_REDDITION_Voie_occupee, OUTPUT);
  digitalWrite(VT_REDDITION_Voie_occupee, LOW);
  BN_REDDITION = 9 + (indice * 20);
  pinMode(BN_REDDITION, INPUT_PULLUP);
  ANNONCE_ETAT = LOW;
  VT_ANNONCE_Aucun_train_annonce = 10 + (indice * 20);
  pinMode(VT_ANNONCE_Aucun_train_annonce, OUTPUT);
  digitalWrite(VT_ANNONCE_Aucun_train_annonce, HIGH);
  VT_ANNONCE_Train_annonce = 11 + (indice * 20);
  pinMode(VT_ANNONCE_Train_annonce, OUTPUT);
  digitalWrite(VT_ANNONCE_Train_annonce, LOW);
  BN_SONNERIE = 12 + (indice * 20);
  pinMode(BN_SONNERIE, INPUT_PULLUP);
}

boolean Appareil::Blocage()
{
  boolean resultat = false;
  resultat = !digitalRead(BN_BLOCAGE);
  return resultat;
}

boolean Appareil::Test()
{
  boolean resultat = false;
  if (!digitalRead(BN_TEST))
  {
    delay(100);
    if (!digitalRead(BN_TEST))
    {
      Serial.print("Action: Appui sur le bouton T.1");
      while (!digitalRead(BN_TEST))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

void Appareil::Vt_Reponse()
{
  REPONSE_ETAT = !REPONSE_ETAT;
  digitalWrite(VT_REPONSE_Position_normale, !REPONSE_ETAT);
  digitalWrite(VT_REPONSE_Reponse_au_test, REPONSE_ETAT);
}

boolean Appareil::Annonce()
{
  boolean resultat = false;
  if (!digitalRead(BN_ANNONCE))
  {
    delay(100);
    if (!digitalRead(BN_ANNONCE))
    {
      Serial.print("Action: Appui sur le bouton An.1");
      while (!digitalRead(BN_ANNONCE))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

void Appareil::Vt_Annonce()
{
  ANNONCE_ETAT = !ANNONCE_ETAT;
  digitalWrite(VT_ANNONCE_Aucun_train_annonce, !ANNONCE_ETAT);
  digitalWrite(VT_ANNONCE_Train_annonce, ANNONCE_ETAT);
}

boolean Appareil::Sonnerie()
{
  boolean resultat = false;
  if (!digitalRead(BN_SONNERIE))
  {
    delay(100);
    if (!digitalRead(BN_SONNERIE))
    {
      Serial.print("Action: Appui sur le bouton Asn.An.2");
      while (!digitalRead(BN_SONNERIE))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}


boolean Appareil::Reddition()
{
  boolean resultat = false;
  if (!digitalRead(BN_REDDITION))
  {
    delay(100);
    if (!digitalRead(BN_REDDITION))
    {
      Serial.print("Action: Appui sur le bouton L.2");
      while (!digitalRead(BN_REDDITION))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

void Appareil::Vt_Reddition()
{
  REDDITION_ETAT = !REDDITION_ETAT;
  digitalWrite(VT_REDDITION_Voie_libre, !REDDITION_ETAT);
  digitalWrite(VT_REDDITION_Voie_occupee, REDDITION_ETAT);
}

Appareil BlockX;
Appareil BlockY;

void setup()
{
  Serial.begin(9600);
  Serial.println(NAME);
  Serial.println(NAME2);
  Serial.println(NAME3);
  Serial.println("---------------------------------------------------------------------------");
  Serial.print(VERSION); Serial.print(", "); Serial.println(COPYRIGHT);
  Serial.println("---------------------------------------------------------------------------");
  Serial.println("");
  pinMode(Levier_Semaphore_X, INPUT_PULLUP);
  pinMode(Verrou_Levier_Semaphore_X, OUTPUT);
  digitalWrite(Verrou_Levier_Semaphore_X, HIGH);
  pinMode(Pedale_Entree_X, INPUT_PULLUP);
  pinMode(Pedale_Sortie_X, INPUT_PULLUP);
  pinMode(Levier_Semaphore_Y, INPUT_PULLUP);
  pinMode(Verrou_Levier_Semaphore_Y, OUTPUT);
  digitalWrite(Verrou_Levier_Semaphore_Y, HIGH);
  pinMode(Pedale_Entree_Y, INPUT_PULLUP);
  pinMode(Pedale_Sortie_Y, INPUT_PULLUP);
  BlockX.Setup(1);
  BlockY.Setup(2);
  Serial.println("Information: Block Manuel de Voie Unique initialisé");
  Serial.println("");
  Serial.println("----------------------------------------------");
  Serial.println("X ---------------- CANTON ------------------ Y");
  Serial.println("----------------------------------------------");
}

void loop()
{
  unsigned long Horodatage;
  // Rq1: En voie unique, le block manuel est interrompu à la traversée des gares.
  // Rq2: Les manoeuvres effectuées en gare sont protégées par la fermeture du Disque (et non par le commutateur Blocage) obligeant le convoi entrant à se mettre en marche à vue
  // au plus tôt et à s'arrêter à la 1ère aiguille rencontrée
  if (Affichage)
  {
    Serial.println("");
    Serial.println("Attente: Appui sur un des boutons T.1()");
    Serial.println("");
    Affichage = false;
  }
  // Si l'Agent de circulation appuie sur le bouton TEST du block X alors
  if (BlockX.Test())
  {
    Serial.println("(X)");
    // Si rien ne s'y oppose alors
    if (BlockY.Blocage() == false)
    {
      Serial.println("-> Voie libre");
      Horodatage = millis();
      // Voyant REPONSE du block X au Vert
      Serial.println("Voyant: K.Rep1(X) -> Vert");
      BlockX.Vt_Reponse();
      // Possibilité d'ouvrir le sémaphore X durant "Delai_Ouverture_Verrou" millisecondes
      // Verrou du levier de manoeuvre du sémaphore X ouvert
      digitalWrite(Verrou_Levier_Semaphore_X, LOW);
      Serial.print("Information: Verrou du L.S1(X) (Ouvert) durant ");
      Serial.print(Delai_Ouverture_Verrou / 1000);
      Serial.println(" secondes");
      while (((millis() - Horodatage) < Delai_Ouverture_Verrou) && Canton_Reserve == false )
      {
        Canton_Reserve = !digitalRead(Levier_Semaphore_X);
        if (Canton_Reserve == true)
        {
          Serial.println("Action: L.S1(X) en position (Renversé)");
          Serial.println("Information: Sémaphore(X) (Ouvert)");
        }
        delay(100);
      }
      // Verrou du levier de manoeuvre du sémaphore X fermé
      digitalWrite(Verrou_Levier_Semaphore_X, HIGH);
      Serial.println("Information: Verrou du L.S1(X) (Fermé)");
      // Voyant REPONSE du block X au Blanc
      Serial.println("Voyant: K.Rep1(X) -> Blanc");
      BlockX.Vt_Reponse();
      // Si le sémaphore X a été ouvert durant le laps de temps défini alors
      if (Canton_Reserve == true)
      {
        // Attente de la l'activation de la pédale de voie d'entrée dans le canton
        // ou de la fermeture du sémaphore X (levier remis en position Normal)
        Affichage = true;
        while ((digitalRead(Pedale_Entree_X) == HIGH) && (digitalRead(Levier_Semaphore_X) == Renverse))
        {
          if (Affichage)
          {
            Serial.println("Attente: Pédale B1(X) activée ou L.S1(X) en position (Normal)");
            Affichage = false;
          }
          delay(100);
        }
        // Attente de la confirmation de la fermeture du sémaphore (levier remis en position Normal par l'Agent de circulation)
        if (digitalRead(Pedale_Entree_X) == LOW)
        {
          Serial.println("Information: Sémaphore(X) (Fermé) par aubinage");
          Serial.println("Information: Pédale B1(X) activée suite au passage du convoi");
          Affichage = true;
          while (digitalRead(Levier_Semaphore_X) == Renverse)
          {
            if (Affichage)
            {
              Serial.println("Attente: L.S1(X) en position (Normal)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("Information : L.S1(X) en position (Normal)");
          // Attente de l'annonce de X à Y par l'Agent de circulation (appui sur le bouton ANNONCE du block X)
          Affichage = true;
          while (!BlockX.Annonce())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton An.1(X)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("(X)");
          Serial.println("-> Convoi annoncé");
          // Voyant REDDITION du block X au Rouge
          Serial.println("Voyant: K.L1(X) -> Rouge");
          BlockX.Vt_Reddition();
          // Voyant ANNONCE du block Y passe au Bleu
          Serial.println("Voyant: K.An2(Y) -> Bleu");
          BlockY.Vt_Annonce();
          // Activation de la sonnerie du block Y tant que l'agent de circulation en Y n'appuie pas sur le bouton SONNERIE
          Jouer_Son(1);
          Serial.println("Information: Sonnerie(Y) -> Marche");
          Affichage = true;
          while (!BlockY.Sonnerie())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton ASn.An.2(Y)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("(Y)");
          Jouer_Son(0);
          Serial.println("Information: Sonnerie(Y) -> Arrêt");
          // Attente de la reddition de Y à X par l'Agent de circulation (appui sur le bouton REDDITION du block Y)
          // une fois la pédale de sortie du canton activée
          Affichage = true;
          while (digitalRead(Pedale_Sortie_Y) == HIGH)
          {
            if (Affichage)
            {
              Serial.println("Attente: Pédale Pg2(Y) activée");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("Action: Pédale Pg2(Y) activée");
          Affichage = true;
          while (!BlockY.Reddition())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton L.2(Y)");
              Affichage = false;
            }
          }
          Serial.println("(Y)");
          Serial.println("-> Convoi réceptionné");
          // Voyant ANNONCE block Y au Blanc
          Serial.println("Voyant: K.An2(Y) -> Blanc");
          BlockY.Vt_Annonce();
          // Voyant REDDITION du block X au Blanc
          Serial.println("Voyant: K.L1(X) -> Blanc");
          BlockX.Vt_Reddition();
          // Activation de la sonnerie du block X durant un temps défini
          Jouer_Son(2);
          Serial.println("Information: Sonnerie(X) -> Marche -> Arrêt");
        }
        else
        {
          Serial.println("Action: L.S1(X) en position (Normal)");
          Serial.println("Information: Sémaphore(X) (Fermé)");
          Canton_Reserve = false;
        }
      }
      Canton_Reserve = false;
      Affichage = true;
    }
    else
    {
      Serial.println("Information: Commutateur de blocage(Y) (Fermé)");
      Affichage = true;
    }
  }
  // Si l'Agent de circulation appuie sur le bouton TEST du block Y alors
  if (BlockY.Test())
  {
    Serial.println("(Y)");
    // Si rien ne s'X oppose alors
    if (BlockX.Blocage() == false)
    {
      Serial.println("-> Voie libre");
      Horodatage = millis();
      // VoXant REPONSE du block Y au Vert
      Serial.println("VoXant: K.Rep1(Y) -> Vert");
      BlockY.Vt_Reponse();
      // Possibilité d'ouvrir le sémaphore Y durant "Delai_Ouverture_Verrou" millisecondes
      // Verrou du levier de manoeuvre du sémaphore Y ouvert
      digitalWrite(Verrou_Levier_Semaphore_Y, LOW);
      Serial.print("Information: Verrou du L.S1(Y) (Ouvert) durant ");
      Serial.print(Delai_Ouverture_Verrou / 1000);
      Serial.println(" secondes");
      while (((millis() - Horodatage) < Delai_Ouverture_Verrou) && Canton_Reserve == false )
      {
        Canton_Reserve = !digitalRead(Levier_Semaphore_Y);
        if (Canton_Reserve == true)
        {
          Serial.println("Action: L.S1(Y) en position (Renversé)");
          Serial.println("Information: Sémaphore(Y) (Ouvert)");
        }
        delay(100);
      }
      // Verrou du levier de manoeuvre du sémaphore Y fermé
      digitalWrite(Verrou_Levier_Semaphore_Y, HIGH);
      Serial.println("Information: Verrou du L.S1(Y) (Fermé)");
      // VoXant REPONSE du block Y au Blanc
      Serial.println("VoXant: K.Rep1(Y) -> Blanc");
      BlockY.Vt_Reponse();
      // Si le sémaphore Y a été ouvert durant le laps de temps défini alors
      if (Canton_Reserve == true)
      {
        // Attente de la l'activation de la pédale de voie d'entrée dans le canton
        // ou de la fermeture du sémaphore Y (levier remis en position Normal)
        Affichage = true;
        while ((digitalRead(Pedale_Entree_Y) == HIGH) && (digitalRead(Levier_Semaphore_Y) == Renverse))
        {
          if (Affichage)
          {
            Serial.println("Attente: Pédale B1(Y) activée ou L.S1(Y) en position (Normal)");
            Affichage = false;
          }
          delay(100);
        }
        // Attente de la confirmation de la fermeture du sémaphore (levier remis en position Normal par l'Agent de circulation)
        if (digitalRead(Pedale_Entree_Y) == LOW)
        {
          Serial.println("Information: Sémaphore(Y) (Fermé) par aubinage");
          Serial.println("Information: Pédale B1(Y) activée suite au passage du convoi");
          Affichage = true;
          while (digitalRead(Levier_Semaphore_Y) == Renverse)
          {
            if (Affichage)
            {
              Serial.println("Attente: L.S1(Y) en position (Normal)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("Information : L.S1(Y) en position (Normal)");
          // Attente de l'annonce de Y à X par l'Agent de circulation (appui sur le bouton ANNONCE du block Y)
          Affichage = true;
          while (!BlockY.Annonce())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton An.1(Y)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("(Y)");
          Serial.println("-> Convoi annoncé");
          // VoXant REDDITION du block Y au Rouge
          Serial.println("VoXant: K.L1(Y) -> Rouge");
          BlockY.Vt_Reddition();
          // VoXant ANNONCE du block X passe au Bleu
          Serial.println("VoXant: K.An2(X) -> Bleu");
          BlockX.Vt_Annonce();
          // Activation de la sonnerie du block X tant que l'agent de circulation en X n'appuie pas sur le bouton SONNERIE
          Jouer_Son(1);
          Serial.println("Information: Sonnerie(X) -> Marche");
          Affichage = true;
          while (!BlockX.Sonnerie())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton ASn.An.2(X)");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("(X)");
          Jouer_Son(0);
          Serial.println("Information: Sonnerie(X) -> Arrêt");
          // Attente de la reddition de X à Y par l'Agent de circulation (appui sur le bouton REDDITION du block X)
          // une fois la pédale de sortie du canton activée
          Affichage = true;
          while (digitalRead(Pedale_Sortie_X) == HIGH)
          {
            if (Affichage)
            {
              Serial.println("Attente: Pédale Pg2(X) activée");
              Affichage = false;
            }
            delay(100);
          }
          Serial.println("Action: Pédale Pg2(X) activée");
          Affichage = true;
          while (!BlockX.Reddition())
          {
            if (Affichage)
            {
              Serial.println("Attente: Appui sur le bouton L.2(X)");
              Affichage = false;
            }
          }
          Serial.println("(X)");
          Serial.println("-> Convoi réceptionné");
          // VoXant ANNONCE block X au Blanc
          Serial.println("VoXant: K.An2(X) -> Blanc");
          BlockX.Vt_Annonce();
          // VoXant REDDITION du block Y au Blanc
          Serial.println("VoXant: K.L1(Y) -> Blanc");
          BlockY.Vt_Reddition();
          // Activation de la sonnerie du block Y durant un temps défini
          Jouer_Son(2);
          Serial.println("Information: Sonnerie(Y) -> Marche -> Arrêt");
        }
        else
        {
          Serial.println("Action: L.S1(Y) en position (Normal)");
          Serial.println("Information: Sémaphore(Y) (Fermé)");
          Canton_Reserve = false;
        }
      }
      Canton_Reserve = false;
      Affichage = true;
    }
    else
    {
      Serial.println("Information: Commutateur de blocage(X) (Fermé)");
      Affichage = true;
    }
  }

}

void Jouer_Son(int Action)
{
  switch (Action)
  {
    case 0:
      // Cloche -> Arrêt
      break;
    case 1:
      // Cloche - > Marche
      break;
    case 2:
      // Cloche -> Marche -> Arrêt
      break;
    default:
      break;
  }
}
Fabrice Fayolle

Répondre