LOCODUINO

Forum de discussion
Dépôt GIT Locoduino
Flux RSS

lundi 20 novembre 2017

50 visiteurs en ce moment

La rétro-signalisation sur Arduino

. Par : JPClaude

L’objectif de cet article est de proposer une solution simple à la réalisation d’une rétro-signalisation sur la base d’Arduino UNO/Nano et MEGA. La solution est un petit programme qui permet rapidement de créer des modules de détection à 16 entrées sur Arduino UNO/Nano ou 64 entrées sur Arduino MEGA. Chaque Arduino peut être relié à d’autres afin d’augmenter le nombre de modules. Cette solution est basée sur le projet de rudymodelrailway [1].

La rétro-signalisation

La rétro-signalisation consiste à renvoyer des événements du réseau vers un TCO ou une centrale. Ces événements sont liés à des accessoires (position d’un aiguillage, d’une animation) ou de l’occupation d’une portion d’un réseau dans le cas d’un cantonnement. La norme DCC   intègre uniquement la communication d’information de la centrale vers les détecteurs. Il n’existe pas de norme en ce qui concerne la rétro-signalisation. Plusieurs solutions existent, toutes propriétaires, qui sont devenus de fait des standards comme par exemple Loconet de Digitrax ou le bus S88 de Marklin. A noter une évolution avec l’apparition des transpondeurs qui permettent d’avoir une communication bidirectionnelle en DCC  . Ce type de communication ne fait pas partie de la norme NMRA mais est plutôt une surcouche de cette norme. En particulier la firme Lenz a créé une technologie appelée Railcom qui commence à être adoptée par plusieurs constructeurs (Lenz, ESU, Uhlenbrock, Tams Elektronik). Il faut cependant que la centrale et le décodeur de la locomotive intègrent cette technologie. Dans le cadre de cet article nous ne parlerons que de la solution bus S88, pas forcément la meilleure mais la plus courante.

La détection

La détection d’un événement sur le réseau se fait par des capteurs (pédale de voie, ILS, consommation de courant, fin de course d’un aiguillage). Il faut donc d’une part un petit circuit capteur qui génère l’événement et un décodeur qui permet de renvoyer cet événement à la centrale ou au TCO. Nous prendrons comme exemple dans cet article un capteur par consommation de courant et un décodeur basé sur le bus S88. Le petit montage suivant, proposé par jacques Veillard sur le site train35 [2] est une bonne solution pour détecter la présence d’un convoi sur un canton et adapté la tension à celle acceptable par un Arduino (NB : prendre soin de bien relier le + et - du pont de diode).

Le bus S88

Le bus S88 consiste à relier par chaînage les modules entre eux. Ce n’est pas le meilleur bus mais il reste encore celui le plus utilisé. Il fonctionne sous une tension comprise entre 4,5 et 5v (donc tout à fait compatible avec nos Arduino). La longueur maximale entre deux modules ne doit pas dépasser 5m, encore faut-il veiller à ce que le câble du bus ne soit pas trop près d’environnements perturbateurs (courant de traction, 220v). Le nombre maximum de capteurs sur un bus S88 est limité à 512. L’adressage des capteurs est simple. Chaque module possède 8 ou 16 capteurs. On commence la numérotation par le premier module (valeur = 1) et son premier capteur (adresse 1:1) puis on incrémente de 1 à chaque capteur suivant dans le chaînage jusqu’à la valeur 16 (1:16) , puis on passe à 2 (2:1) et ainsi de suite modulo 16. La photo suivante provenant de LDT-infoCenter présente le principe de ce chaînage.

Le fonctionnement est simple. Chaque module est un registre à décalage de 8 ou 16 positions. La centrale génère un signal "PS" qui déclenche le comptage de l’horloge. Tous les modules reçoivent le signal "PS" et les fronts de l’horloge. Ils sont reliés entre eux par un câble de sortie et un d’entrée. On obtient ainsi un décalage de buffers à chaque top d’horloge.

Le bus S88 est un connecteur possédant 6 connexions dont la signification est la suivante :

  • broche 1 : data (blanc) - sortie des données vers un autre module ou vers la centrale
  • broche 2 : GND (marron) - GND
  • broche 3 : clock (vert) – top de l’horloge
  • broche 4 : PS (jaune) – signal PS démarrage de l’horloge
  • broche 5 : Reset (violet) - reset du comptage
  • broche 6 : V+ (rose) – alimentation 4,5 à 5V

