Sur nos réseaux il est nécessaire de contrôler un certain nombre d’articles comme la détection de présence avec le cantonnement et la position des aiguillages qui ont un impact direct avec le roulement de nos trains et d’autres articles, plus pour l’esthétique, comme les animations ou les feux de signalisation. La détection a été abordée avec le bus S88 et maintenant avec le travail de mes collègues avec le bus CAN beaucoup plus performant. Le contrôle des aiguillages à solénoïde a également été abordé dans un article précédent. Nous souhaitons ici proposer une solution pour réaliser un décodeur de feux de signalisation à deux ou trois feux gérés par des commandes DCC.
Un décodeur DCC pour les signaux à deux ou trois feux sur Arduino NANO/UNO
.
Par :
DIFFICULTÉ :★★★
Réalisation de la carte décodeur
Les feux de signalisation sur nos réseaux n’ont aucune influence sur le roulement de nos trains, ils sont juste là pour créer un environnement réaliste. Si vous êtes comme moi un peu réfractaire à comprendre la complexité des signaux SNCF, je me limite, au moins pour l’instant, à des signaux à deux ou trois feux. Je vous propose donc de réaliser un décodeur pour ce type de signaux.
Le principe est assez simple puisque cela revient à allumer ou éteindre des leds, ce que nos Arduino font très bien. Les signaux en DCC sont considérés comme des accessoires possédant une adresse (dans le cas des signaux à deux feux) ou deux adresses (dans le cas des signaux à trois feux). Il suffit donc de coller un capteur de signaux DCC à un Arduino qui exécutera la commande reçue et allumera (ou éteindra) les bonnes leds. Dans notre approche l’alimentation des leds est faite par le courant DCC.
Le schéma suivant reprend la capture des signaux DCC classique basée sur un 6N137 auquel on ajoute en parallèle un pont et un régulateur 8V pour l’alimentation de l’Arduino et des leds. Cela est raisonnable car nous le verrons dans le cas des signaux à trois feux il n’y aura que 5 leds allumées et dans le cas des signaux à deux feux, 8 leds allumées. Un strap a été prévu suivant la polarité des signaux (leds avec commun positif ou négatif). L’Arduino reçoit les commandes DCC sur la broche 2 (interruption 0) et renvoie le résultat sur les broches 3 à A4 suivant les cas. Cela tient sur une carte classique 6x10 et est la même que ce soit des signaux à deux ou trois feux.
Et voici le typon correspondant :
(NB : petite astuce pour ceux qui se lance dans la réalisation, le problème est d’aligner convenablement le perçage pour l’Arduino NANO. Pour cela j’utilise une plaque d’essai qui me sert de guide :
Et tout se passe bien.)
Pour ceux qui connaissent Eagle et qui font leur carte via des fournisseurs voici les fichiers Eagle :
et le zip Gerber qui va avec :
et obtient des cartes quasi professionnelles :
L’algorithme
Le programme permet de gérer aussi bien les signaux à deux feux que ceux à trois feux. Par contre on ne peut mélanger les deux types sur une même carte.
Pour les signaux à trois feux la carte admet 5 signaux dont les leds sont contrôlées par les broches 3 à A3 en triplet.
Signal1 | broches 3,4,5 |
Signal2 | broches 6,7,8 |
Signal3 | broches 9,10,11 |
Signal4 | broches 12,13,A0 |
Signal5 | broches A1,A2,A3 |
Les adresses paires correspondent aux leds vertes et rouges.
Les adresses impaires correspondent aux leds jaunes.
Pour les signaux à deux feux la carte admet 8 signaux dont les leds sont contrôlées par les broches 3 à A4 par paire.
Signal1 | broches 3,4 |
Signal2 | broches 5,6 |
Signal3 | broches 7,8 |
Signal4 | broches 9,10 |
Signal5 | broches 11,12 |
Signal6 | broches 13, A0 |
Signal7 | broches A1, A2 |
Signal8 | broches A3, A4 |
Chaque signal possède une adresse unique.
L’algorithme est simple et ne demande que trois paramètres de configuration :
MODE : détermine le niveau de commande des leds en fonction de la polarité commune, LOW si le commun est positif, HIGH si le commun est négatif.
FIRST_ID_DCC : correspond à la première adresse des signaux, les adresses des signaux suivants en découleront (linéaire dans le cas BICOLOR, par paire dans le cas TRICOLOR).
NB_TRAFFIC_LIGHT : détermine la nature des signaux, TRICOLOR pour des signaux à trois feux ou BICOLOR pour des signaux à deux feux.
Un dernier paramètre ne sert qu’à permettre de visualiser la bonne configuration et peut être omis par la suite, c’est le paramètre CONSOLE.
Le reste de l’algorithme reste inchangé quel que soit le type de signaux.
Paramètres internes
Ils déterminent les paramètres du DCC (insertion de la librairie Minabay, broche d’interruption), évitent les commandes multiples ayant même adresse et/ou même commande (previous_address/previous_position) et si une mise à jour est nécessaire (update_light).
Ils décrivent les signaux (BICOLOR ou TRICOLOR), la broche de départ des leds des signaux (FIRST_PIN) et les couleurs possibles (GREEN, RED, YELLOW).
Ils définissent la structure d’un signal (light) qui possède une adresse (address), une couleur courante (current_position), les broches des leds associées (green, red et yellow) et si une requête de changement est demandée (activation_request).
L’ensemble des signaux est regroupé dans un tableau (traffic_light[]).
Le setup instancie le DCC et détermine les adresses des signaux (address), linéaire dans le cas BICOLOR, par paire dans le cas TRICOLOR, les broches des leds (green, red, yellow) et positionne tous les signaux au rouge. Voici par exemple des configurations :
Pour des signaux à deux feux :
traffic light0 |
---|
green led on pin : 3 , DCC address : 90/0 |
red led on pin : 4 , DCC address : 90/1 |
traffic light1 |
---|
green led on pin : 5 , DCC address : 91/0 |
red led on pin : 6 , DCC address : 91/1 |
traffic light2 |
---|
green led on pin : 7 , DCC address : 92/0 |
red led on pin : 8 , DCC address : 92/1 |
traffic light3 |
---|
green led on pin : 9 , DCC address : 93/0 |
red led on pin : 10 , DCC address : 93/1 |
traffic light4 |
---|
green led on pin : 11 , DCC address : 94/0 |
red led on pin : 12 , DCC address : 94/1 |
traffic light5 |
---|
green led on pin : 13 , DCC address : 95/0 |
red led on pin : 14 , DCC address : 95/1 |
traffic light6 |
---|
green led on pin : 15 , DCC address : 96/0 |
red led on pin : 16 , DCC address : 96/1 |
traffic light7 |
---|
green led on pin : 17 , DCC address : 97/0 |
red led on pin : 18 , DCC address : 97/1 |
Et des signaux pour trois feux :
traffic light0 |
---|
green led on pin : 3 , DCC address : 90/0 |
red led on pin : 4 , DCC address : 90/1 |
yellow led on pin : 5 , DCC address : 91/0 |
traffic light1 |
---|
green led on pin : 6 , DCC address : 92/0 |
red led on pin : 7 , DCC address : 92/1 |
yellow led on pin : 8 , DCC address : 93/0 |
traffic light2 |
---|
green led on pin : 9 , DCC address : 94/0 |
red led on pin : 10 , DCC address : 94/1 |
yellow led on pin : 11 , DCC address : 95/0 |
traffic light3 |
---|
green led on pin : 12 , DCC address : 96/0 |
red led on pin : 13 , DCC address : 96/1 |
yellow led on pin : 14 , DCC address : 97/0 |
traffic light4 |
---|
green led on pin : 15 , DCC address : 98/0 |
red led on pin : 16 , DCC address : 98/1 |
yellow led on pin : 17 , DCC address : 99/0 |
L’algorithme consiste à tester le DCC (méthode BasicDecoderPacket_Handler).
Ce dernier décode l’adresse reçue, vérifie s’il y a un changement depuis la dernière fois (cela évite les commandes multiples). S’il y a changement en fonction du type de signal (BICOLOR ou TRICOLOR) on calcule l’index du signal concerné en fonction de l’adresse reçue et la led concernée. Dans le cas TRICOLOR il y a deux adresses par signal, si l’adresse est impaire c’est le signal jaune qui est concerné. Le DCC met à jour les paramètres du signal et prévient d’un changement.
Si un changement a eu lieu on le propage au bon signal (méthode activation_traffic_light). Cette méthode recherche les signaux en attente de traitement (activation_request) et exécute les commutations des leds du signal en fonction de la demande (current_position).
Le programme Arduino
/*
* Decoder for traffic light with three or two leds on ARDUINO NANO
*
* by default the red leds are switched on
* pin 2 receives DCC interrupts
*
* TRAFFIC LIGHT WITH THREE leds (GREEN, RED, YELLOW)
* 5 decoders of traffic lights with three leds on Arduino NANO/UNO
* the leds are controlled by pins 3 to A3 by triplet
* traffic light 1 : 3,4,5
* traffic light 2 : 6,7,8
* traffic light 3 : 9,10,11
* traffic light 4 : 12,13,A0
* traffic light 5 : A1,A2,A3
* two addresses by traffic light
* even addresses for green and red lights
* odd addresses for yellow light
*
* TRAFFIC LIGHT WITH TWO leds (GREEN, RED)
* 8 decoders of traffic lights with two leds on Arduino NANO/UNO
* the leds are controlled by pins 3 to A4 by pair
* traffic light 1 : 3,4
* traffic light 2 : 5,6
* traffic light 3 : 7,8
* traffic light 4 : 9,10
* traffic light 5 : 11,12
* traffic light 6 : 13,A0
* traffic light 7 : A1,A2
* traffic light 8 : A3,A4
* one address by traffic light
*
* CONFIGURATION
* MODE : determined by the common of the led, LOW if common = HIGH, HIGH if common = LOW
* FIRST_ID_DCC : DCC address of the first traffic light
* NB_TRAFFIC_LIGHT : determined by the kind of traffic light, BICOLOR for two leds, TRICOLOR for three leds
*
*/
/***************************************************************************************
* CONFIGURATION SETTING
*
****************************************************************************************/
#define CONSOLE // output console, delete this after checking the configuration
#define MODE LOW // LOW or HIGH
#define FIRST_ID_DCC 90 // first DCC address, DCC_CODE
#define NB_TRAFFIC_LIGHT TRICOLOR // TRICOLOR or BICOLOR
/**********************************************************************************
* DON'T CHANGE THE FOLLOWING
*********************************************************************************/
/******************************************************************************
* INTERNAL PARAMETERS
*
********************************************************************************/
// DCC
#include <DCC_Decoder.h> // Minabay library
#define kDCC_INTERRUPT 0 // pin 2 receives DCC interrupts
int previous_address = 0; // avoids multiple DCC addresses
int previous_position = 2; // avoids multiple DCC orders
volatile boolean update_light; // set if an update should be processed after DCC control
// traffic light
#define BICOLOR 8 // 8 traffic lights with two leds
#define TRICOLOR 5 // 5 traffic lights with three leds
#define FIRST_PIN 3 // pin of the first traffic light
#define GREEN 0 // address DCC/0
#define RED 1 // address DCC/1
#define YELLOW 2 // address DCC+1/0
// traffic light definition
struct light {
int address; // its DCC address
int current_position; // green / red / yellow
int green; // pin of the green led
int red; // pin of the red led
int yellow; // pin of the yellow led
boolean activation_request; // request of activation
};
light traffic_light[NB_TRAFFIC_LIGHT]; // the set of traffic light
/********************************************************************
* method called if a request is made by the DCC
*
*******************************************************************/
void activation_traffic_light() {
for (int i = 0; i < NB_TRAFFIC_LIGHT; i++) // for all traffic lights
{
if (traffic_light[i].activation_request == true) // if the traffic_light is waiting for activation
{
switch(traffic_light[i].current_position) // we look the current position
{
case GREEN :{ // if green led
digitalWrite(traffic_light[i].green,MODE); // switch on green
digitalWrite(traffic_light[i].red,!MODE); // switch off red
if ( NB_TRAFFIC_LIGHT == TRICOLOR){digitalWrite(traffic_light[i].yellow,!MODE);} // switch off yellow
#ifdef CONSOLE
Serial.print("activation -> traffic light");Serial.print(i);Serial.println(" : green led");
#endif
break;}
case RED : { // if red led
digitalWrite(traffic_light[i].green,!MODE); // switch off green
digitalWrite(traffic_light[i].red,MODE); // switch on red
if ( NB_TRAFFIC_LIGHT == TRICOLOR){digitalWrite(traffic_light[i].yellow,!MODE);} // switch off yellow
#ifdef CONSOLE
Serial.print("activation -> traffic light");Serial.print(i);Serial.println(" : red led");
#endif
break;}
case YELLOW : { // if yellow led
digitalWrite(traffic_light[i].green,!MODE); // switch off green
digitalWrite(traffic_light[i].red,!MODE); // switch off red
digitalWrite(traffic_light[i].yellow,MODE); // switch on yellow
#ifdef CONSOLE
Serial.print("activation -> traffic light");Serial.print(i);Serial.println(" : yellow led");
#endif
break;}
}
}
traffic_light[i].activation_request = false; // the traffic light is updated
}
update_light = false; // all updates are made
}
/*************************************************************************************
* DCC method
*
***********************************************************************************/
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
address -= 1; address *= 4; address += 1; address += (data & 0x06) >> 1; // DCC address decoding
int led = (data & 0x01) ? GREEN : RED; // DCC/0 or DCC/1
int traffic_light_index = address; // index of a traffic light
int color = led; // the color of the led
boolean activation = false;
if ((address != previous_address) || ((led != previous_position)&&(address == previous_address))){ // if we change the address or the led
switch (NB_TRAFFIC_LIGHT) {
case BICOLOR : { // if the address is in our range for traffic light with two leds
if ((address >= FIRST_ID_DCC) && (address < FIRST_ID_DCC + NB_TRAFFIC_LIGHT)){
traffic_light_index = address - FIRST_ID_DCC; // index of the traffic light
activation = true;}
break;}
case TRICOLOR : { // if the address is in our range for traffic light with three leds
if ((address >= FIRST_ID_DCC) && (address < FIRST_ID_DCC + (2*NB_TRAFFIC_LIGHT))){
if (address%2 != 0) { traffic_light_index = address - 1; color = YELLOW;} // if odd address => yellow led
traffic_light_index = (traffic_light_index - FIRST_ID_DCC)/2; // index of the traffic light
activation = true;}
break;}
}
traffic_light[traffic_light_index].activation_request = activation; // activation is requested
traffic_light[traffic_light_index].current_position = color; // state is requested (color of the led)
update_light = activation; // traffic light update is requested
}
previous_address = address; previous_position = led; // the current activation is saved
}
/**********************************************************************************************
* setup
*
******************************************************************************************/
void setup() {
int pin_jump = 0; // a jump for traffic light pins
int traffic_light_jump = 0; // a jump for traffic light number
for (int i=0; i<NB_TRAFFIC_LIGHT; i++){ // for all the traffic lights
traffic_light[i].activation_request = false; // no activation request
traffic_light[i].green = pin_jump + FIRST_PIN; // pin number of the green led
pinMode(traffic_light[i].green, OUTPUT); // green led in output(ID DCC/0)
digitalWrite(traffic_light[i].green, !MODE); // green led switch off
traffic_light[i].red = 1+ pin_jump + FIRST_PIN; // pin number of the red led
pinMode(traffic_light[i].red, OUTPUT); // red led in output (ID DCC/1)
digitalWrite(traffic_light[i].red, MODE); // red led switch on
if (NB_TRAFFIC_LIGHT == TRICOLOR) { // if three leds
traffic_light[i].address = traffic_light_jump + FIRST_ID_DCC + i; // its DCC ID
traffic_light[i].yellow = 2+ pin_jump + FIRST_PIN; // pin number of the yellow led
pinMode(traffic_light[i].yellow, OUTPUT); // yellow led in output (ID DCC+1/0)
digitalWrite(traffic_light[i].yellow, !MODE); // yellow led switch off
traffic_light_jump++; // the following traffic light
pin_jump+=3; // the following pin for three leds
}
else { // if two leds
traffic_light[i].address = FIRST_ID_DCC + i; // its DCC ID
pin_jump+=2; // the following pin for two leds
}
}
DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true); // instanciate the DCC
DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT ); // its IT
update_light = false; // no update
#ifdef CONSOLE
Serial.begin(115200);
for (int i=0; i<NB_TRAFFIC_LIGHT; i++){
Serial.print("traffic light");Serial.println(i);
Serial.print("\t green led on pin : ");Serial.print(traffic_light[i].green);Serial.print(" , DCC address : ");Serial.print(traffic_light[i].address);Serial.println("/0");
Serial.print("\t red led on pin : ");Serial.print(traffic_light[i].red);Serial.print(" , DCC address : ");Serial.print(traffic_light[i].address);Serial.println("/1");
if (NB_TRAFFIC_LIGHT == TRICOLOR) {
Serial.print("\t yellow led on pin : ");Serial.print(traffic_light[i].yellow);Serial.print(" , DCC address : ");Serial.print(traffic_light[i].address+1);Serial.println("/0");
}
}
#endif
}
/*************************************************************************
* loop
*
******************************************************************/
void loop() {
DCC.loop(); // Is there a DCC command ?
if (update_light) {activation_traffic_light();} // if yes, activation of traffic lights
}
Le programme à télécharger ici :
Ce petit décodeur de signaux est facile à réaliser pour un coût très modique. Il marche très bien sur mon réseau avec mon ECOS et TrainController. Pour ceux qui possède une Cameo silhouette on peut même réaliser ses propres feux et potence dont voici une première ébauche.
et son utilisation avec une ECOS :
la bibliothèque minabay pour le DCC