Un éminent membre de mon club butait depuis un certain temps sur un automatisme de passage à niveau à partir d’une logique à relais.
Il faut dire que ce passage supporte une double voie, dont une branche est en "Y". Le cahier des charges impose de ne lever les barrières que lorsque toute la zone est libre de trains.
J’ai décidé de relever le défi avec un Arduino et d’ajouter un ultime raffinement : le clignotement réaliste des feux rouges (coté route) à leds.
Voici les détails de la réalisation que vous pourrez certainement adapter à votre réseau.
Le cahier des charges
Le passage à niveau doit protéger une double voie, dont l’une des branches est en "Y". Il y a donc 5 sections de voies de part et d’autre du passage à niveau.
Sur chaque branche, sont disposés 2 détecteurs de type interrupteur à lame souple, "ILS".
Il y en a donc 10 au total.
Le plus proche du passage à niveau doit déclencher la fermeture des barrières lorsque le train va vers le passage.
Le plus éloigné du passage à niveau doit déclencher l’ouverture des barrières lorsque le train s’éloigne du passage. Attention toutefois, les barrières ne doivent pas s’ouvrir tant qu’il reste un autre train dans la zone comprise entre tous les détecteurs éloignés.
Tant que les barrières ne sont pas complètement ouvertes, les feux rouges de chaque coté, sur la route doivent clignoter. Comme dans la réalité, ce sont des lampes à incandescence qui s’allume et s’éteignent avec une certaine inertie, on reproduira cette inertie sur des Leds rouges, gräce aux commandes analogiques.
Enfin, l’ouverture et la fermeture des barrières est opéré par un moteur Fulgurex livré avec le passage à niveau. Ce moteur devra donc être alimenté dans un sens ou dans l’autre pendant 4 à 5 secondes environ. Les feux restent donc en service pendant cette manoeuvre.
Le matériel nécessaire
Compte tenu de ce cahier des charges, un Arduino Mini suffira. L’absence de port USB est compensée par le fait que je dispose d’interface "Bob" d’Elektor qui se raccordent facilement sur le Mini dont les pins sont sur un des petits cotés. On trouve également sur le web des interfaces USB-serie pour presque rien. Dernièrement j’ai même trouvé un Arduino Mini avec l’interface USB-série séparée, le tout pour 6€ environ (avec le chip original FT232 de FTDI).
Attention : il faut bien relier la sortie TxD de l’interface USB avec l’entrée RxD du Mini, ainsi que la sortie TxD du Mini avec l’entrée RxD de l’interface USB. Ensuite on relie le Vcc au Vcc, le Gnd au Gnd et la sortie DTR de l’interface USB à la patte marquée GRN sur le Mini (c’est ce qui permet à l’IDE Arduino de passer le Mini en mode programmation).
Les ILS sont raccordés directement sur 10 pins de l’Arduino, les communs des ILS étant regroupés sur le 0V.
Les feux sont réalisés avec 2 Leds rouges en série, sur une pin analogique (à sortie en PWM) du Mini.
Les commandes du moteur sont faites avec une carte à 2 relais qui se pilote par 2 sorties du Mini. J’ai choisi 2 pins analogiques, utilisées en digital.
Pour alimenter l’Arduino, les Leds et les relais, j’ai réalisé une petite alimentation régulée par un 7805, avec un pont de diode et quelques condensateurs. J’ai préféré cela au régulateur embarqué dans le Mini, qui me semble un peu sous-dimensionné pour alimenter les relais et les Leds.
Au total, on peut s’en sortir avec 10€ de matériel, sans les ILS ni le passage à niveau.
Le schéma
Sur ce schéma, la carte à 2 relais est représentée par seulement 2 relais, n’ayant pas le dessin de l’élément acheté qui se raccorde par 4 contacts : relai 1, relai 2, 5V et 0V.
La source d’alimentation est prise sur celle du moteur Fulgurex. Comme sa tension peut être comprise entre 8 et 15 volts, le régulateur externe 7805 tiendra bien le choc (la tension maximum est de 40V au lieu de 12V pour un Arduino Mini).
La réalisation
Une planchette en bois sert de support direct aux composants. Elle permet un étiquetage clair des connexions.
Petite anecdote : Lors d’un essai précédent, avant l’ajout de la petite alimentation 5V, j’avais utilisé le régulateur intégré de l’Arduino Mini. Résultat d’une erreur : le régulateur intégré est parti en fumée. Mais tout le reste de l’Arduino est intact : quel chance, mais aussi quelle robustesse ! C’est pour cela qu’on peut voir une zone noircie sur le Mini. Depuis, j’ai refait le montage avec un Mini tout neuf.
Les dominos ordinaires aurait pu être avantageusement remplacés par cette superbe plaque à borniers.
Le programme
C’est la partie la plus intéressante du projet !
Je précise tout de suite que ce n’est pas le meilleur programme possible : il ne couvre pas tous les cas possibles. Ca se coince parfois lors de manoeuvres spéciales.
Mais c’est un programme convenable pour les cas ordinaires et assez simple à comprendre pour les débutants.
Nous verrons plus loin que cet article aura une suite, justement pour explorer un peu plus cet automate qui n’est pas si trivial que ça en a l’air.
On commence donc par la déclaration des ports d’entrée et sortie :
// Pins utilisées pour les connexions aux detecteurs Reed
#define ReedA1 2 //RA1 = O1-29G
#define ReedB1 3 //RB1 = F1-29G
#define ReedC1 4 //RB2 = F1-29D
#define ReedD1 5 //RD2 = O1-29D
#define ReedA2 6 //RA2 = O2-30G
#define ReedB2 7 //RB2 = F2-30G
#define ReedC2 8 //RC2 = F2-3031D
#define ReedD2 9 //RD2 = O2-3031D
#define ReedA3 A2 //RA3 = O2-31G
#define ReedB3 A3 //RB3 = F2-31G
// Pins utilisées pour la Led et le PAN
#define LED 13 // on board
#define Feux 11 // PWM ou digital OUT
#define PANPWM 12 // not used
#define PAN1 A0 //digital OUT IN2 relai
#define PAN2 A1 //digital OUT IN1 relai
#define PANMOVE 5000 // duree d'activation du moteur Fulgurex
Puis, pour éviter tout problème de contact au niveau des ILS, on utilise intensivement la bibliothèque Bounce.
// Variables
boolean RA1, RA2, RB1, RB2, RC1, RC2, RD1, RD2, RA3, RB3 = false;
int etat1, etat2 = 0; // libre
boolean dir1, dir2 = false;
boolean etat_PAN = true; // true=ouvert, false=fermé
unsigned long TimerFeux, TimerPAN;
int fadeValue; // valeur variable de la durée du fading des feux
int fading = 10; // 10 croit/decroit ou 1000 allume/eteint
int cycle = 0; // 0 eteint, 1 croit, 2 allumé, 3 decroit
int panValue = PANMOVE; //durée impulsion ouverture et fermeture pour Fulgurex
boolean Fulgurex = false; // true seulement pour envoyer le courant au moteur
A ce stade, j’avoue que la déclaration de plusieurs variables de même type sur la même ligne avec la dernière = 0, n’entraine pas nécessairement que la première (et les autres) soient aussi = 0
La gestion du moteur Fulgurex (ouverture ou fermeture) pendant le temps défini par PANMOVE
Détections des ILS
Chaque détection est faite par la bibliothèque Bounce et entraîne une action spécifique à chaque ILS.
// Update the debouncer
bounceA1.update ( );
bounceB1.update ( );
bounceC1.update ( );
bounceD1.update ( );
bounceA2.update ( );
bounceB2.update ( );
bounceC2.update ( );
bounceD2.update ( );
bounceA3.update ( );
bounceB3.update ( );
// Une transition de HIGH à LOW entraine une action (fonction)
if ( bounceA1.fell() ) {
action1();
}
if ( bounceB1.fell() ) {
action2();
}
if ( bounceC1.fell() ) {
action3();
}
if ( bounceD1.fell() ) {
action4();
}
if ( bounceA2.fell() ) {
action5();
}
if ( bounceA3.fell() ) {
action5();
}
if ( bounceB2.fell() ) {
action6();
}
if ( bounceB3.fell() ) {
action6();
}
if ( bounceC2.fell() ) {
action7();
}
if ( bounceD2.fell() ) {
action8();
}
On notera que les actions pour la branche déviée de l’"Y" sont les même que celles de la branche droite.
On verra le contenu de ces actions un peu plus loin.
L’automate des feux
Il est bien évidemment interdit d’utiliser l’instruction delay().
L’astuce consiste à détecter l’écoulement d’un laps de temps défini par la variable "fading" et à invoquer le fonction FeuxON(). C’est cette dernière qui réalise l’automate par une série d’états associés chacun à une valeur particulière de"fading", ce que nous verrons plus loin.
Cette petite partie fait simplement avancer l’automate FeuxON() à chaque période définie par la variable fading dont la valeur change dans l’automate.
On peut obtenir ainsi un comportement sophistiqué de manière simple.
L’automate du moteur de barrière
Du même principe, il stoppe le moteur à la fin d’une tempo initialisée dans une des actions liées aux détections d’ILS.
// commande de barrière (impulsion de duree panValue)
if (Fulgurex)
{
FeuxON(); // le feu reste allume pendant la manoeuvre
if ((TimerPAN + panValue) < millis()) // depassement timer
{
Fulgurex = false;
digitalWrite(PAN2, HIGH); // arret relais Fulgurex
digitalWrite(PAN1, HIGH);
if (etat_PAN)
{
FeuxOFF(); // extinction feu à la fin de l'ouverture
}
}
}
On notera que le feu rouge pour les voitures doit rester allumé pendant la manœuvre de la barrière.
Les actions en réponse aux détections ILS
L’état libre ou occupé des voies est représenté par les variables état1 et état2.
Pour tenir compte de la possibilité de la présence de plusieurs trains dans la zone, chaque entrée de train se traduit par l’incrémentation de la variable étatx.
La sortie des trains, par symétrie, se fait par décrémentation de cette variable.
Il faut qu’elle passe à zéro pour constater que la zone est libre !
void action1() // detecteur loin a gauche du PaN voie 1
{
/*- RA1 - O1-29G
-> si etat1=false, alors etat1=true, dir1=ADroite (entrée par la gauche de la voie 1, direction vers droite)
-> si etat1=true, alors etat1=false, (sortie par la gauche de la voie 1)
et -> si etat2=false (voie 2 libre), alors etat_PAN=ouvert (ouverture PAN autorisée)
*/
if (etat1 == 0) // etat libre, entrée par la gauche voie 1
{
etat1++; // voie 1 occupée
dir1=true; // vers la droite
} else { // sinon pas libre donc c'est une sortie vers la gauche
// ou une autre entree par la gauche
if (!dir1) // sortie
{
if (etat1 > 0)
{
etat1--; // voie 1 libre
}
} else { // entree
etat1++;
dir1=true;
}
if ((etat1 == 0) && (etat2 == 0)) // si voies 1 et 2 libres
{
etat_PAN=true; // ouverture si l'autre voie est libre
FeuxON();
OuvreBarriere();
}
}
}
/////////////////////
void action2() // detecteur pres à gauche du PaN voie 1
{
// RB1 - F1-29G
// -> si etat1>0 et dir1=ADroite alors etat_PAN = ferme (fermeture PAN)
if (etat1 && dir1 && etat_PAN) // vers la droite 2e détecteur à gauche du PaN
{
etat_PAN=false; // fermeture
FeuxON();
FermeBarriere();
}
}
/////////////////////
void action3() // detecteur près à droite du PaN voie 1
{
//- RC1 - F1-29D
// -> si etat1>0 et dir1=AGauche alors etat_PAN = ferme (fermeture PAN)
if (etat1 && !dir1 && etat_PAN) // vers la gauche 2e détecteur à droite du PaN
{
etat_PAN=false; // fermeture
FermeBarriere();
FeuxON();
}
}
/////////////////////
void action4() // detecteur loin a droite du PaN voie 1
{
/*- RD1 - O1-29D
-> si etat1=false, alors etat1=true, dir1=AGauche (entrée par la droite de la voie 1, direction vers gauche)
-> si etat1=true, alors etat1=false (sortie par la droite de la voie 1)
et si etat2=false (voie 2 libre), alors etat_PAN=ouvert (ouverture PAN)
*/
if (etat1 == 0) // etat libre, entrée par la droite voie 1
{
etat1++; // voie 1 occupee
dir1=false; // vers la gauche
} else { // sinon pas libre donc c'est une sortie vers la droite
// ou une nouvelle entree par le droite
if (dir1) // sortie
{
if (etat1 > 0)
{
etat1--;
}
} else { // sinon entree
etat1++;
dir1=false;
}
if ((etat1==0) && (etat2==0))
{
etat_PAN=true;
FeuxON();
OuvreBarriere();
}
}
}
/////////////////////
void action5()
{
/*- RA2 ou RA3
- O2-30G -> si etat2=false, alors etat2=true, dir2=ADroite (entrée par la gauche de la voie 2, direction vers droite)
- O2-31G -> si etat2=true alors etat2=false (sortie par la gauche de la voie 2)
et -> si etat1=false (voie 1 libre), alors etat_PAN=ouvert (ouverture PAN)
*/
if (etat2 == 0) // voie 2 libre, entree par la gauche
{
etat2++;
dir2=true;
} else { // sinon pas libre donc c'est une sortie vers la gauche
// ou nouvelle entree par la gauche
if (!dir2) // sortie
{
if (etat2 > 0)
{
etat2--;
}
} else { // sinon entree
etat2++;
dir2=true;
}
if ((etat1==0) && (etat2==0))
{
etat_PAN=true;
OuvreBarriere();
}
}
}
/////////////////////
void action6()
{
//- RB2 ou RB3 - F2-30G ou F2-31G
// -> si etat2=true et dir2=ADroite alors etat_PAN = ferme (fermeture PAN)
if (etat2 && dir2 && etat_PAN)
{
etat_PAN=false;
FeuxON();
FermeBarriere();
}
}
/////////////////////
void action7()
{
//- RC2 - F2-3031D
// -> si etat2=true et dir2=AGauche alors etat_PAN = ferme (fermeture PAN)
if (etat2 && !dir2 && etat_PAN)
{
etat_PAN=false;
FeuxON();
FermeBarriere();
}
}
/////////////////////
void action8()
{
/*- RD2
- O2-3031D
-> si etat2=0, alors etat2=true, dir2=AGauche (entrée par la droite de la voie 2, direction vers gauche)
-> si etat2=true alors etat2=false (sortie par la droite de la voie 2 et )
et -> si etat1=false (voie 1 libre), alors etat_PAN=ouvert (ouverture PAN)
*/
if (etat2 == 0) //entree par la droite, direction vers gauche
{
etat2++;
dir2=false;
} else { // sinon sortie vers la droite
// ou nouvelle entree
if (dir2)
{
if (etat2 > 0)
{
etat2--;
}
} else {
etat2++;
dir2=false;
}
if ((etat1==0) && (etat2==0))
{
etat_PAN=true;
FeuxON();
OuvreBarriere();
}
}
}
Les fonctions d’ouverture et fermeture de la barrière
Le fait de passer la variable Fulgurex à true va démarrer le décomptage du temps dans la loop.
On trouvera dans le document joint le code complet du passage à niveau.
Dans ce code j’ai ajouté une fonction de DEBUG qui utilise la console de l’IDE Arduino pour afficher un message à chaque événement et l’état des principales variables.
Il y a aussi une possibilité de simuler les détections d’ILS en tapant des chiffres au clavier.
On peut faire disparaître du code l’ensemble de la fonction de DEBUG en mettant la définition au début en commentaire.
//#define DEBUG // a mettre en commentaire pour enlever les echanges avec la console
L’installation in situ a eu lieu et le montage fonctionne bien... dans presque tous les cas... sauf quelques uns ;(.
Comme toujours dans un projet, il y a quelques améliorations que je ne manquerai pas de vous donner dans un prochain article.
Mais en réalité c’est une nouvelle manière de raisonner et un nouvel automate qui vous sera présenté par Jean-Pierre très prochainement, car le passage à niveau est un cas d’école !!!
Ensuite, nous y ajouterons l’incontournable sonnerie qui accompagne toujours la fermeture de la barrière. Le tout dans notre Mini, avec un lecteur de carte SD en plus : OUI il arrive à tout faire !
Enfin, nous espérons vous proposer une nouvelle réalisation avec un circuit imprimé.
Tout est parfait le seul regret est la détection par ILS ! celle par détecteur de consommation de courant ? qui éviterai de coller des aimants sous le matériel roulant et plus discret !
Les ILS sont le choix du modéliste qui a installé le passage à niveau. Il fait ses détections par ILS. La solution décrite dans cet article peut supporter toutes sortes de détecteurs auxquels il faudra adapter le schéma et le logiciel.
D’ailleurs vous en verrez d’autres dans les prochains articles.
Je vous encourage à nous faire part de vos choix et réalisations sur le Forum Locoduino.
J’avais fait un programme dans ce genre pour une traversée de PN en un seul sens, cela peut peut être vous donnez des idées pour votre cas.
Voici le programme, ATTENTION les deux servos sont tête bêche ce qui veut dire qu’ils tournent en sens inverse cela est dû à la limite de leur emprise en les couchant sur le coté.
/*****************************************************************************
* Gestion d'une barriere dans un seul sens de direction par
* 2 capteurs un pour l'entree du train et l'autre pour la sortie, ILS, detecteur de consommation ou autre
* 2 servos de type SG90 mis tete beche sur leur cote afin de limiter leur emprise
* ce qui fait que quand un servo tourne dans un sens l'autre tourne dans l'autre sens
* et 2 feux routiers qui clignotent
***************************************************************************/
#include <Servo.h>
#include <Bounce2.h>
#define PIN_CAPTEUR_OUVRE 2
#define PIN_CAPTEUR_FERME 3
#define INTERVAL 50
#define PIN_FEU_DROIT 4
#define PIN_FEU_GAUCHE 5
#define ALLUME 0
#define ETEINT 255
#define VITESSE_CLIGNOTEMENT 250
#define PIN_SERVO_DROIT A2
#define PIN_SERVO_GAUCHE A3
// a regler en fonction des servos
#define VITESSE_SERVO 80
#define ANGLE_FERMETURE 1300
#define ANGLE_OUVERTURE 1900
#define PAS_ANGULAIRE 20
/***********************************************************************
* les feux routiers
**************************************************************************/
int cycle = 0; // cycles de clignotement
int changement = VITESSE_CLIGNOTEMENT; // vitesse de clignotement
unsigned long timerLed = millis(); // timer pour le clignotement
/******************************************************************************
* les capteurs
********************************************************************************/
Bounce capteurOuverture; // anti rebond
Bounce capteurFermeture; // anti rebond
/************************************************************************************
* les servos
**************************************************************************************/
int angleFerme = ANGLE_FERMETURE; // angle de fermeture
int angleOuvre = ANGLE_OUVERTURE; // angle pour l'ouverture
int angleDroit; // angle actuel du servo 1
int angleGauche; // angle actuel du servo 2
int pasServo = PAS_ANGULAIRE; // pas angulaire
enum mode {montee,descente,arret};
mode sens = arret; // sens du mouvement de la barriere
enum etat {ouvert, ferme, encours};
etat situation = ouvert; // situation de la barriere
bool actif = false; // etat de la manoeuvre
unsigned long timerServo; // timer pour le servo
int duree = VITESSE_SERVO; // vitesse des servos
Servo servoDroit; // servo de la premiere barriere
Servo servoGauche; // servo de la seconde barriere
/*****************************************************************************
* clignotement des feux routiers
***************************************************************************/
void clignote() {
if (timerLed + changement < millis()) // vitesse de clignotement
{
timerLed = millis(); // reinit le timer
switch (cycle) {
case 0 : {analogWrite(PIN_FEU_DROIT,ALLUME); analogWrite(PIN_FEU_GAUCHE,ALLUME);cycle = 1;break;} // on allume
case 1 : {analogWrite(PIN_FEU_DROIT,ETEINT); analogWrite(PIN_FEU_GAUCHE,ETEINT);cycle = 0;break;} // on eteint
}
}
}
/*****************************************************************************
* initialisation de l'ouverture des barrieres
*****************************************************************************/
void ouverture() {
if (situation != ouvert) { // si pas deja ouvert
servoDroit.attach(PIN_SERVO_DROIT); // on attache les servos
servoGauche.attach(PIN_SERVO_GAUCHE);
actif = true; // on devient actif
angleDroit = angleFerme; // une des barrieres va vers le bas (inversion des servos)
angleGauche = angleOuvre; // l'autre en symetrie va vers le haut
timerServo = millis(); // MAJ du timer
sens = montee; // on monte
situation = encours; // manoeuvre en cours
}
}
/**************************************************************************
* initialisation de la fermeture des barrieres
***************************************************************************/
void fermeture() {
if (situation != ferme ) { // si pas deja ferme
servoDroit.attach(PIN_SERVO_DROIT); // on attach les servos
servoGauche.attach(PIN_SERVO_GAUCHE);
actif = true; // on devient actif
angleDroit = angleOuvre; // une des barrieres va vers le haut (inversion des servos)
angleGauche = angleFerme; // l'uatre en symetrie vers le bas
timerServo = millis(); // MAJ des timers
timerLed = millis();
sens = descente; // on descend
situation = encours; // manoeuvre en cours
}
}
/*******************************************************************************
* manoeuvre de la bbariere
*********************************************************************************/
void manoeuvre() {
if (actif){
if ((timerServo + duree) < millis()){ // vitesse des servos
if (sens == montee) {angleDroit += pasServo; angleGauche -= pasServo; // on monte
if (angleDroit >= angleOuvre) { // en bout de course
actif = false; // on n'est plus actif
sens = arret; // on est a l'arret
situation = ouvert; // la barriere est ouverte
analogWrite(PIN_FEU_DROIT,ETEINT); // on eteint les feux routiers
analogWrite(PIN_FEU_GAUCHE,ETEINT);
servoDroit.detach(); // on detache les servos
servoGauche.detach();
return;} // termine
}
if (sens == descente) {angleDroit -= pasServo; angleGauche += pasServo; // on descend
if (angleDroit <= angleFerme) { // en bout de course
actif = false; // on n'est plus actif
sens = arret; // on est a l'arret
situation = ferme; // la barriere est fermee
servoDroit.detach(); // on detache les servos
servoGauche.detach();
return;} // termine
}
servoDroit.writeMicroseconds(angleDroit); // on avance de l'angle
servoGauche.writeMicroseconds(angleGauche);
analogWrite(PIN_FEU_DROIT,ALLUME); // on allume les feux routiers
analogWrite(PIN_FEU_GAUCHE,ALLUME);
timerServo = millis();
}
}
}
/*******************************************************************
* setup
******************************************************************/
void setup()
{
servoDroit.attach(PIN_SERVO_DROIT);servoDroit.writeMicroseconds(angleOuvre);
servoGauche.attach(PIN_SERVO_GAUCHE);servoGauche.writeMicroseconds(angleFerme);
pinMode(PIN_CAPTEUR_OUVRE,INPUT_PULLUP);capteurOuverture.attach(PIN_CAPTEUR_OUVRE);capteurOuverture.interval(INTERVAL);
pinMode(PIN_CAPTEUR_FERME, INPUT_PULLUP);capteurFermeture.attach(PIN_CAPTEUR_FERME);capteurFermeture.interval(INTERVAL);
analogWrite(PIN_FEU_DROIT,ETEINT);
analogWrite(PIN_FEU_GAUCHE,ETEINT);
}
/*******************************************************************
* la boucle
********************************************************************/
void loop()
{
if (situation == ferme) { clignote();}
if (capteurOuverture.fell()) {ouverture();}
if (capteurFermeture.fell()) {fermeture();}
if (situation == encours) {manoeuvre();}
capteurOuverture.update();
capteurFermeture.update();
}
La source, c’est le référentiel IN323 du 15/10/1980 de la SNCF (Equipement des PN et réglementaiton article 9) que je ne peux pas diffuser ici. Il est en cours de réécriture pour tenir compte de l’arrêté ministériel du 18/03/1991 rectifié en 2017. Mais rien ne changera sur cette partie de fonctionnement.
Vous pouvez vous poster à un PN pour constater ces valeurs.
Je n’ai pas mis toutes les tolérences, mais pour le préavis (7s indiqué avant la descente des barrières) c’est 6 à 8s.
Par contre, je n’utiliserai pas les détections individuelles, puisque le vrai cablage d’un PN totalise l’ensemble des provenances des trains (les relais d’annonce) sur un seul relais (la commande de la signalisation routière). C’est donc celui-ci qui servira à commander les feux, barrières et sonneries.
Le réarmement de chaque annonce se fait par un passage sur le PN (1 zone courte par voie) qui réarme l’annonce déclenchée et par extension le relais totalisateur des annonces.
Pour être précis, la signalisation, les postes d’aiguillage et les PN, c’était mon métier pendant 40 ans !
J’ai encore une petite activité de recherche sur les PN et j’ai besoin de faire un maquettage, d’où mon besoin d’un arduino.
Je suis en train de réaliser un passage à niveau au plus près de la réalité.
Tout fonctionne correctement (il me manque encore le son), mais je me heurte à un problème d’affichage sur un écran.
Je voudrais afficher en permanence sur un écran LCD I2C, l’état de 4 relais pour indiquer l’état du PN.
J’arrive bien à faire fonctionner mon affichage dans un programme isolé en utilisant la fonction delay().
Par contre, il n’est pas possible de bloquer l’ensemble du programme avec cette fonction.
Comment pourrais-je m’en sortir ?
J’avais pensé à utiliser MsTimer2, mais là, je suis bloqué !
Merci de votre aide
mon croquis ecran :
/* Fonctionnement d’un ecran LCS I2C sur Mega *****************
* Branchement en +VCC, GND, SDA (20) et SLC (21)
* Informations provenant de 4 contats de relais
* branchés en A0, A1, A2 et A3 avec Resistances et capa
* pour gérer les rebonds (avec un trigger sur la carte finale
* ***********************************************************/
/* programme non compatible avec le reste du passage à niveau
* du fait de l’utilisation de la fonction delay(1000) pour
* l’affichage des différents états à l’écran (blocage du prog)
* *********************************************************/
// MsTimer2 : : set (1000, ecran) ; periode de 1s
// MsTimer2 : : start() ;
int error ;
Serial.begin(115200) ;
Serial.println("LCD...") ;
// wait on Serial to be available on Leonardo
while (!Serial) ;
Serial.println("Dose : check for LCD") ;
// Voir http://playground.arduino.cc/Main/I... pour tester le port I2C.
Wire.begin() ;
Wire.beginTransmission(0x27) ;
error = Wire.endTransmission() ;
Serial.print("Error : ") ;
Serial.print(error) ;
if (error == 0)
Serial.println(" : LCD found.") ;
show = 0 ;
lcd.begin(16, 2) ; // initialize the lcd else
Serial.println(" : LCD not found.") ; // fin if
// fin setup()
Bonjour,
vous avez fait le bon diagnostic avec delay.
A sa place, mettez la mise à jour de votre lcd dans un if genre millis > old_millis + raffraichissement et màj de old_millis ...
Utilisez plutôt le forum, cela vous évitera de voir vos accolades disparaitre.
Bonjour.
Ce tuto m’intéresse beaucoup car j’ai un PN un peut dans cette configuration mais plus "compliqué".
En effet, deux voies à double sens avec chacune une sortie dont un croisement pour le dépôt en sortie du PN.
Ma question est de savoir si il y a possibilité de remplacer les ILS pas des LEDS Infra Rouge ( il y en a qui se placent entre les traverses) pour ne pas avoir à instaler des aimants sur tout le matériel roulant.
Merci pour votre réponse et bravo pour ce site.
Cordialement JP.
Oui c’est possible en respectant la logique des capteurs (équivalent à un ILS du point de vue logique). Pour le reste vous pouvez adapter le programme à votre réseau.
J’ai réalisé un PN simple pour un train LGB. Gestion de deux servos moteur, du clignotement de deux LED, détection par ils. Lors du rajout ultérieur de la sonnerie sur une carte arduino uno avec un DFplayer mini, j’ai observé qu’à la lecture du fichier son mp3, les servos étaient perturbés par cette lecture (notamment au démarrage de la lecture sur la carte SD). J’avais logiquement utilisé la librairie softwareserial pour émuler une nouvelle connexion série pour ma carte DFplayer avec l’arduino UNO, celui ci ne disposant nativement que d’une seule sortie série (déjà utilisée par la connexion USB)
Je précise que les servos étaient alimentés par une alimentation régulée 5V dédiée avec un GND commun sur l’arduino
J’avais choisi le DFplayer mini car celui ci est peu couteux, facile à programmer avec la bibliothèque DFRobotDFPlayerMini, et disposant d’un petit amplificateur intégré.
Disposant d’une carte MEGA, J’ai reconnecté le DFplayer sur la sortie serial2. Dans ce contexte, je n’observe plus aucune perturbation de fonctionnement sur les servos, tout fonctionne parfaitement. Pour autant c’est un peu dommage d’utiliser une carte MEGA pour une application finalement assez simple
Je tenais à vous faire part de ce retour d’expérience, je pense qu’il doit être possible de tout réunir sur une carte UNO, mais à l’instant je ne trouve pas la solution
Pourriez vous me donner votre avis sur ce sujet
Votre site est une vrais source d’inspiration, je vous félicite pour tout ce travail réalisé
Bonjour, je n’ai pas la réponse qui nécessite des essais pour trouver une solution logicielle ou pas. Cependant je pense qu’au lieu d’utiliser un Mega il est moins onéreux d’utiliser deux Pro-mini ou Nano reliés en I2C ou de la manière de Christian dans sa série d’articles Passage à niveau géré par Arduino (4)
Bonjour,
vous n’avez pas vu le 8e commentaire ?
sinon, lisez la série d’articles Passage à niveau géré par Arduino (1 à 5)
Et pour un dépannage passez sur le forum.
Cordialement