Le bus S88 avec un Arduino

La solution proposée ici se base sur le travail de Ruud Boer [3]. Le principe est le suivant, chaque Arduino correspond à un module pouvant posséder 16 capteurs pour un UNO/Nano ou 64 capteurs pour un MEGA. Le chaînage des Arduino se fait de la manière suivante :

  • Tous les Arduino doivent être connectés aux broches 2, 3,4 et 6 du bus S88
  • Le premier Arduino connecte sa broche 1 à la broche 1 du bus S88
  • Les autres Arduino connectent leur broche 1 à la broche 0 de l’Arduino précédent.

L’interface avec le bus S88 se fait sur les broches 0 à 3, Gnd et Vin de la manière suivante :

  • broche 0 (rx) : entrée depuis un autre Arduino
  • broche 1 (tx) : sortie vers la station de contrôle ou vers un autre Arduino
  • broche 2 (int0) : interruption de l’horloge du bus S88 (sur tous les Arduino du chaînage)
  • broche 3 (int1) : interruption du signal PS du bus S88 (sur tous les Arduino du chaînage)
  • Gnd : masse commune (sur tous les Arduino du chaînage)
  • Vin : alimentation S88 (sur tous les Arduino du chaînage)

Rétro-signalisation sur UNO/Nano

Le programme se limite à inclure la bibliothèque UNO_S88 et à faire un setup avec le nombre de détecteurs souhaités (8 ou 16). Les broches utilisées sont les suivantes :

  • Broche 0 : entrée des états des autres Arduino chaînés
  • Broche 1 : sortie des états vers la station de contrôle ou vers un autre Arduino
  • Broche 2 : interruption de l’horloge S88
  • Broche 3 : interruption PS du S88
  • Pour 8 détecteurs les broches 4 à 11 sont utilisées
  • Pour 16 détecteurs toutes les broches sont utilisées (4 à A5)

Le programme Arduino UNO/Nano

  1. #include <UNO_S88.h> // la librairie S88 pour les UNO/Nano
  2.  
  3. void setup() {
  4. S88_Setup(16); // on donne le nombre capteur 8 ou 16
  5. }
  6.  
  7. void loop() {
  8. S88_Loop(); // boucle sur les capteurs
  9. }

et la bibliothèque associée

Le fichier entête UNO_S88.h

  1. #include <Arduino.h>
  2. void S88_Setup(int nb_sensors);
  3. void S88_Loop();

