Dans cet article, on va aborder la programmation de l’Arduino pour produire un signal DCC de 2 manières différentes.
La première méthode oblige à considérer le fonctionnement du Timer et des interruptions, ainsi que les routines d’interruption. C’est une application pratique des articles généraux publiés dans ce site, notamment « Les interruptions (1) » et « Les Timers (I) » et suivants. Elle a pour but de permettre de comprendre les tripes de la technologie, pour ceux qui le souhaitent.
La deuxième méthode fait appel à une bibliothèque toute faite qui permet de cacher ces tripes et aussi de proposer plus de fonctions. Ce sera certainement celle que vous choisirez pour votre projet !
Une première méthode pour produire un signal DCC simple avec Arduino
On a dit précédemment, voir « L’Arduino et le système de commande numérique DCC » que l’envoi des commandes DCC impose de faire travailler notre Arduino en tâche de fond, sous interruption. On va donc utiliser un des timers existants.
Le Timer0 est utilisée par les fonctions delay(), millis(), entre autres.
Le Timer1 est utilisée par la librairie Servo et est le plus précis (16 bits).
La Timer2 est utilisée par la fonction Tone().
On va, dans cet exemple, se servir de Timer2 et, par conséquent, on devra se passer de la production des sons avec Tone() car notre exemple va modifier les valeurs de temps pour satisfaire la norme DCC et donc dérégler la fonction Tone() ;
Le jeu va consister à programmer le timer pour qu’il envoie une interruption à chaque fois que le signal DCC doit changer. Pour les 0, ceci correspond à 50µs et pour les 1, à 29µs. Nous n’allons pas entrer dans les détails de cette programmation car elle fera l’objet d’un article séparé. Tout d’abord, le timer est programmé de manière à ce qu’il s’incrémente toutes les 0,5µs, on appelle ceci un tick du timer. Ensuite, le déclenchement d’interruption sur débordement est validé. L’explication de ce qu’est un débordement est dans l’article « Types, constantes et variables. Il est enfin initialisé à une valeur telle qu’il faut 100 ticks (TIMER_LONG dans le programme qui suit), pour un 0 et 58 ticks (TIMER_SHORT) pour un 1 pour déborder.
Cela correspond à l’initialisation suivante :
/* ------------------- Setup Timer2. -------------------
* Configure le Timer2 de 8-Bit pour générer une interruption
* toutes les 58 ou 100 micro-secondes.
* La durée doit être chargée dans TCNT2 par la routine
* d'interruption ISR(TIMER2_OVF_vect).
*/
#define TIMER_LONG 156
#define TIMER_SHORT 198
void SetupTimer2()
{
//Timer2 Settings: Timer Prescaler /8, mode 0
//Timer clock = 16MHz/8 = 2MHz ou 0,5usec
TCCR2A = 0;
TCCR2B = 0 << CS22 | 1 << CS21 | 0 << CS20;
//Timer2 Overflow Interrupt Enable
TIMSK2 = 1 << TOIE2;
//load the timer for its first cycle
TCNT2 = TIMER_SHORT;
}
Cette fonction est appelée une fois seulement dans la fonction setup().
Grâce à elle, la routine d’interruption ISR(TIMER2_OVF_vect) que l’on verra plus loin, sera appelée automatiquement à chaque fois qu’une transition 0 vers 1 ou 1 vers 0 est nécessaire.
Auparavant on devra déclarer quelques constantes et variables globales qui sont utilisées par cette routine d’interruption :
#define DCC_PIN 4 // Port Arduino qui délivre le signal DCC
#define PREAMBLE 0 // état "envoi du préambule"
#define SEPARATOR 1 // état "envoi du bit start de chaque octet"
#define SENDBYTE 2 // état "envoi des bits de chaque octet"
unsigned char last_timer = TIMER_SHORT; // valeur du Timer en cours
unsigned char flag = 0; // soit bit 1 (court) ou 0 (long)
unsigned char every_second_isr = 0; // demi-impulsion : haut ou bas
unsigned char state = PREAMBLE;
unsigned char preamble_count = 16;
unsigned char outbyte = 0;
unsigned char cbit = 0x80;
ainsi qu’une zone en mémoire qui contient les commandes DCC à envoyer les unes après les autres, en recommençant au début lorsque la dernière est émise.
// ------------------- buffer for command -------------------
struct Message {
unsigned char data[7]; // taille de la plus grande commande possible
unsigned char len; // taille réelle de la commande
} ;
#define MAXMSG 5
struct Message msg[MAXMSG] = {
{{0xFF, 0, 0xFF, 0, 0, 0, 0}, 3}, // message idle
{{locoAdr, 0x3F, 0, 0, 0, 0, 0}, 4}, // vitesse (128 pas) et direction (bit 7)
{{locoAdr2, 0x3F, 0, 0, 0, 0, 0}, 4}, // vitesse (128 pas) et direction (bit 7)
{{locoAdr, 0x80, 0, 0, 0, 0, 0}, 3}, // lumière FL : 0x80 éteinte
{{locoAdr2, 0x90, 0, 0, 0, 0, 0}, 3} // lumière FL : 0x90 allumée
}; // chaque message doit être complété avec les valeurs et le XOR
int msgIndex=0;
int byteIndex=0;
La routine d’interruption
Voici maintenant la routine d’interruption qui effectue l’envoi de chaque bit d’un message DCC et recharge le timer avec la valeur correspondant au délai avant la prochaine transition du signal DCC. Il est nécessaire de fournir quelque explication sur ce rechargement. Entre le moment où l’interruption est déclenchée et le moment ou le timer est rechargé, le temps continue de s’écouler et le timer de s’incrémenter. Par conséquent si le timer était rechargé avec la valeur brute, le prochain délai serait trop important. Il est donc nécessaire d’ajuster cette valeur en lui ajoutant la valeur du timer au moment du rechargement. C’est le rôle de la variable latency qui reçoit valeur du timer et est ajoutée à la valeur brute.
// ------------------- Timer2 overflow interrupt vector handler -------------------
ISR(TIMER2_OVF_vect) {
//Capture la valeur courante de TCTN2.
//Permet de corriger le temps de latence de l'interruption.
//Recharge le Timer.
// Une interruption sur 2, inversion seulement du signal (seconde moitié du bit)
if (every_second_isr) {
digitalWrite(DCC_PIN,1);
every_second_isr = 0;
// mise à jour du Timer
latency=TCNT2;
TCNT2=latency+last_timer;
} else { // != passage au bit ou état suivant
digitalWrite(DCC_PIN,0);
every_second_isr = 1;
switch(state) {
case PREAMBLE:
flag=1; // bit court
preamble_count--;
if (preamble_count == 0) { // vers état suivant
state = SEPARATOR;
// message suivant
msgIndex++;
if (msgIndex >= MAXMSG) { msgIndex = 0; }
byteIndex = 0; //index 0 du premier octet
}
break;
case SEPARATOR:
flag=0; // bit long
// état suivant
state = SENDBYTE;
// octet suivant
cbit = 0x80; // bit à envoyer le coup suivant
outbyte = msg[msgIndex].data[byteIndex];
break;
case SENDBYTE:
if (outbyte & cbit) {
flag = 1; // bit court
} else {
flag = 0; // bit long
}
cbit = cbit >> 1;
if (cbit == 0) { // dernier bit, vers octet suivant
byteIndex++;
if (byteIndex >= msg[msgIndex].len) {
// fin du message
state = PREAMBLE;
preamble_count = 16;
} else {
// envoi du bit 0 séparateur avant octet suivant
state = SEPARATOR ;
}
}
break;
}
if (flag) { // 1 bit court
latency=TCNT2;
TCNT2=latency+TIMER_SHORT;
last_timer=TIMER_SHORT;
} else { // 0 bit long
latency=TCNT2;
TCNT2=latency+TIMER_LONG;
last_timer=TIMER_LONG;
}
}
}
Génération de la trame DCC
D’abord, chaque bit comprend une demi-période à l’état bas (0) et une demi-periode à l’état haut (1). A la fin de cette demi-période, on doit passer au bit suivant en parcourant la zone mémoire de message, octet par octet (chargé dans la variable outbyte = msg[msgIndex].data[byteIndex]).
Pour organiser cette promenade, on utilise un automate avec switch (state) et 3 états possibles pour state :
PREAMBLE : tant qu’on ne tombe pas sur un 0, on envoie des 1
SEPARATOR : on envoie le 0 qui marque le début de l’octet suivant
SENDBYTE : on envoie les bits de chaque octet du message
A la fin d’un message on passe au suivant. A la fin du dernier, on recommence au premier.
Les 5 messages dans l’exemple sont :
Un message IDLE ;
2 commandes de vitesse ;
2 commandes de lumière.
donc pour piloter 2 locomotives.
Cette méthode a l’avantage d’être assez simple, mais elle a l’inconvénient de nécessiter la connaissance au bit près des commandes DCC.
J’ai vite trouvé cette méthode extrêmement fastidieuse et j’ai cherché une autre méthode.
Je suis finalement tombé sur le site de Railstar [1] qui propose une librairie disponible librement en Open Source.
La librairie CmdrArduino
Il s’agit maintenant d’une librairie, ce qui signifie qu’il n’est plus nécessaire de copier/coller du code dans votre application mais seulement d’appeler des fonctions, Nous verrons cela dans un prochain article.
Lorsque la librairie est installée, il suffit d’aller dans le menu Fichier/Exemples/CmdrArduino et de choisir l’exemple CmdrArduino_minimum :
/********************
* Centrale DCC minimum avec un potentiomètre de vitesse connecté
* sur le port analogique 0,
* un bouton poussoir connecté entre le 0V et l'entrée digitale 4
* Le signal DCC est délivré sur la Pin 9, et est capable de piloter
* un booster à base de LMD18200 directement.
********************/
#include <DCCPacket.h>
#include <DCCPacketQueue.h>
#include <DCCPacketScheduler.h>
DCCPacketScheduler dps;
unsigned int analog_value;
char speed_byte, old_speed = 0;
byte count = 0;
byte prev_state = 1;
byte F0 = 0;
void setup() {
Serial.begin(9600);
dps.setup(); // initialisation de la librairie
// Bouton sur la pin 4
pinMode(4, INPUT_PULLUP);
}
void loop() {
// Lecture de l'état du bouton pour la commande de lumière F0
byte button_state = digitalRead(4); //high == relaché; low == appuyé
if(button_state && (button_state != prev_state))
{
// inversion de l'état
F0 ^= 1;
Serial.println(F0,BIN);
dps.setFunctions0to4(3,DCC_SHORT_ADDRESS,F0);
}
prev_state = button_state;
// Potentiomètre de vitesse
analog_value = analogRead(0);
speed_byte = (analog_value >> 2)-127 ;
// Ramène la gamme 0-1023 à +126-126, l'arrêt étant le point milieu du potentiomètre
if(speed_byte != old_speed)
{
if(speed_byte == 0) // On évite l'arrêt brutal (e_stop) en remplaçant le 0 par 1
{
if(old_speed > 0) speed_byte = 1;
else speed_byte = -1;
}
Serial.print("analog = ");
Serial.println(analog_value, DEC);
Serial.print("digital = ");
Serial.println(speed_byte, DEC);
dps.setSpeed128(3,DCC_SHORT_ADDRESS,speed_byte);
old_speed = speed_byte;
}
// Cet appel est impératif pour permettre à la librairie de faire son travail
dps.update();
}
Explications :
On réalise le montage suivant avec :
Un Arduino Uno
Un module LMD18200
Un potentiomètre de 10K
Un bouton poussoir
Une alimentation 12 volts
On supposera que l’Arduino est alimenté via le câble USB relié à l’ordinateur
Ensuite on installe la librairie CmdrArduino, on charge le programme ci-dessus et cela doit marcher du premier coup, si la loco placée sur les rails est bien configurée avec l’adresse DCC 3.
Il faut placer le potentiomètre au milieu avant d’alimenter le circuit.
La loco avance quand on pousse le potentiomètre d’un coté, et recule de l’autre coté.
Un appui sur le bouton allume les phares de la loco. Un autre appui les éteint.
Bien entendu cet exemple est le plus simple qu’il soit possible de réaliser. Il démontre vite que nous devons aller plus loin. Par exemple :
Il serait plus pratique d’avoir un inverseur de Direction et utiliser toute l’excursion du potentiomètre pour la vitesse.
On voudrait piloter plusieurs locomotives.
On voudrait commander d’autres fonctions de la machine et des accessoires.
Etc..
Rassurez-vous, on va y arriver !
Tout d’abord nous allons explorer la librairie CmdrArduino, les fonctions qu’elle propose. Ce sera l’objet de l’article suivant.
Puis nous reviendrons sur la construction d’une centrale plus complète pour conclure cette série d’articles.
J’ai une interrogation, peut-être pourrez-vous m’apporter de l’aide ?
Sachant que je suis en LENZ DCC et que j’ai un deuxième transfo LENZ, avec un Arduino il devrait être possible de demander un arrêt dans une zone isolée (suite de 0) avec une commutation par relais (reviendrait moins cher que le générateur de frein DCC actuel (transfo, LV100, LG100)
Si oui, pensez vous que ce soit simple à mettre en place ?
Bonjour Didier,
Vous pouvez tout simplement utiliser un BM1 (en fait son équivalent en montage "maison" ; coût : 1 à 1,5 eur) et un relais dont un contact shunt ou active ce BM1. Le relais étant, naturellement, piloté par Arduino.
C’est ce que j’ai fait pour les dix voies de garage sur mon réseau.
Cordialement
Philippe
Un BM1 est un module de Lenz qui sert à déclencher un arrêt progressif d’une loco équipée d’un décodeur réagissant au système ABC (décodeur Lenz ou ESU - je ne connais pas pour les autres marques -).
Ce BM1 (ou son clone) produit une dissymétrie du signal qui est interprétée comme un ordre d’arrêt.
Pour les décodeurs LENZ, il faut mettre 3 dans le CV 51. On peut ensuite indiquer la longueur de freinage avec le CV52 ; ce qui permet d’avoir un arrêt des trains toujours au même endroit.
Avec deux BM1 (ou leur clone), et en mettant 11 dans le CV51, on peut faire des "va et vient" sans problème.
Pour la valeur du CV52 (longueur de freinage, il faut faire des essais car les locos ne réagissent pas de la même façon, leur mécanique n’ayant pas la même "inertie".
Bonjour,
Merci pour cette question à laquelle je vais commencer par répondre... par des questions :
D’abord je ne sais pas ce qu’est un transfo LENZ (est-ce un booster qui génère aussi du DCC ?).
A priori, s’il y a une zone isolée (isolée comment ?, est-ce un canton ? comporte-t-elle un détecteur d’occupation ? A quoi servirait le relai ?), oui on peut envoyer des paquets DCC d’arrêt.
N’importe quelle loco devrait s’arrêter (attention aux court-circuit au moment où la loco est à cheval sur la zone isolée et la zone précédente !!!).
Et après, pour la faire repartir, il faut connaitre son adresse DCC, mais comment ?
Sujet intéressant d’autant que je ne connais pas les centrales LENZ.
Dominique
le transfo lenz est un transfo 3A en AC (TR100), je pensais qu’avec un ILS ou une détection par courant nous pourrions demander l’envoi du message avec un temps de retard (ordre d’arrêt général, mais seule une loco sur la zone concernée reçoit l’info).
La commutation se fait par un relais (2RT) et quand il faut relancer la loco, le relais renvoit les infos de la centrale DCC (qui a gardé les infos de vitesse, sens etc ...) donc redémarrage également en douceur en fonction des réglages du décodeur.
La différence avec une coupure nette sans courant, est le fait de garder les lumières et la détection par courant.
Je ne sais pas si j’ai été très clair. Je peux faire un schéma si besoin (pdf, jpeg ...)
Si j’ai bien compris, la zone est isolée par le relai et est,
soit alimentée par une centrale Arduino (à construire) qui n’envoie que des IDLE pour alimenter le décodeur de la loco et son moteur, puis une commande d’arrêt général DCC après détection par courant, ILS ou IR
soit alimentée par la centrale LENZ du reste du réseau et dans ce cas, la loco repart bien.
Cela pourrait marcher mais avec le problème du court-circuit au passage à cheval sur les 2 zones, qui pourrait mettre les centrales à l’arrêt. Il faudrait synchroniser les signaux DCC des 2 centrales, ce qui est compliqué. Il y a aussi la transition entre les signaux DCC des 2 centrales à la commutation du relai. Quid du comportement du décodeur. A priori il devrait ignorer.
C’est cela, en gros c’est le principe du générateur de frein lenZ LG100.
On peut peut être éviter le court circuit en décalant de 1 sec l’envoi de l’info de façon à ce que la loco soit déjà dans la zone d’arrêt ?
C’est une réflexion, une piste mais merci de m’avoir consacré un peu de temps. En dehors du DCC, pour les aiguillages, la détection, les feux l ’Arduino c’est génial.
C’est pas si simple que ça !
S’il n’y a pas de DCC (avec des idle) en permanence, la loco va s’arrêter net en arrivant dans la zone, faute d’alimentation.
Donc il faut envoyer du DCC en permanence et le risque de court-circuit est toujours vivant (comme le canard !).
Personnellement je ne fais pas comme cela : j’alimente le DCC partout et j’envoie des commandes spécifiques aux locos. Reste qu’il faut savoir quelle est la loco qui entre dans la zone car il faut connaitre son @dcc. C’est tout l’art des détecteurs (notamment RFID ou code barre) et du block system. Mais ça fait un paquet de soft (on y viendra).
En attendant il y a peut-être une autre solution et c’est chouette d’essayer de la trouver.
Je viens de regarder les forums qui en parlent. Effectivement il faut un module LG100 + un booster + un relai + un détecteur de présence. Le problème des court-circuits est évoqué.
Mais une petite centrale Arduino avec son booster peut très bien remplacer le couple LG100+Booster LV100.
Le reste devrait rester conforme à la doc du LG100.
C’est très facile : vous faites une recherche Internet avec le libellé "LMD18200 ebay" et vous trouvez plusieurs vendeurs de composants et de modules. Je vous recommande plutôt le module tout fait que l’on trouve entre 10 et 20 Euros.
Par précaution, prenez en 2 d’emblée. En général le port est gratuit.
On ne peut pas relier directement l’Arduino tel que décrit dans cette série d’articles avec un SPROG dont l’entrée est de type USB (le schéma interne du SPROG montre des lignes série Tx et Rx mais je n’ai pas d’information pour savoir comment les utiliser).
De plus le SPROG est conçu pour être commandé via USB avec un protocole de commande de type "texte" par des logiciels tels que RocRail ou JMRI.
Un Sprog contient un micro-controlleur et un "booster" tel que décrit dans cet article (pont en H de transistors de puissance). C’est équivalent à la combinaison de notre Arduino et d’un LMD18200, sauf que vous ne pouvez pas programmer le PIC qui se trouve à l’intérieur comme un Arduino.
On abordera peut-être un jour une manière de piloter un Sprog avec Arduino, mais je n’en vois pas l’interêt à court terme (sauf pour les heureux possesseurs de cette bestiole :-). Nous aborderons alors une architecture totalement différente du cas simple que nous traitons maintenant.
Connecter JMRI (ou autre logiciel de gestion de réseau) à un Arduino est relativement facile sur le plan technique puisqu’on a à faire à un mode commande de type "ligne de commande" (texte) que l’Arduino n’aurait qu’a "parser" (analyser).
Après avoir dit cela, la question est "pour faire quoi ?"
Si c’est pour cloner une SPROG ou d’autres centrales du commerce, alors ça ne vaut pas le coup, vu les prix très abordables de ces centrales.
La question de la rétro signalisation fait, à mon avis, que la réflexion se porte ailleurs, notamment dans ses interactions avec la centrale.
je vous conseille de suivre de près LOCODUINO où ces sujets seront progressivement abordés.
Très intéressé par vos articles sur le DCC j’ai réalisé le montage de la centrale DCC minimum avec un Arduino Nano et téléchargé le logiciel ainsi que les bibliothèques qui vont avec.
Malheureusement je n’ai pas à ce jour réussi à le faire fonctionner, le moteur de la locomotive tourne de façon tout à fait aléatoire, indépendamment de l’adresse que l’on peut mettre dans le logiciel.
Les signaux DCC contrôlés en sortie a l’Oscilloscope ont une amplitude et une durée correcte.
Le décodeur utilisé est un KUEHN N45 a été testé avec SPROG II + PC et fonctionne parfaitement.
L’Arduino Nano a été remplacé par un Arduino Méga, fonctionnement toujours identique.
Il semblerait qu’au lieu d’envoyer une seule adresse DCC le logiciel envoie une rafale d’adresses parmi lesquels se retrouve de temps en temps l’adresse de la locomotive (?)
Pour pouvoir vous aider, il faudrait au moins m’envoyer votre sketch et me décrire votre montage et votre environnement de travail (PC ? Est-ce que l’IDE Arduino fonctionne bien ?) et que je puisse apprécier votre expérience.
Les exemples donnés dans ces articles ont été testés et fonctionnent correctement... sauf s’il y a une erreur quelque part !
Je vous conseille néanmoins de laisser tomber le premier exemple de cet article que je considère un peu comme un exemple "à ne pas faire", mais qui sert à expliquer la technique.
Installez plutôt la librairie Cmdrarduino, dont vous pouvez tester les exemples sans attendre le soft de ma centrale, bien plus compliqué, qui viendra avec l’article 4.
Si c’est le cas, on en revient à ce que j’indique au début de cette réponse (trouver l’erreur).
Bonjour
Merci pour votre réponse, le sketch utilisé est effectivement l’exemple de la librairie Cmdrarduino.
Je pense avoir trouvé la cause du non fonctionnement, il s’agit du signal DCC en sortie du booster qui n’est pas centré autour du zéro Volt mais qui varie entre 0V et +12 V au lieu de varier entre -12 V et +12 V.
Il ne me reste plus qu’à en trouver la raison, (j’utilise comme booster un L298 dont je disposais, à la place du LM 18200) mais je pense que les deux sont compatibles dans cette fonction (?)
Merci pour votre intérêt pour le DIY de la centrale DCC.
Vous démarrez avec l’exemple de l’article N°1, donc progressivement ce qui est bien. Mais sachez que cet exemple ne génère des commandes DCC que vers une locomotive programmée avec l’adresse 3 (comme toute locomotive neuve sortant d’usine).
Si vous avez modifié l’adresse de vos locos, c’est normal que ça ne marche pas.
Si l’adresse est bien 3, alors il se peut aussi que vous ayez utilisé un potentiomètre qui "crache".
Je vous encourage à lire les articles suivants de cette série où vous trouverez des réponses à plein de questions.
Bonjour,
C’est un grand classique : NON le L298 n’est pas compatible avec le LMD 18200.
Avant de démarrer la construction de ma centrale, j’ai lu quantités de Forums sur ce sujet. Cette série L298 pose des problèmes. Laisser tomber est mon meilleur conseil, même si on en trouve partout à pas cher.
D’ailleurs on trouve aussi facilement des modules LMD18200 !
Mais on n’en parle pas assez, alors je le dis !
Vous êtes sur la bonne voie maintenant.
Tenez moi au courant de la suite.
Bon, j’ai remplacé le L298 par un LMD 18200 et tout s’est mis à fonctionner instantanément !
Je ne sais pas trop quelle conclusion en tirer sauf que le L298 fonctionne très bien en tant que Booster PWM mais ne semble pas trop apprécier les signaux DCC ...
J’ai consulté les datasheets des deux composants et le L298 n’a pas du tout les mêmes caractéristiques que le LMD 18200. Les retards entre le changement d’une entrée du L298 et le changement correspondant de la sortie sont asymétriques. C’est à dire que les retards ne sont pas les même selon que le signal d’entrée passe de 0 à 1 ou de 1 à 0 (ce qui n’est pas bon pour le DCC puisque les informations sont codées par le temps). Selon l’entrée qui change (EN ou IN) la différence de délai est de 0,5µs ou de 0,9µs. Le LMD 18200 présente lui des délais quasi identiques avec une différence de seulement 0,1µs. Dans les datasheets, les conditions de test sont très différentes. Le LMD 18200 est testé avec une charge capacitive de 2200µF plus une charge résistive de 2 x 12Ω et présente avec 42V des temps de montée et de descente des signaux de 0,08 à 0,1µ et de 0,07 à 0,075µs dans ces conditions qui sont plus sévères que ce que l’on a sur un réseau. Le L298 n’est testé qu’avec une charge résistive de 20Ω également avec 42V et présente des temps de montée et descente comparables au LMD 18200 alors qu’il n’y a aucune charge capacitive. Comment se comporte-t-il avec des capas parasites ? moins bien sans doute.
Conclusion : le L298 altère les signaux DCC au point que les décodeurs y perdent leur latin.
Merci pour cette analyse comparative du L298 et du LMD 18200 qui donne un début d’explications au mauvais fonctionnement du L298 dans la fonction de booster de trames DCC.
Même si une différence dans le temps d’établissement de la sortie de 0.9 µs peut paraître faible comparée à la durée des niveaux Zéros et Un (respectivement 110 et 58 us ), la réponse tient peut-être dans le mode d’échantillonnage à l’entrée des décodeurs plus ou moins susceptible selon les marques.
Oui, la tolérance des décodeurs doit jouer. Des temps de montée et de descente paresseux peuvent également amener des durées hors de la gamme admise par la norme (entre 55 et 61μs)
Bonsoir,
Merci pour ces différents articles
Je suis à la recherche d’un dispositif me permettant de commander des décodeurs d’accessoire à partir d’un programme Arduino. J’ai donc trouvé le dispositif.
Mais une question : peut-on brancher en même temps une centrale/booster DCC et le dispositif à base d’une carte Arduino et d’un module LMD18200 ?
D’avance merci pour votre retour
FF
J’ai développé un programme Arduino qui permet de simuler (les bases) les enclenchements d’un poste d’aiguillage.
Ce programme est prévu pour fonctionner avec des relais.
Mais pourquoi ne pas générer un paquet DCC qui permettrait si rien ne s’y oppose de manœuvrer une aiguille ou un signal ?
D’où ma question sachant que la carte Arduino ne servira qu’à cela. Le pilotage des locomotives sera géré par la centrale DCC.
A vous lire, FF
Vous avez donc, d’un coté, une centrale DCC pour piloter les trains. Et d’un autre coté un système de commande d’enclenchements de signaux (la version opérationnelle du simulateur à base d’Arduino).
Le solution n’est évidemment pas de passer par le DCC pour le second système, mais de commander les signaux directement par l’Arduino indépendamment de la traction et sans passer par des décodeurs d’accessoires.
Je vous invite à regarder l’article L’Arduino au coeur des systèmes de pilotage analogiques ou numériques qui vous donnera plus de détails sur les architectures possibles.
Bien cordialement
Dominique
Félicitations pour votre site, toutefois, j’aimerais en tant qu’enseignant/chercheur en génie électrique revenir un peu sur le vocabulaire.
1/ Booster :
Le convertisseur dit "booster" ne booste rien et en particulier il ne booste pas le signal de commande DCC.
Nous avons un hacheur dit 4Q (pour 4 quadrants ou pont en H, cf. votre article http://www.locoduino.org/spip.php?a...) réversible en tension et en courant dont la tension de sortie moyenne varie entre -15V à 15V.
Ce convertisseur n’est donc pas un ’booster’ car la tension de sortie n’est pas supérieure à la tension d’entrée de 15V. Il ne faut donc pas parler de booster, boost qui laisse à penser au hacheur élévateur de tension en électronique de puissance.
Par ailleurs, la phrase suivante est incorrecte : Le signal DCC généré par notre Arduino est appliqué à l’entrée DIR qui commande l’ouverture de 2 transistors/commutateurs et la fermeture des 2 autres, de telle sorte que le courant envoyé aux rails est soit dans un sens, soit dans l’autre sens.
C’est la tension qui change de signe via le pont en H.
2/ Signal DCC
Le signal DCC est un signal de commande permettant d’organiser le fermeture et l’ouverture des interrupteurs. Avec un hacheur 4Q, nous pouvons imposer 4 niveaux de tension : +15V, 0V selon deux configurations des diodes de roue libre et enfin -15V.
Pour générer un signal +15/-15V, nous utilisons une "commande bipolaire" en pilotant en même temps les interrupteurs sur la diagonale, puis l’anti-diagonale.
Dans le cas, la tension moyenne de sortie est (2*alpha-1) Udc, ou alpha est le rapport cyclique et Udc la tension de l’alim à 15V.
3/ L298 vs LMD 18200
D’un point de vue théorique, les 2 composants peuvent être utilisés. Toutefois, l’utilisation du L298 va nécessiter de retoucher le code pour avoir DIR LMD 18200 = IN1 L298 = NOT (IN2 L298) avec ENA (L298) = high et retrouver la commande bipolaire.
Je vous remercie pour ces remarques : on n’est jamais trop précis.
J’ai emprunté le mot "booster" à la littérature anglo-saxone et également française, sachant que ce n’est pas la tension qui pourrait être "boostée" ici, mais seulement le courant pour passer de quelques milliampères de l’Arduino à quelques ampères sur les rails. Il y a aussi cette fonction de hacheur 4Q qui permet d’inverser la tension.
Il se trouve que certains modélistes ont pu utiliser avec succès, au début du DCC, un simple amplificateur audio BF.
Pour le choix entre L298 et LMD18200, il suffit de compiler les diverses expériences présentées sur le Web pour préférer le LMD18200. C’est aussi mon expérience qui n’a jamais été déçue pour le DCC. Mais je conçois que le L298 puisse être utilisé aussi, ce que je peux pas garantir, faute de l’avoir expérimenté, même si quantité de robots sont pilotés par ce type de circuit.
Je serais très intéressé (ainsi que les lecteurs de Locoduino) par de plus amples développements de votre part, notamment dans le Forum, pour compléter mon article dont je vais déjà corriger les inexactitudes.
Je me suis lancé dans la réalisation d’un contrôleur analogique (en PWM) à base d’arduino et d’un module IBT_2 (utilisant un driver de pont en H BTS7960 - http://www.alldatasheet.fr/datashee...)destiné initialement à l’alimentation de trains jouets anciens (JEP ...). Pour ce contrôleur, j’utilise aussi et optionnellement un LM298 afin de commander un fader motorisé.
J’ai fait le choix de l’IBT_2 pour la commande en raison de ses tensions et puissances élevées, l’objectif étant de soutenir 5A sous 20V sans sourciller.
A la lecture de cet excellent article, je pourrais peut-être envisager de "digitaliser" mon contrôleur afin de le rendre aussi (et optionnellement) compatible DCC bien que le mode ’timer 2’ ne m’arrange pas. J’aurais souhaité votre avis sur les caractéristiques du BTS7960 comparativement au LMD18200 qui semble être la référence pour le DCC. A première vue ce dernier semble bien moins solide, mais, les caractéristiques (timings .. )du BTS sont-elles adaptées au DCC ?
Dans l’attente de votre précieux éclairage ... Hervé
Son prix est équivalent à celui du LMD18200, je vais donc en commander un pour essayer.
Pour les caractéristiques, je dois regarder de plus près la fiche car les temps de montée et descente sont cruciaux pour le DCC.
Par contre l’interface avec l’Arduino semble différente de celle du LMD18200, l’exemple donné dans la fiche utilisant 5 broches au lieu de 2 pour le LMD. Ou alors il faut ajouter un peu de logique, ce qu’il y a peut-être sur le breadboard cité par le lien.
N’oublions pas que le circuit est piloté sous interruption et avec un timer (2) à partir d’une bibliothèque (CmdrArduino, et versions plus recentes), donc il est surement plus facile de l’adapter que de modifier la bibliothèque.
Donc je complèterai ma réponse un peu plus tard. Peut-être trouverez-vous les réponses avant moi si vous possédez déjà le circuit.
Néanmoins, être capable de fournir 43 A maximum sur un circuit ferroviaire en DCC ou en PWM me semble un peu dangereux !!! J’ai déjà vu de la fumée s’échapper d’un court-circuit sur le LMD18200 (environ 5 A maxi) entre une roue et une flèche d’aiguille mal positionnée, avant que je mette en place la détection de courant et la gestion des court-circuits.
Mais là, avec un potentiel de 40 A (si j’ose dire, pour faire hérisser les cheveux des électroniciens :), il y a de quoi déclencher un incendie : donc soyez prudents et n’oubliez pas la mesure de courant et détection de court-circuit décrite dans l’un des articles suivants.
Je vous remercie bien de l’intérêt que vous portez à ma question ... L’application aux "voitures électriques" n’est à priori qu’un exemple, le nom générique du module est "IBT-2" et je n’ai vu nulle part de référence à un domaine d’application particulier.
Pour ce qui est de l’interfaçage, c’est un "double-demi" pont en H - C’est à dire qu’il est capable de commander 2 moteurs (CC) dans un seul sens de rotation ou 1 moteur (CC) avec inversion du sens de rotation. Vous trouverez ici (http://wordpress.bonairetec.com/?p=75) un exemple de librairie (assez discutable d’ailleurs).
En ce qui me (nous) concerne :
Les pin X_IS (status/puissance) peuvent être reliées entre elles sur une entrée.
Les pins X_EN (Enable/Frein) peuvent être reliées entre elles sur une sortie.
Le sens et vitesse de rotation étant défini par l’impulsion PWM délivrée sur R_PWM ou L_PWM.
Dans le cadre du DCC (ce qui n’est pas encore l’ambition de mon projet), la polarité de sortie n’a peut être pas d’importance et dans ce cas, l’utilisation d’un seul demi-pont est peut être suffisante.
Hervé
PS : Je me suis amusé à regarder aujourd’hui à l’osciloscope le signal présent sur les rails d’un circuit de slot-car Carrera Digital 1/43eme ... Il y a aussi peut être moyen de faire quelque chose avec l’Arduino ...
En DCC, l’Arduino génère un signal carré sur une seule Pin, à partir d’un de ses Timers internes.
Les hacheurs 4Q utilisés pour obtenir de la puissance avec le signal DCC ont 4 états dont seuls 2 sont utilisés en DCC. En général ces hacheurs ont 2 pins d’entrée pour commander les 4 états.
Donc il faut que la logique d’interface avec l’Arduino puisse convertir le signal DCC sur une pin de l’Arduino en une paire de signaux complémentaires pour le hacheur.
Certaines cartes comme le LMD18200 ou le shield pour moteur Arduino ou le Pololu Dual MC33926 disposent de cette logique interne qui permet un interfaçage direct avec l’Arduino.
Je ne connais pas encore l’IBT-2 pour vous dire s’il s’interface aussi facilement. Mais j’en ai commandé un.
A suivre ...
Nous allons faire des essais, mais il semble qu’elle accepte différents types de hacheurs dont ceux des cartes d’interface bi-moteur d’Arduino et de Pololu.
Après de premiers essais en analogique, je me suis intéressé à la commande en DCC et j’ai suivi avec un immense intérêt les 4 articles sur le sujet ; je ne peux que vous remercier pour ces contributions et por la réelle qualité de la rédaction et de l’approche.
Ma première réalisation a été l’équipement d’une de mes locos avec un décodeur LENZ standard+ (#10231) que j’ai commandé par la centrale DCC minimale citée en exemple de la librairie CmdrArduino (potentiomètre et 1 bouton poussoir de fonction).
Maintenant, je souhaite aller plus loin et utiliser une télécommande infrarouge pour commander les locos et leurs fonctions et surtout pour régler les CV. Pour moi, l’utilisation de la télécommande offre deux avantages principaux :
Plus besoin de liaison par fil ;
La construction mécanique de la centrale est réduite à sa plus simple expression (pas de clavier, d’inverseurs mécaniques, etc.).
Quand cela fonctionne évidemment…
Car j’ai un problème que je n’arrive pas à résoudre. Mon équipement comprend une Arduino UNO complétée
D’un module booster LMD18200
D’un écran LCD 16x2 commandé en I²C
Un récepteur Ir TSOP 4838
L’idée est assez simple : décoder les infos transmises par la télécommande et les transmettre à la loco via les instructions de la librairie CmdrArduino.
Cela fonctionne bien sauf que la réalisation souffre d’un défaut très gênant et que je ne parviens pas à résoudre : dès la mise sous tension ou après un reset de la carte, il faut émettre une dizaine de commande avec la télécommande avant que la commande de vitesse ne soit efficace. Le problème ne vient pas de la télécommande Ir, car je suis certain que l’ordre est bien transmis et reçu ; en effet, l’écran LCD est là pour confirmer la réception du bon ordre. J’ai soupçonné un problème d’incompatibilité entre les librairies CmdrArduino et IRremote et j’ai opté pour une autre(Irlib) mais sans succès ; en désespoir de cause, j’ai contourné le problème en envoyant artificiellement par une boucle WHILE en début de programme 30 codes de vitesse vers la carte ; mais je n’aime pas cette solution car elle ne résoud pas vraiment le problème et cela ne me rassure pas pour la suite.
Cela ressemble à un conflit entre les Timers utilisés dans les 2 bibliothèques.
Pouvez-vous m’envoyer votre code en message privé ? Et le lien vers la bibliothèque IR.
Dominique
Je pense que le souci ne vient que de l’absence de répétition des commandes DCC de vitesse, la bibliothèque CmdrArduino ayant une faiblesse sur ce point.
Il faut donc répéter les commandes de vitesse plusieurs fois par seconde, certains décodeurs n’exécutant les commandes qu’après 1 ou 2 répétitions.
Vous aviez raison. Le souci venait vraisemblablement du manque de répétitions. J’ai revu le code (ci-dessous) en provoquant un rafraîchissement, suivant votre méthode, toutes les 200 msec et cela fonctionne parfaitement.
Je joins le code à toutes fins utiles (dans l’état actuel, il ne sert qu’à tester la solution).
Un grand merci pour votre aide !
/*
* Croquis basé sur la référence suivante à laquelle j'ai ajouté une adaptation de l'exemple repris dans la librairie accompagnant le
display I2C/TWI LCD1602 de DFROBOT, article TOY0046 :
* Avec télécommande PANASONIC DVD/TV
* Version V6 24-03-2016 : suite modifications Dominique
Le display I2C LCD1602 est raccordé comme suit : SDA à la pin analog4 et SCL à la pin analog5 de l'Arduino; attention dans certaines docs ces 2 pins sont inversées à tort.
Le capteur IR TSOP 4838 est raccordé comme suit à l'Arduino :
Pin 1 (à gauche lorsque le capteur est vu de face) = Vout (pin 3 de l'Arduino)
Pin 2 (au centre) = GND raccordée à un GND de l'Arduino
Pin 3 (à droite lorsque le capteur est vu de face) = Vcc (+5v de l'Arduino)
Le signal à destination du LMD18200 part de la pin 9
*/
/*******************CODE********************/
#include <IRLib.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DCCPacket.h>
#include <DCCPacketQueue.h>
#include <DCCPacketScheduler.h>
//definition des codes de la telecommande Panasonic
//telecommande Panasonic lib IRLib
#define arrow_up 3796283338
#define arrow_down 989538004
#define arrow_left 1296259434
#define arrow_right 3138313506
#define digit_0 950179491
#define digit_1 1366498449
#define digit_2 1242645753
#define digit_3 577270721
#define digit_4 278230305
#define digit_5 3236444089
#define digit_6 2050858721
#define digit_7 1376882089
#define digit_8 1077841673
#define digit_9 809146499
#define button_pause 2860196199
#define button_play 3737721253
LiquidCrystal_I2C lcd(0x20, 16, 2); // attention! Lorsque tous les 3 jumpers sont placés (réglage d'usine) l'addresse LCD est 0x20
int IRpin = 3;
IRrecv My_Receiver(IRpin);
IRdecode My_Decoder;
IRdecodeHash My_Hash_Decoder;
DCCPacketScheduler dps;
unsigned int analog_value;
int old_speed = 0;
byte count = 0;
byte prev_state = 1;
byte F0 = 0;
int timerefresh = 200 ;//frequence de rafraichissement des commandes vitesse (msec).
int vit_abs = 0; //valeur absolue de la vitesse
int vit = 0; //consigne de vitesse a envoyer a la loco
int sens_marche = 1; // seulement deux valeurs possible de sens de marche : 1= AV, -1 = AR
int lumiere = 0; //a utiliser pour la fonction lumiere
int long time = 0; // mesure du temps avant répétition
int timebcl = 0; // mesure du temps de boucle
int oldtimebcl = 0; // mesure du temps de boucle
void setup()
{
lcd.init(); // initialisation du LCD
lcd.backlight(); // allumage retroeclairage
Serial.begin(9600);
My_Receiver.enableIRIn();
dps.setup(); // initialisation de la librairie
}
void loop()
{
//rafraichissement des commandes vitesse et fonctions
timebcl = millis();
int tbcl = timebcl - oldtimebcl;
if (tbcl > 5) //affichage du temps de boucle seulement lors de commande ir (temps boucle superieur a 5 msec)
{
Serial.println(timebcl - oldtimebcl);
}
oldtimebcl = timebcl;
if ((time + timerefresh) < millis())//instruction de rafraichissement regulier des commandes de vitesse (tous les timerefresh msec)
{
time = time + timerefresh;
SR_500();
}
if (My_Receiver.GetResults(&My_Decoder))
{
My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
My_Decoder.decode();
lcd.clear();
lcd.setCursor(0, 1);
dps.update();
My_Hash_Decoder.decode();
switch (My_Hash_Decoder.hash)
{
case arrow_up:
lcd.print("UP");
//limitation de montee a 127
if (vit_abs < 127) {
vit_abs = vit_abs + 1;
}
break;
case arrow_down:
lcd.print("DOWN");
//limitation de descente à 0
if (vit_abs > 0) {
vit_abs = vit_abs - 1;
}
break;
case arrow_left:
lcd.print("LEFT");
if (sens_marche == 1) {
vit_abs = -1;
}
sens_marche = -1;
break;
case arrow_right:
lcd.print("RIGHT");
if (sens_marche == -1) {
vit_abs = 1;
}
sens_marche = 1;
break;
case digit_0:
lcd.print("=0=");
vit_abs = 1;
break;
case digit_1:
lcd.print("=1=");
vit_abs = 15;
break;
case digit_2:
lcd.print("=2=");
vit_abs = 25;
break;
case digit_3:
lcd.print("=3=");
vit_abs = 35;
break;
case digit_4:
lcd.print("=4=");
vit_abs = 48;
break;
case digit_5:
lcd.print("=5=");
vit_abs = 55;
break;
case digit_6:
lcd.print("=6=");
vit_abs = 65;
break;
case digit_7:
lcd.print("=7=");
vit_abs = 75;
break;
case digit_8:
lcd.print("=8=");
vit_abs = 85;
break;
case digit_9:
lcd.print("=9=");
vit_abs = 95;
break;
case button_pause:
lcd.print("PAUSE");
vit_abs = 30;
break;
case button_play:
lcd.print("PLAY");
vit_abs = 127;
break;
}
//envoi de la commande de vitesse a la loco
vit = vit_abs * sens_marche;
Serial.print ("Vitesse : ");
Serial.print (vit);
Serial.print (" Vitesse abs : ");
Serial.print(vit_abs);
Serial.print (" - ");
lcd.setCursor(8, 0);
lcd.print(vit);
//inclure ici la commande de vitesse DCC
dps.setSpeed128(3, DCC_SHORT_ADDRESS, vit);
dps.update();
Serial.println(My_Hash_Decoder.hash, DEC); // Impression du code ir recu
My_Receiver.resume();
}
}
// repetition commande loco
void LocoRepeter()
{
dps.setSpeed128(3, DCC_SHORT_ADDRESS, vit);
dps.setFunctions0to4(3, DCC_SHORT_ADDRESS, lumiere);
}
//relance des commandes DCC de vitesse
void SR_500()
{
LocoRepeter();
dps.update();
}
J’en profite pour rappeler que certains décodeurs DCC ont besoin de confirmations de commandes avant d’exécuter, donc de recevoir au moins 2 commandes identiques.
De plus il ne faut pas oublier que la transmission DCC est ENORMEMENT bruitée, Donc il y a beaucoup de pertes. On ne peut pas avoir toujours des rails et des locos super propres.
Je débute complètement, que ce soit en train ou en arduino.
Je possède du matériel Marklin, est-il possible d’utiliser ce système avec mon matériel ?
Mon doute ce situe au niveau de l’alimentation AC chez Marklin or, le module Lmd18200 est un "pilote" de moteur DC.
Merci de votre intérêt, en tant que débutant, pour Locoduino !
Débutant en Arduino, avez-vous une expérience en programmation ? Parce qu’il vous faudra envisager des adaptations éventuelles à votre projet des descriptions données dans ce site.
Quel matériel Marklin possédez-vous ? Des locos et des wagons, des rails, une alimentation ? Si c’est du matériel AC, ce n’est pas compatible avec la norme DCC, sauf si votre matériel supporte un kit d’adaptation. Mais je ne connais pas du tout ce type de matériel.
Il existe peut-être maintenant du matériel Marklin Digital qui est compatible DCC, étant donné qu’ils ont travaillé avec Lenz, un des inventeurs du DCC. Mais Il y a aussi d’autres standards chez Marklin : Motorola et MFX.
Il faudrait donc s’orienter vers les kits de conversion vers le DCC, s’ils existent.
Pour cet article, je ne considère que le cas du DCC et le LMD18200, est utilisé pour une alimentation DCC uniquement.
Bonjour et merci pour cette série d’articles très instructive !
J’ai bien entendu testé ce premier exemple utilisant la bibliothèque CmdrArduino. L’exemple fonctionne parfaitement, mais lorsque je laisse le train rouler, au bout d’un moment il s’immobilise sur la voie et il ne se passe plus rien (à part un petit grésillement au niveau des rails).
A y regarder de plus près, ça semble être au niveau du rail d’alimentation issu d’un coffret de départ Minitrix. Je crains qu’il ne contienne un petit condensateur de déparasitage, quelqu’un sait-il si ce petit condensateur peut être l’ennemi du DCC ?
Merci par avance !
Je ne connais pas ce coffret de départ (pour analogique je suppose), mais, s’il y a un condensateur, oui il faut l’enlever : j’enlève aussi ceux qui sont dans les locos quand j’installe un décodeur.
Maintenant je m’étonne que ça provoque un grésillement, ça ressemblerait plutôt à un mauvais contact ou un court-circuit : à regarder de près !
Bonjour,
J’ai entre temps supprimé le condensateur, mais pareil, même pire. En fait, je pense que mon problème vient de l’alimentation. L’arduino est alimenté par le port USB du PC et va très bien (il réagit parfaitement dans ma fenêtre de debug). En revance pour l’alimentation des rails (donc avant le LMD), j’ai utilisé une alimentation de PC portable Dell qui sort du 19V, et derrière j’ai installé un Buck Converter qui sort du 12V. Au multimètre, il sort parfaitement 12V. Mais sur les rails, parfois le train démarre quelques secondes, parfois rien. Mais quand je débranche l’alimentation Dell du secteur, au fur et à mesure de sa décharge interne, tout à coup le train allume ses feux et part jusqu’à ce que l’alimentation soit complètement déchargée.
Est-il possible que cette alimentation ne sorte pas un courant assez "lisse" pour générer le signal DCC ? Que faudrait-il pour avoir une source de courant bien fiable ? Un condensateur entre l’alim Dell et le Buck converter pour lisser le courant ?
Bonjour Sierramike,
Je crois que j’alimente aussi mon LMD avec une alim de portable 18v et un convertisseur pour descendre à 13 ou 14v, puis un Max471. La sortie du LMD est en série avec les détecteurs de consommation qui font perdre un bon volt. On n’est pas loin de 12v sur les rails, pour du N c’est normal.
je vais vérifier cela en rentrant après demain...
Chez moi ça marche bien.
Essayes un autre convertisseur par hazard ou une autre alim. J’ai une alim de live box 15v 2A en direct sur le LMD via un Max471 qui marche nickel.
Bonjour, excellente question car je prépare une réponse sous forme de d’article.
. OUI on peux lire l’adresse DCC d’une loco, comme je l’explique ici sur le Forum.
.
Cela vaut le coup (et le coût, avec un simple Pro-Mini et un LMD18200, pour 10€ environ) de faire une toute petite centrale spécialement pour détecter l’adresse d’une loco : on en a pratiquement tous besoin notamment quand on achète une machine d’occasion que le vendeur n’a pas reprogrammée avec l’adresse 3.
Dans la foulée, cette petite centrale peut faire d’autres choses bien utiles et là votre avis m’interesse !
Je souhaiterais transformer 2 locomotives LGB analogiques depuis des années dans mon grenier : l’article "Comment piloter trains et accessoires en DCC avec un Arduino (1)" m’incite à construire la centrale qui crée le signal DCC qui par l’intermédiaire du booster envoie des signaux vers les locomotives. Si j’ai bien compris, il est tout à fait possible de placer dans chaque locomotive un Arduino de petite taille qui peut jouer le rôle de décodeur. Mais alors, comment programmer ces Arduino pour qu’ils soient chacun caractérisés par une adresse propre et ensuite comment le programmer pour lui envoyer les ordres de marche avant ou arrière et de vitesse ?
Un grand merci pour toute idée à ce sujet ou référence à des articles déjà publiés mais pas encore trouvés.
Si vous lisez d’autres commentaires sur ce site et sur le Forum, vous verrez qu’il n’est pas du tout recommandé de tenter de faire un décodeur de loco avec un Arduino : la question a déjà été posée (vu le faible cout des décodeurs du commerce et leur miniaturisation).
Par contre pour faire une centrale, OUI vous pouvez.
A l’heure actuelle, je vous conseille de vous orienter vers de logiciel DCC++ présenté et testé sur le Forum
Les aspects électronique et informatique m’intéressent plus encore que la réalisation d’un grand réseau comprenant de nombreux trains avec décor...
Comme j’enseigne la physique et spécialement les options liées au numérique en seconde et en terminale, la réalisation du décodeur de locomotive me semble intéressante. On trouve des articles à ce sujet sur internet avec des PIC (http://dccdiy.org.uk/motor.html) mais je préférerais réaliser cela avec Arduino. Quant à la place que prendrait un décodeur fait-maison, comme je travaille avec LGB, il y a la place. Merci.
Sur Arduino, la bibliotheque de référence est celle de Minabay (voir ci-dessous)
Je vous comprend bien (moi aussi c’est l’électronique qui m’interesse).
Avec cette bibliothèque vous pouvez décoder tout ce que vous voulez. A vous de faire ensuite l’électronique. Ce n’est pas plus compliqué sur AVR que sur PIC.
J’espère que nous aurons le plaisir de publier un article sur votre réalisation.
J’ai écrit un programme en ASM pour Pic pour automatiser un aller-retour en HO digital, mais je ne sais pas comment donner un ordre de changement de sens de marche. L’instruction doit être sensiblement identique pour un Pic ou un Arduino, mais quelle est-elle et comment passer l’ordre à la centrale ?
A noter que ma centrale ne possède pas de fonction de navette.
Vous n’indiquez pas quelle centrale vous utilisez, son type (DCC ?) et par quelle interface vous la commandez par un Pic ni par quel programme, ce qui n’intéresse d’ailleurs pas notre site Locoduino dédié à l’Arduino.
Bonjour,
J’ai lu avec intérêt votre explication sur la génération de trame DCC ... après m’être beaucoup creusé la tête (et atteint mon objectif !) sur un sujet comparable que je ne développerai pas, car il n’est pas ferroviaire :-)
Mes domaines de prédilection ne sont pas ferroviaires mais le site LOCODUINO est une magnifique source d’inspiration et d’information, merci donc aux rédacteurs pour le travail de pédagogie et de transmission qu’ils réalisent.
Je m’interroge sur un détail, la latence qu’il faut intégrer pour produire le créneau de la longueur désirée.
J’ai besoin de commander plusieurs servos dans le temps le plus court possible. A cette fin, les commandes ne sont pas traitées de façon séquentielle mais les débuts des créneaux sont décalés de 1 ms. Si on a 5 servos, la durée maxi de transmission est de 4 ms + 2 ms.
4ms, c’est le début du créneau du 5ème servo et 2 ms la durée maxi du créneau de ce 5ème servo. Si on traite séquentiellement, on aura une durée maxi de 10 ms ...
Dans ma réalisation j’utilise le timer 1 (avec le prescaler à 8) en mode comparateur et à chaque interruption je "recharge" OCR1A pour le traitement suivant (mise à 0 ou à 1 d’une sortie).
De cette façon, à mon avis, il n’y a pas besoin de tenir compte d’une latence, OCR1A a pris sa nouvelle valeur avant que TCNT1 l’ait atteinte ...
Dominique me demande de répondre puisque cette question porte sur les timers.
Encore une fois, sans connaître l’ensemble de votre projet, j’ai trop peu d’informations pour pouvoir donner une réponse fiable. Et je ne comprends pas comment OCR1A a pu prendre une nouvelle valeur avant que TCNT1 l’ait atteinte (ce qui signifie qu’il n’y a pas eu comparaison, donc que vous avez modifié la valeur de OCR1A avant ; je suis un peu perdu).
J’ai répondu à un autre post de votre part dans un autre article et je ne peux que vous redire que vous trouveriez une aide plus efficace sur un forum plus adapté à votre projet (Drone si j’ai bien compris).
Bon courage pour la suite.
" à chaque interruption je "recharge" OCR1A pour le traitement suivant (mise à 0 ou à 1 d’une sortie). De cette façon, à mon avis, il n’y a pas besoin de tenir compte d’une latence "
Bonjour,
oui, c’est la bonne méthode. Elle permet d’avoir des signaux propres de façon simple
bien entendu, il faut que la nouvelle valeur soit chargée avant que le compteur ne l’ait atteinte
.
cela dit +1 à n’avoir rien compris à ton affaire de servos
Je confirme ce que Christian répond, si votre projet concerne les drones (j’en viens d’ailleurs avant de m’atteler au modélisme ferroviaire). Il y a plein de forums sur les drones que vous trouverez facilement. En tout cas nous vous remercions pour vos compliments. Notre qualité résulte du fait que nous sommes concentrés exclusivement sur le modélisme ferroviaire.
Bon courage.
Merci pour votre répons précise à ma question ...
Et c’est promis, je ne vous importunerai plus avec mes questions qui sortent des rails :-)
Mais ...
... si d’aventure je trouve une réponse solide à la raison qui fait que le TIMER 1 ne se remet pa à ZERO au moment de l’interruption en mode CTC, je ne manquerai pas de vous en faire part.
Cela sera un maigre retour comparé à la masse de choses que j’ai apprises en parcourant LOCODUINO, et, allez savoir, comme il m’a semblé qu’on utilisait les TIMER dans le monde ferroviaire, cela pourra peut-être servir à un cheminot HO :-)
Bien cordialement,
Michel
il ne faut pas confondre cause et conséquence
ce n’est pas le timer qui se met à 0 lors de l’interruption, mais c’est l’interruption qui est provoquée par le passage à 0 du timer
l’isr n’est exécutée qu’après une certaine latence, qui peut varier notamment selon le nombre de cycles (1, 2 ou 4) de l’instruction machine en cours au moment du déclenchement
après, il y a toutes les opérations de sauvegardes temporaires que le compilateur décide de réaliser, un peu à notre insu, et dont la durée peut varier selon ce qui aura été mis dans l’isr, et selon le paramétrage du compilateur
si une autre isr est en cours, il faut aussi attendre qu’elle soit terminée avant de servir la nouvelle, ce qui peut se produire assez vite avec arduino
pareil, certaines opérations nécessitent d’interdire temporairement les interruptions, on attendra que l’interdiction soit levée
.
pour résumer, la seule méthode pour avoir un timing précis, c’est de le confier au hardware, en s’assurant que celui-ci soit disponible pour la tâche requise
Bonjour TRIMARCO et merci pour ces précisions,
Ce qui me chagrine c’est précisément que je suis certain que l’interruption de comparaison se produit car l’oscilloscope est un arbitre impartial et que le timer continue sa course sans passer à ZERO car c’est en tenant compte de cela que je détermine les valeurs successives de OCR1A ...
C’est précisément pour éviter la simultanéité de 2 interruptions, l’une activant le TIMER 2 (pour réaliser un décodage d’un signal extérieur) et l’autre générant les créneaux de commande avec le TIMER 1 que je cherche à "contracter" au maximum cette génération de créneaux. De cette façon, le TIMER 1 a terminé son job avant que le TIMER 2 commence à traiter la séquence suivante. Et cela fonctionne ....
c’est une question de terminologie pour bien se faire comprendre : ce ne sont pas les interruptions qui "activent le timer" ou "génèrent des créneaux", mais éventuellement l’inverse
la seule chose que fait une interruption, c’est appeler un isr
activer un timer ou générer des créneaux, ça se fait par du code
In der Arduino-IDE ist der LMD18200 nicht vorhanden. Wie muß ich den hinzufügen und wo ? In der Config.h und/oder in DCCpp_Uno.h ?
Ich hoffe, es kann mir hier jemand weiterhelfen. Danke.
Hans
Le LMD18200 est un pont en H qu’il faut piloter comme les autres ponts avec ENABLE et DIR depuis les outputs de l’Arduino. Regardez les schémas et adaptez les sketches à votre projet si besoin.
The LMD18200 is an H-shaped bridge that you have to drive like the other bridges with ENABLE and DIR from the Arduino outputs. Look at the diagrams and adapt the sketches to your project if necessary.