Bonjour.
Certaines centrales DCC notamment les DIY ne sont pas compatibles RailCom car ne génèrent pas le CutOut.
Ce petit montage à base, seulement d’un Arduino Uno, Nano ou Micro s’insère entre la centrale et le Booster.
Il génère le CutOut afin de la rendre compatible RailCom.
Testé sur un Booster L298N et L6203.
Si dessous, le code et le schéma.
Bien à vous.
// RailCom: Programme pour insérer un CutOut dans les trames DCC. Arduino Uno, Nano, Micro.
// Testé avec Bridge Driver L6203 et L298N
// V.1.0. 24-04-24
// lebelge2@yahoo.fr
volatile uint8_t dccrecState;
volatile uint8_t tempByte;
#define WAIT_PREAMBLE 0
#define WAIT_START_BIT 1
#define WAIT_DATA 2
#define WAIT_END_BIT 3
#define MaxDccSize 6 // DCC messages can have a length upto this valu
#define PinIn1 3 // Entrée signalDcc sans CutOut
#define PinOut1 4 // Sortie signal DCC avec CutOut
#define PinOut2 5 // Sortie signal DCC inversé avec CutOut
class DccMessage {
public:
volatile uint8_t size;
volatile uint8_t data[MaxDccSize]; // The contents of the last dcc message received
} dccMessage;
struct {
uint8_t bitCount; // Count number of preamble bits / if we have a byte
volatile uint8_t tempMessage[MaxDccSize]; // Once we have a byte, we store it in the temp message
volatile uint8_t tempMessageSize; // Here we keep track of the size, including XOR
} dccrec; // The received DCC message is assembled here
struct {
uint8_t port;
uint8_t bit; // Bitmask for reading the input Port
volatile uint8_t *portRegister;
} dccIn;
void setup() {
Serial.begin(9600);
pinMode(PinIn1, INPUT);
pinMode(PinOut1, OUTPUT);
pinMode(PinOut2, OUTPUT);
init_timer2();
attachInterrupt(digitalPinToInterrupt(PinIn1), Dcc_Interrupt, CHANGE );
dccIn.port = digitalPinToPort(PinIn1);
dccIn.bit = digitalPinToBitMask(PinIn1);
dccIn.portRegister = portInputRegister(dccIn.port);
Serial.println ("SetUp OK");
}
void loop() {
}
void CutOut(void) {
delayMicroseconds(8);
asm("sbi 0x0B, 4");
asm("sbi 0x0B, 5");
delayMicroseconds(425);
asm("cbi 0x0B, 4");
asm("cbi 0x0B, 5");
}
//----------------------------------------------------------------------------------------------------------
void init_timer2(void) {
#define T2_PRESCALER 8
#define T2_PRESCALER_BITS ((0<<CS02)|(1<<CS01)|(0<<CS00))
#define T77US (F_CPU * 77L / T2_PRESCALER / 1000000L)
#if (T77US > 254)
#warning T77US too big, use either larger prescaler or slower processor
#endif
#if (T77US < 32)
#warning T77US too small, use either smaller prescaler or faster processor
#endif
noInterrupts(); // disable all interrupts
TCCR2A = 0; // should be zero for our purpose
TCCR2B = 0; // 0 => timer is stopped
TCNT2 = 256L - T77US; // preload the timer
TIMSK2 |= (1 << TOIE2); // the timer is used in overflow interrupt mode
interrupts(); // enable all interrupts
}
//----------------------------------------------------------------------------------------
void Dcc_Interrupt() {
if (digitalRead(PinIn1) == true) {
asm("cbi 0x0B, 5");
asm("sbi 0x0B, 4");
TCCR2B |= (T2_PRESCALER_BITS); // Start Timer 2
}
else {
asm("cbi 0x0B, 4");
asm("sbi 0x0B, 5");
}
}
//-----------------------------------------------------------------------------------
ISR(TIMER2_OVF_vect) {
uint8_t DccBitVal;
DccBitVal = !(*dccIn.portRegister & dccIn.bit);
TCCR2B = 0; // 0 => timer is stopped
TCNT2 = 256L - T77US; // preload the timer
dccrec.bitCount++;
switch (dccrecState) {
case WAIT_PREAMBLE:
if (DccBitVal) { // a "1" bit is received
if (dccrec.bitCount >= 10)
dccrecState = WAIT_START_BIT;
}
else
dccrec.bitCount = 0; // not a valid preamble.
break;
case WAIT_START_BIT:
if ( !DccBitVal ) { // a "0" bit is received
dccrecState = WAIT_DATA;
dccrec.tempMessageSize = 0;
uint8_t i;
for (i = 0; i < MaxDccSize; i++ )
dccrec.tempMessage[i] = 0;
dccrec.bitCount = 0;
}
break;
case WAIT_DATA:
if ( dccrec.bitCount == 8 ) { // byte is complete
if (dccrec.tempMessageSize == MaxDccSize ) { // Packet is too long - abort
dccrecState = WAIT_PREAMBLE;
dccrec.bitCount = 0;
}
else
dccrecState = WAIT_END_BIT; // Wait for next byte or end of packet
}
break;
case WAIT_END_BIT:
if ( DccBitVal ) { // End of packet?
CutOut();
dccrecState = WAIT_PREAMBLE;
}
else // Get next Byte
dccrecState = WAIT_DATA;
dccrec.bitCount = 0; // prepare for the next byte
}
}