et le fichier UNO_S88.cpp

  1. #include "UNO_S88.h"
  2. #include <Arduino.h>
  3.  
  4. const byte clockS88 = 2; // horloge du bus S88 pin = 2
  5. int clockCounter=0; // compteur de tops horloge
  6. const byte PSS88 = 3; // signal PS du bus S88 pin = 3
  7. long loopCounter=0; // reset proper à l’ECOS
  8. const byte dataIn=0; // entrée des données depuis un autre Arduino dans
  9. // la chaîne S88 pin = 0
  10. const byte dataOut=1; // sortie des données vers un autre Arduino dans
  11. // la chaîne ou vers la centrale pin=1
  12. unsigned int sensors=0; // tampon de 16 bits pour les capteurs
  13. unsigned int data=0xffff; // le registre à décalage
  14. int nbsensors; // nombre de capteurs 8 or 16
  15. int beginPin = 4; // première broche utilisée pour les capteurs
  16. int endPin8 = 12; // dernière broche pour 8 capteurs
  17. int endPin16 = 21; // dernière broche pour 16 capteurs
  18. int endPin; // variable locale
  19.  
  20. // routine d’interruption du signal PS
  21. // (déclenchement d’un nouveau cycle d’horloge)
  22.  
  23. void PS() {
  24. clockCounter=0; // on remet le compteur à zéro
  25. data=sensors; // on vide le tampon des capteurs dans le
  26. // registre à décalage
  27. sensors=0; // on remet à zéro le tampon des capteurs
  28. loopCounter++; // on incrémente le nombre de top d’horloge
  29. }
  30.  
  31. // routine d’interruption de l’horloge S88
  32.  
  33. void clock() {
  34. digitalWrite(dataOut,bitRead(data,clockCounter)); // on décale 1 bit en sortie
  35. delayMicroseconds(16); // délai pour le décalage
  36. bitWrite(data,clockCounter,digitalRead(dataIn)); // on décale 1 bit en entrée
  37. clockCounter =(clockCounter +1) % nbsensors; // modulo le nombre de capteurs
  38. // (8 ou 16)
  39. }
  40.  
  41. // le setup S88
  42.  
  43. void S88_Setup(int nb_sensors) {
  44. nbsensors = nb_sensors; // nombre de capteurs désirés (8 ou 16)
  45. if (nbsensors == 8) { // MAJ des broches concernées
  46. endPin = endPin8;
  47. }
  48. else {
  49. endPin = endPin16;
  50. }
  51. pinMode(clockS88, INPUT_PULLUP); // init de la broche pour l’horloge
  52. attachInterrupt(0,clock,RISING); // horloge sur int 0 sur la broche 2
  53. pinMode(PSS88, INPUT_PULLUP); // init de la broche du signal PS
  54. attachInterrupt(1,PS,RISING); // PS sur int1 sur la broche 3
  55. pinMode(dataIn,INPUT_PULLUP); // pin 0 = entrée des données depuis un
  56. // autre Arduino
  57. pinMode(dataOut, OUTPUT); // pin 1 = sortie des données vers la
  58. // centrale ou vers un autre Arduino
  59. // dans le chaînage S88
  60. for (int i = beginPin; i< endPin;i++) {
  61. pinMode(i,INPUT_PULLUP); // init des broches des capteurs
  62. }
  63. }
  64.  
  65. // la boucle
  66.  
  67. void S88_Loop() {
  68. if (loopCounter==20) {
  69. bitSet(sensors,0); // reset des tampons des capteurs pour l’ECOS
  70. }
  71. for (int i = 4; i<endPin; i++) { // MAJ des capteurs
  72. if (!digitalRead(i)) {
  73. bitSet(sensors,i-4);
  74. }
  75. }
  76. }

Rétro-signalisation sur MEGA

La différence avec les cartes UNO/Nano est que le MEGA représente à lui seul 4 modules S88 de 16 capteurs en interne. Le grand avantage est de réduire considérablement le câblage, par quatre par rapport à un UNO et limite grandement la demande en courant depuis le bus S88. Le chaînage de ces quatre modules devient interne au MEGA. Le module 1 est le premier et le module 4 le dernier, un MEGA à lui seul peut donc intégrer 64 capteurs sur quatre modules internes. Cela n’empêche pas d’avoir des chaînages externes avec d’autres Arduino (UNO, Nano ou MEGA). La limite étant de 512 capteurs pour un bus S88, il suffit donc de quatre MEGA pour remplir le bus.

Tout comme précédemment le programme se limite à inclure la bibliothèque MEGA_S88 et à faire un setup.
Les broches utilisées sont les suivantes :

  • Broche 0 : entrée des états des autres Arduino chaînés
  • Broche 1 : sortie des états vers la station de contrôle ou vers un autre Arduino
  • Broche 2 : interruption de l’horloge S88
  • Broche 3 : interruption PS du S88
  • Les broches 20 et 21 sont volontairement inutilisées pour des extensions avec le DCC (interruption sur broche 20 et led de contrôle sur broche 21)

Les modules sont regroupés en quatre groupes de 16 détecteurs dont les broches sont les suivantes :

  • Module1 = 4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
  • Module2 = 22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37
  • Module3 = 38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53
  • Module4 = 54(A0),55(A1),56(A2),57(A3),58(A4),59(A5),60(A6),61(A7),62(A8),63(A9),64(A10),
  • 65(A11), 66(A12), 67(A13), 68(A14), 69(A15)

Le programme permet d’instancier 1 à 4 modules de 16 détecteurs dans un ordre séquentiel partant du module 1 jusqu’au module 4.

Le programme Arduino MEGA

  1. #include <MEGA_S88.h> // librairie S88 pour le MEGA
  2.  
  3. void setup()
  4. {
  5. S88_Setup(2); // on donne le nombre de modules souhaités
  6. }
  7.  
  8. void loop()
  9. {
  10. S88_Loop(); // on boucle
  11. }

