Page 4 sur 5

Re: Block système manuel de voie unique

Posté : 22 août 2019, 23:35
par ffayolle
Bonsoir,

Après quelques tests et quelques corrections, le code est maintenant fonctionnel.
A me répéter, le moniteur Série est d'une très grande utilité pour corriger et valider.
J'ai utilisé une carte Arduino MEGA afin de ne pas être limité par le nombre d'E/S.

:merci: encore à Eiffel pour la formation et à Jean-Marc pour les informations et photographies

Il me reste à traiter les points suivants (sur l'aspect fonctionnel):
-Copier le code "en symétrie" pour gérer le test en Block Y
-Gérer le voyant blanc associé à chaque voyant de couleur
-Gérer la cloche et le bouton sonnerie associé
-Documenter encore plus le code
-Optimiser le code

A suivre...

Fabrice

Code : Tout sélectionner

// Name
#define NAME  "BMVU"
#define NAME2 "Block Manuel de Voie Unique type SNCF"
#define NAME3 "IN1547 (Règlement S5C) - Articles 101.4 et 102"

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

boolean Affichage1 = true;
boolean Affichage2 = true;

const int Levier_SemaphoreX_Normal = 4;
const int Verrou_Levier_SemaphoreX = 5;
const int PedaleX_Non_Active = 6;
const int Levier_SemaphoreY_Normal = 7;
const int Verrou_Levier_SemaphoreY = 8;
const int PedaleY_Non_Active = 9;

class Appareil
{
  private:
    int BN_BLOCAGE;
    int BN_ANNONCE;
    boolean VT_ANNONCE_ETAT;
    int VT_ANNONCE;
    int BN_REDDITION;
    boolean VT_REDDITION_ETAT;
    int VT_REDDITION;
    int BN_TEST;
    boolean VT_TEST_ETAT;
    int VT_TEST;
    int BN_SONNERIE;
    int CLOCHE;
  public:
    boolean SEMAPHORE_OUVERT;
    void Setup(int indice);
    boolean Blocage();
    boolean Test();
    boolean Voielibre();
    void Vt_Test();
    boolean Annonce();
    boolean Reddition();
    void Vt_Annonce();
    void Vt_Reddition();
    void Cloche_Block(int etat);
}
;

void Appareil::Setup(int indice)
{
  BN_BLOCAGE = 2 + (indice * 20);
  pinMode(BN_BLOCAGE, INPUT_PULLUP);
  BN_ANNONCE = 3 + (indice * 20);
  pinMode(BN_ANNONCE, INPUT_PULLUP);
  VT_ANNONCE_ETAT = LOW;
  VT_ANNONCE = 4 + (indice * 20);
  pinMode(VT_ANNONCE, OUTPUT);
  digitalWrite(VT_ANNONCE, LOW);
  BN_REDDITION = 5 + (indice * 20);
  pinMode(BN_REDDITION, INPUT_PULLUP);
  VT_REDDITION_ETAT = LOW;
  VT_REDDITION = 6 + (indice * 20);
  pinMode(VT_REDDITION, OUTPUT);
  digitalWrite(VT_REDDITION, LOW);
  BN_TEST = 7 + (indice * 20);
  pinMode(BN_TEST, INPUT_PULLUP);
  VT_TEST_ETAT = LOW;
  VT_TEST = 8 + (indice * 20);
  pinMode(VT_TEST, OUTPUT);
  digitalWrite(VT_TEST, LOW);
  BN_SONNERIE = 9 + (indice * 20);
  pinMode(BN_SONNERIE, INPUT_PULLUP);
  SEMAPHORE_OUVERT = LOW;
  CLOCHE = 10 + (indice * 20);
  pinMode(CLOCHE, OUTPUT);
  digitalWrite(CLOCHE, LOW);
}

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.println("Appui du bouton TEST");
      while (!digitalRead(BN_TEST))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

boolean Appareil::Voielibre()
{
  boolean resultat = false;
  if (!VT_TEST_ETAT && !VT_ANNONCE_ETAT && !VT_REDDITION_ETAT && !SEMAPHORE_OUVERT)
  {
    resultat = true;
  }
  return resultat;
}

void Appareil::Vt_Test()
{
  VT_TEST_ETAT = !VT_TEST_ETAT;
  digitalWrite(VT_TEST, VT_TEST_ETAT);
}

boolean Appareil::Annonce()
{
  boolean resultat = false;
  if (!digitalRead(BN_ANNONCE))
  {
    delay(100);
    if (!digitalRead(BN_ANNONCE))
    {
      Serial.println("Appui du bouton ANNONCE");
      while (!digitalRead(BN_ANNONCE))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

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

boolean Appareil::Reddition()
{
  boolean resultat = false;
  if (!digitalRead(BN_REDDITION))
  {
    delay(100);
    if (!digitalRead(BN_REDDITION))
    {
      Serial.println("Appui du bouton REDDITION");
      while (!digitalRead(BN_REDDITION))
      {
      }
      resultat = true;
    }
  }
  return resultat;
}

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

void Cloche_Block(int etat)
{
  switch (etat)
  {
    case 0:
      //Arrêt de la sonnerie
      break;
    case 1:
      //Sonnerie (1 lecture)
      break;
    case 2:
      //Sonnerie (x lectures)
      break;
    default:
      break;
  };
}

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_SemaphoreX_Normal, INPUT_PULLUP);
  pinMode(Verrou_Levier_SemaphoreX, OUTPUT);
  digitalWrite(Verrou_Levier_SemaphoreX, HIGH);
  pinMode(PedaleX_Non_Active, INPUT_PULLUP);
  pinMode(Levier_SemaphoreY_Normal, INPUT_PULLUP);
  pinMode(Verrou_Levier_SemaphoreY, OUTPUT);
  digitalWrite(Verrou_Levier_SemaphoreY, HIGH);
  pinMode(PedaleY_Non_Active, INPUT_PULLUP);
  BlockX.Setup(1);
  BlockY.Setup(2);
  Serial.println("Block Manuel de Voie Unique initialisé");
}

void loop()
{
  unsigned long Temps;
  //Tant qu'un commutateur Blocage est fermé sur un des deux appareils de block, aucun convoi ne peut-être expédié ou réceptionné
  //Mise en protection par au moins une des deux extrémités du block (travaux, dérangement, ...)
  //Rq: Les manoeuvres effectuées en gare sont protégés par la fermeture du Disque obligeant le convoi entrant à se mettre en marche à vue
  //au plus tôt et à s'arrêter à la 1ère aiguille rencontrée
  Affichage1 = true;
  while (BlockX.Blocage() || BlockY.Blocage())
  {
    if (Affichage1)
    {
      Serial.println("Commutateur BLOCAGE d'un des deux appareils de block fermé");
      Affichage1 = false;
      Affichage2 = true;
    }
    delay(250);
  }
  if (Affichage2)
  {
    Serial.println("Attente d'un test");
    Affichage2 = false;
  }
  // Si l'Agent de circulation appuie sur le bouton TEST du block X alors
  if (BlockX.Test())
  {
    // Si rien ne s'y oppose (Voie libre de X vers Y et Voie libre de Y vers X) alors
    if (BlockX.Voielibre() && BlockY.Voielibre())
    {
      Serial.println("Voie libre");
      Temps = millis();
      //Voyant TEST du block X passe au Vert
      BlockX.Vt_Test();
      //Possibilité d'ouvrir le sémaphore X durant 5 secondes (5000 millisecondes)
      //Verrou du levier de manoeuvre du sémaphore X ouvert
      digitalWrite(Verrou_Levier_SemaphoreX, LOW);
      Serial.println("Verrou du levier de manoeuvre du sémaphore ouvert");
      while (((millis() - Temps) < 5000) && BlockX.SEMAPHORE_OUVERT == LOW )
      {
        BlockX.SEMAPHORE_OUVERT = !digitalRead(Levier_SemaphoreX_Normal);
        delay(100);
      }
      //Voyant Test du block X passe au blanc (ou éteint)
      BlockX.Vt_Test();
      if (BlockX.SEMAPHORE_OUVERT)
      {
        Serial.println("Manoeuvre du levier du sémaphore");
      }
      //Verrou du levier de manoeuvre du sémaphore X ouvert
      digitalWrite(Verrou_Levier_SemaphoreX, HIGH);
      Serial.println("Verrou du levier de manoeuvre du sémaphore fermé");
      //Si le sémaphore X a été ouvert durant le laps de temps défini alors
      if (BlockX.SEMAPHORE_OUVERT)
      {
         Serial.println("Sémaphore ouvert");
        // Attente de la l'activation de la pédale de voie (canton occupé)
        // ou de la fermeture du sémaphore X (levier remis en position Normal)
        Affichage1 = true;
        while ((digitalRead(PedaleX_Non_Active) == HIGH) && (digitalRead(Levier_SemaphoreX_Normal) == LOW))
        {
          if (Affichage1)
          {
            Serial.println("Attente de l'activation de la pédale de voie ou de la fermeture manuelle du sémaphore");
            Affichage1 = 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(PedaleX_Non_Active) == LOW)
        {
          Serial.println("Pédale de voie activée");
          Serial.println("Sémaphore fermé (aubinage)");
          Affichage1 = true;
          while (digitalRead(Levier_SemaphoreX_Normal) == LOW)
          {
            if (Affichage1)
            {
              Serial.println("Attente de la confirmation de la fermeture du sémaphore");
              Affichage1 = false;
            }
          }
          Serial.println("Manoeuvre du levier du sémaphore");
          // Attente de l'annonce de X à Y par l'Agent de circulation (appui sur le bouton ANNONCE du block X)
          Affichage1 = true;
          while (!BlockX.Annonce())
          {
            if (Affichage1)
            {
              Serial.println("Attente de l'annonce");
              Affichage1 = false;
            }
          }
          Serial.println("Convoi annoncé");
          //Voyant REDDITION du block X passe au rouge
          BlockX.Vt_Reddition();
          //Voyant ANNONCE du block Y passe au 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
          // Attente de la reddition de Y à X par l'Agent de circulation (appui sur le bouton REDDITION du block Y)
          Affichage1 = true;
          while (!BlockY.Reddition())
          {
            if (Affichage1)
            {
              Serial.println("Attente de la reddition");
              Affichage1 = false;
            }
          }
          Serial.println("Convoi réceptionné");
          //Voyant ANNONCE du block Y passe au blanc (ou s'éteint)
          BlockY.Vt_Annonce();
          //Voyant REDDITION du block X passe au blanc (ou s'éteint)
          BlockX.Vt_Reddition();
          // Activation de la sonnerie du block X durant un temps défini
        }
        else
        {
          Serial.println("Manoeuvre du levier du sémaphore");
          Serial.println("Sémaphore fermé");
          BlockX.SEMAPHORE_OUVERT=LOW;
        }
      }
      Affichage2 = true;
    }
  }
  if (BlockY.Test())
  {
    // Symétrie de "if (BlockX.Test())
  }
}

Re: Block système manuel de voie unique

Posté : 23 août 2019, 08:33
par ffayolle
Bonjour,
La nuit portant conseil, une question aux spécialistes:
Contexte: Le test validé en X, le sémaphore X a été ouvert.
Question: doit-on dérouler toute la séquence (aubinage, confirmation de fermeture, annonce,...) ou peut-on refermer manuellement le sémaphore si aucun convoi ne se présente?
Fabrice

Re: Block système manuel de voie unique

Posté : 23 août 2019, 09:46
par Suppr sur demande
Bonjour @ tous,

Joli code Fabrice :applause1:

Re: Block système manuel de voie unique

Posté : 23 août 2019, 17:18
par Eiffel
A priori, sauf particularité locale, et après avoir appliqué le temps moral, rien ne doit s'opposer à une refermeture manuelle du signal.

Re: Block système manuel de voie unique

Posté : 24 août 2019, 09:00
par ffayolle
Le temps moral...
3 mn en VP / 1mn en VS

L'utilisation d'un appareil de block étant maintenant connue, il me faut connaître l'arrière du décor, "décortiquer" en fait l'appareil pour modéliser parfaitement son fonctionnement.

D'avance merci pour les informations que vous auriez sur le sujet

Fabrice

Re: Block système manuel de voie unique

Posté : 25 août 2019, 09:58
par ffayolle
Bonjour,

J'ai obtenu sur le forum d'en face (merci à EC64) d'une part la description de la phase de test
1.jpg
et d'autre part le schéma électrique d'un appareil de block type année 1960.
14.jpg
Ce dernier confirme la présence de dispositifs adhoc (pédale de voie). De quoi revoir l'aspect fonctionnel (le programme).

Et j'ai validé une fois tous les composants électroniques reçus (et donc validation des empreintes et des gabarits de perçage) l'aspect visuel (la face avant).
L'infographie
BMVU-FA-Infographie.jpg
BMVU-FA-Infographie.jpg (24.71 Kio) Vu 3009 fois
Le gabarit de perçage
BMVU-FA-Percage.jpg
BMVU-FA-Percage.jpg (11.18 Kio) Vu 3009 fois
A suivre...

Fabrice

Re: Block système manuel de voie unique

Posté : 25 août 2019, 15:50
par JeanMarc
Bonjour à tous,

Jolie travail ! :bravo:

Concernant la refermeture du sémaphore de sortie c'est tout à fait possible avec l'organe de commande du signal. (les seuls enclenchements de parcours que j'ai pu voir dans mes gares de VU agissait sur les disques d'entrée, et encore, pas partout! :) )
Par contre en cas d'expédition après une refermeture d'un sémaphore de sortie, il faut refaire le "test" avant de commander son ouverture.

Bonne soirée à tous !

Re: Block système manuel de voie unique

Posté : 26 août 2019, 11:23
par ffayolle
Bonjour,

et :merci: Jean-Marc

Le code a donc été modifié en conséquence.

Histoire de, voilà quelques copies d'écran (Moniteur Série) pour mieux comprendre le fonctionnement.

Pas de commutateur de blocage fermé + Test positif + Levier du Sémaphore non manœuvré dans le délai imparti
2019-08-26_111259.png
Pas de commutateur de blocage fermé + Test positif + Levier du Sémaphore manœuvré dans le délai imparti + Pédale de voie d'entrée dans le canton activée + Confirmation de la fermeture du sémaphore
2019-08-26_111422.png
Séquence complète

Code : Tout sélectionner

Action: Appui sur le bouton T.1(X)
-> Voie libre
Voyant: K.Rep1(X) -> Vert
Information: Verrou du L.S1(X) (Ouvert) durant 5 secondes
Action: L.S1(X) en position (Renversé)
Information: Sémaphore(X) (Ouvert)
Information: Verrou du L.S1(X) (Fermé)
Voyant: K.Rep1(X) -> Blanc (ou Eteint)
Attente: Pédale B1(X) activée ou L.S1(X) en position (Normal)
Information: Sémaphore(X) (Fermé) par aubinage
Information: Pédale B1(X) activée suite au passage du convoi
Attente: L.S1(X) en position (Normal)
Information : L.S1(X) en position (Normal)
Attente: Appui sur le bouton An.1(X)
Action: Appui sur le bouton An.1(X)
-> Convoi annoncé
Voyant: K.L1(X) -> Rouge
Voyant: K.An2(Y) -> Bleu
Information: Sonnerie(Y) -> Marche
Attente: Appui sur le bouton ASn.An.2(Y)
Action: Appui sur le bouton Asn.An.2(Y)
Information: Sonnerie(Y) -> Arrêt
Attente: Pédale Pg2(Y) activée
Action: Pédale Pg2(Y) activée
Attente: Appui sur le bouton L.2(Y)
Action: Appui sur le bouton L.2(Y)
-> Convoi réceptionné
Voyant: K.An2(Y) -> Blanc (ou Eteint)
Voyant: K.L1(X) -> Blanc (ou Eteint)
Information: Sonnerie(X) -> Marche -> Arrêt
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.

A suivre...

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("Information: 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("Information: 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;
  }
}


Re: Block système manuel de voie unique

Posté : 29 août 2019, 13:30
par ffayolle
Bonjour,
Les faces avant sont en cours de réalisation. Il n'y aura plus qu'à!!!
A suivre...
Mais d'ici là, si on faisait maintenant la version italienne:

Fabrice

Re: Block système manuel de voie unique

Posté : 08 sept. 2019, 20:22
par ffayolle
Bonsoir,
Vous allez rire mais en cherchant des LED bicolores, je n'ai trouvé que Rouge/Blanc ou Rouge/Vert. Auriez-vous connaissance de l'existence de LED bicolore Bleu/Blanc et Vert/Blanc?
D'avance merci
Fabrice