et la petite bibliothèque associée

Le fichier d’entête MEGA_S88.h

  1. #include "MEGA_S88.h"
  2. #include <Arduino.h>
  3.  
  4. // Allocation des broches
  5.  
  6. const byte dataIn = 0; // entrée des données depuis d’autres Arduino
  7. const byte dataOut = 1; // sortie vers la centrale ou vers d’autres
  8. // Arduino
  9. const byte clockS88 = 2; // int0 pour l’horloge sur la broche 2
  10. const byte PSS88 = 3; // int1 pour le signal PS sur la broche 3
  11.  
  12. int clockCounter = 0; // compteur des tops horloge
  13. long loopCounter = 0; // reset propre à l’ECOS
  14.  
  15. // nombre de modules de 16 capteurs
  16.  
  17. int nbBlocs = 0; // le nombre de module souhaité
  18.  
  19. // registres à décalage des différents modules
  20.  
  21. unsigned int data1 = 0xFFFF; // register du module 1
  22. unsigned int data2 = 0xFFFF; // register du module 2
  23. unsigned int data3 = 0xFFFF; // register du module 3
  24. unsigned int data4 = 0xFFFF; // register du module 4
  25.  
  26. // tampon des capteurs
  27.  
  28. unsigned int sensors1 = 0; // 16 capteurs du module 1
  29. unsigned int sensors2 = 0; // 16 capteurs du module 2
  30. unsigned int sensors3 = 0; // 16 capteurs du module 3
  31. unsigned int sensors4 = 0; // 16 capteurs du module 4
  32.  
  33. // internal variable
  34.  
  35. int i,j;
  36.  
  37. // routine d’interruption du signal PS
  38.  
  39. void PS()
  40. {
  41. clockCounter = 0; // RAZ du compteur de top horloge
  42. // il y a au moins un module, le premier le module 1
  43. data1 = sensors1; // on vide le tampon des capteurs
  44. // dans le registre à décalage
  45. sensors1 = 0; // RAZ du tampon des capteurs
  46. switch (nbBlocs)
  47. {
  48. case 2 : { // si deux modules
  49. data2 = sensors2; sensors2 = 0;
  50. break;
  51. }
  52. case 3 : { // si 3
  53. data2 = sensors2; sensors2 = 0;
  54. data3 = sensors3; sensors3 = 0;
  55. break;
  56. }
  57. case 4 : { // si 4
  58. data2 = sensors2; sensors2 = 0;
  59. data3 = sensors3; sensors3 = 0;
  60. data4 = sensors4; sensors4 = 0;
  61. break;
  62. }
  63. }
  64. loopCounter++; // for reset management
  65. }
  66.  
  67. // clock signal from S88
  68.  
  69. void clock()
  70. {
  71. // exit bits to next S88 in chain
  72. digitalWrite(dataOut, bitRead(data1,clockCounter));
  73. switch (nbBlocs) // data buffer shift
  74. {
  75. case 1 : {
  76. bitWrite(data1, clockCounter, digitalRead(dataIn));
  77. break;
  78. }
  79. case 2 : {
  80. bitWrite(data1, clockCounter, bitRead(data2,clockCounter));
  81. bitWrite(data2, clockCounter, digitalRead(dataIn));
  82. break;
  83. }
  84. case 3 : {
  85. bitWrite(data1, clockCounter, bitRead(data2,clockCounter));
  86. bitWrite(data2, clockCounter, bitRead(data3,clockCounter));
  87. bitWrite(data3, clockCounter, digitalRead(dataIn));
  88. break;
  89. }
  90. case 4 : {
  91. bitWrite(data1, clockCounter, bitRead(data2,clockCounter));
  92. bitWrite(data2, clockCounter, bitRead(data3,clockCounter));
  93. bitWrite(data3, clockCounter, bitRead(data4,clockCounter));
  94. bitWrite(data4, clockCounter, digitalRead(dataIn));
  95. break;
  96. }
  97. }
  98. clockCounter = (clockCounter + 1) % 16; // bits 0 to 15
  99. }
  100.  
  101. // setup
  102.  
  103. void S88_Setup(int NbBlocs)
  104. {
  105. nbBlocs = NbBlocs;
  106. for (i=4; i<20; i++) { // the first bloc
  107. p

    inMode
    (i,INPUT_PULLUP);
  108. }
  109. switch (nbBlocs)
  110. {
  111. case 2 : { // the second
  112. for (i=22; i<38; i++) {
  113. pinMode(i,INPUT_PULLUP);
  114. }
  115. break;
  116. }
  117. case 3 : { // the third
  118. for (i=22; i<54; i++) {
  119. pinMode(i,INPUT_PULLUP);
  120. }
  121. break;
  122. }
  123. case 4 : { // the fourth
  124. for (i=22; i<70; i++) {
  125. pinMode(i,INPUT_PULLUP);
  126. }
  127. break;
  128. }
  129. }
  130. pinMode(clockS88,INPUT_PULLUP); // S88 clock in input
  131. attachInterrupt(0,clock,RISING); // interrupt int0
  132. pinMode(PSS88,INPUT_PULLUP); // S88 PS in input
  133. attachInterrupt(1,PS,RISING); // interrupt int1
  134. pinMode(dataOut, OUTPUT); // init data out to other Arduino
  135. // or control board
  136. digitalWrite(dataOut,LOW); // led off
  137. pinMode(dataIn,INPUT_PULLUP); // data in from other Arduino
  138. }
  139.  
  140. // loop
  141.  
  142. void S88_Loop()
  143. {
  144. // reset management for ECOS
  145. if (loopCounter == 20) {
  146. bitSet(sensors1,0);
  147. switch (nbBlocs)
  148. {
  149. case 2 : {
  150. bitSet(sensors2,0);
  151. break;
  152. }
  153. case 3 : {
  154. bitSet(sensors3,0);
  155. break;
  156. }
  157. case 4 : {
  158. bitSet(sensors4,0);
  159. break;
  160. }
  161. }
  162. }
  163.  
  164. // update all sensors by group
  165. for (i=4; i<20; i++) {
  166. if (!digitalRead(i)) {
  167. bitSet(sensors1,i-4);
  168. }
  169. }
  170.  
  171. switch (nbBlocs)
  172. {
  173. case 2 : {
  174. for (i=22; i<38; i++) {
  175. if (!digitalRead(i)) {
  176. bitSet(sensors2,i-22);
  177. }
  178. }
  179. break;
  180. }
  181. case 3 : {
  182. for (i=22; i<38; i++) {
  183. if (!digitalRead(i)) {
  184. bitSet(sensors2,i-22);
  185. }
  186. }
  187. for (i=38; i<54; i++) {
  188. if (!digitalRead(i)) {
  189. bitSet(sensors3,i-38);
  190. }
  191. }
  192. break;
  193. }
  194. case 4 : {
  195. for (i=22; i<38; i++) {
  196. if (!digitalRead(i)) {
  197. bitSet(sensors2,i-22);
  198. }
  199. }
  200. for (i=38; i<54; i++) {
  201. if (!digitalRead(i)) {
  202. bitSet(sensors3,i-38);
  203. }
  204. }
  205. for (i=54; i<70; i++) {
  206. if (!digitalRead(i)) {
  207. bitSet(sensors4,i-54);
  208. }
  209. }
  210. break;
  211. }
  212. }
  213. }

Conclusion

En espérant que ma petite contribution répondra aux besoins de certains, cela permet pour tous ceux qui utilisent le bus S88 et qui ne souhaitent pas rentrer dans la complexité du codage de réaliser, de façon simple, rapide et peu chère, une rétro-signalisation avec un grand nombre de capteurs. J’ai testé sur mon ECOS et cela marche très bien et permet à mon logiciel RRTC de prendre les bonnes décisions sur le roulement des trains.

La bibliothèque pour les Nano/Uno

et celle pour les MEGA

59 Messages

Réagissez à « La rétro-signalisation sur Arduino »

Qui êtes-vous ?
Votre message

Pour créer des paragraphes, laissez simplement des lignes vides.

Lien hypertexte

(Si votre message se réfère à un article publié sur le Web, ou à une page fournissant plus d’informations, vous pouvez indiquer ci-après le titre de la page et son adresse.)

Rubrique « Projets »

Un chenillard de DEL

Enseigne de magasin

Feux tricolores

Multi-animations lumineuses

L’Arduino et le système de commande numérique DCC

Un décodeur d’accessoire DCC versatile basé sur Arduino

Un moniteur de signaux DCC

Une barrière infrarouge

Un capteur RFID

Un TCO xpressnet

Une animation sonore

L’Arduino au coeur des systèmes de pilotage analogiques ou numériques

Calcul de la vitesse d’un train miniature avec l’Arduino

La génèse d’un réseau 100% Arduino

Une horloge à échelle H0

Simulateur de soudure à arc

Un automatisme de Passage à Niveau

La rétro-signalisation sur Arduino

Décodeur pour aiguillage à solénoïdes sur Arduino

Un décodeur DCC pour les signaux à deux ou trois feux sur Arduino NANO/UNO

Etude d’un passage à niveau universel

Réalisation pratique d’un système de mesure de vitesse à l’échelle N

Une Passerelle entre le bus S88 et le bus CAN pour la rétro signalisation

Un décodeur DCC pour 16 feux tricolores

Block Automatique Lumineux avec la carte shield "Arduino 4 relays"

Réalisation d’un affichage de gare ARRIVEE DEPART

Ménage à trois (Ordinateur, Arduino, réseau)

Comment piloter trains et accessoires en DCC avec un Arduino (1)

Comment piloter trains et accessoires en DCC avec un Arduino (2)

Comment piloter trains et accessoires en DCC avec un Arduino (3)

Comment piloter trains et accessoires en DCC avec un Arduino (4)

SGDD : Système de Gestion DD (1)

SGDD : Système de Gestion DD (2)

SGDD : Système de Gestion DD (3)

La PWM : Qu’est-ce que c’est ? (1)

La PWM : Qu’est-ce que c’est ? (2)

La PWM : Qu’est ce que c’est ? (3)

La PWM : Qu’est ce que c’est ? (4)

Mise en oeuvre du Bus CAN entre modules Arduino (1)

Mise en oeuvre du Bus CAN entre modules Arduino (2)

Un gestionnaire en C++ pour votre réseau (1)

Un gestionnaire en C++ pour votre réseau (2)

Un gestionnaire en C++ pour votre réseau (3)

Un gestionnaire en C++ pour votre réseau (4)

Réalisation de centrales DCC avec le logiciel libre DCC++ (1)

Réalisation de centrales DCC avec le logiciel libre DCC++ (2)

Réalisation de centrales DCC avec le logiciel libre DCC++ (3)

Contrôleur à télécommande infrarouge pour centrale DCC++

Gestion d’une gare cachée (1)

Gestion d’une gare cachée (2)

Gestion d’une gare cachée (3)

Les derniers articles

Ménage à trois (Ordinateur, Arduino, réseau)


Christian

La PWM : Qu’est ce que c’est ? (4)


Jean-Luc

Block Automatique Lumineux avec la carte shield "Arduino 4 relays"


Christian

Réalisation d’un affichage de gare ARRIVEE DEPART


Gilbert

Contrôleur à télécommande infrarouge pour centrale DCC++


Daniel

La PWM : Qu’est ce que c’est ? (3)


Jean-Luc

Réalisation de centrales DCC avec le logiciel libre DCC++ (3)


bobyAndCo

Un gestionnaire en C++ pour votre réseau (4)


Pierre59

Un décodeur DCC pour 16 feux tricolores


Dominique, JPClaude, Thierry

Réalisation de centrales DCC avec le logiciel libre DCC++ (2)


bobyAndCo

Les articles les plus lus

La PWM : Qu’est-ce que c’est ? (1)

Comment piloter trains et accessoires en DCC avec un Arduino (1)

Ménage à trois (Ordinateur, Arduino, réseau)

L’Arduino au coeur des systèmes de pilotage analogiques ou numériques

Réalisation d’un affichage de gare ARRIVEE DEPART

Comment piloter trains et accessoires en DCC avec un Arduino (3)

La rétro-signalisation sur Arduino

Block Automatique Lumineux avec la carte shield "Arduino 4 relays"

Réalisation de centrales DCC avec le logiciel libre DCC++ (1)

L’Arduino et le système de commande numérique DCC