Aquí os dejo el Sketch que tendréis que meter al Arduino Nano para que funcione la tarjeta como decoder de desvíos tipo Fleischmann de bobina/solenoide.
Supongo que este programa no será perfecto y muy mejorable, pero es lo que conseguí elaborar para mis propósitos tras pegarme con él largas horas y sin conocer este lenguje de programación.
Tal y como está, si no se programase una nueva dirección, sería de la 33 a la 40 y los impulso de tensión a las bobinas, para accionar el desvío, de 450 ms.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Arduino DCC Solenoid Switch Decoder.
// Author: Ruud Boer - January 2015
// Modificado por Pecetero - Julio 2018
// This sketch turns an Arduino into a DCC decoder to drive max 8 dual coil solenoid switches.
// The DCC signal is optically separated and fed to pin 2 (=Interrupt 0). Schematics: www.mynabay.com
// Many thanks to www.mynabay.com for publishing their DCC monitor and -decoder code.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <DCC_Decoder.h>
#include <EEPROM.h>
#define kDCC_INTERRUPT 0
#define EEPROM_ADDRESS 2 // dode se guardara la direccion dcc
#define pulsador 3
#define aviso_tiempo 20
unsigned long Tprog_Milli; // Tiempo de espera para programar
int direccion=33;
int bucle ;
int reset = 0;
const byte impulso=250; // Se sumará 200 al valor definido
////////////////////////////////////////////////////////
//El numero de desvios que se van a controlar
const byte maxaccessories=8;
///////////////////////////////////////////////////////
typedef struct
{
int address; // Address to respond to
byte output; // State of accessory: 1=on, 0=off (for internal use only)
int outputPin; // Arduino output pin
int outputPin2; // Arduino output pin2, used for solenoid junctions
byte highlow; // State of outputpin: 1=HIGH, 0=LOW
byte highlow2; // State of outputpin2: 1=HIGH, 0=LOW
boolean finished; // Memory location that says the oneshot is finished
boolean finished2; // Memory location that says the second oneshot (for solenoid) is finished
int durationMilli; // ms flash time
unsigned long onMilli; // for internal use
unsigned long offMilli; // for internal use
}
DCCAccessoryAddress;
DCCAccessoryAddress accessory[maxaccessories];
void ConfigureDecoderFunctions()
{
accessory[0].address = direccion;
accessory[0].durationMilli = impulso + 200;
accessory[0].outputPin = 4;
accessory[0].outputPin2 = 5;
accessory[0].highlow = 0; // Do not change this value
accessory[0].highlow2 = 0; // Do not change this value
accessory[0].finished = false; // Do not change this value
accessory[0].finished2 = true; // Do not change this value
accessory[0].output = 0; // Do not change this value
accessory[1].address = direccion + 1;
accessory[1].durationMilli = impulso + 200;
accessory[1].outputPin = 6;
accessory[1].outputPin2 = 7;
accessory[1].highlow = 0; // Do not change this value
accessory[1].highlow2 = 0; // Do not change this value
accessory[1].finished = false; // Do not change this value
accessory[1].finished2 = true; // Do not change this value
accessory[1].output = 0; // Do not change this value
accessory[2].address = direccion + 2;
accessory[2].durationMilli = impulso + 200;
accessory[2].outputPin = 8;
accessory[2].outputPin2 = 9;
accessory[2].highlow = 0; // Do not change this value
accessory[2].highlow2 = 0; // Do not change this value
accessory[2].finished = false; // Do not change this value
accessory[2].finished2 = true; // Do not change this value
accessory[2].output = 0; // Do not change this value
accessory[3].address = direccion + 3;
accessory[3].durationMilli = impulso + 200;
accessory[3].outputPin = 10;
accessory[3].outputPin2 = 11;
accessory[3].highlow = 0; // Do not change this value
accessory[3].highlow2 = 0; // Do not change this value
accessory[3].finished = false; // Do not change this value
accessory[3].finished2 = true; // Do not change this value
accessory[3].output = 0; // Do not change this value
accessory[4].address = direccion + 4;
accessory[4].durationMilli = impulso + 200;
accessory[4].outputPin = 12;
accessory[4].outputPin2 = 13;
accessory[4].highlow = 0; // Do not change this value
accessory[4].highlow2 = 0; // Do not change this value
accessory[4].finished = false; // Do not change this value
accessory[4].finished2 = true; // Do not change this value
accessory[4].output = 0; // Do not change this value
accessory[5].address = direccion + 5;
accessory[5].durationMilli = impulso + 200;
accessory[5].outputPin = 14;
accessory[5].outputPin2 = 15;
accessory[5].highlow = 0; // Do not change this value
accessory[5].highlow2 = 0; // Do not change this value
accessory[5].finished = false; // Do not change this value
accessory[5].finished2 = true; // Do not change this value
accessory[5].output = 0; // Do not change this value
accessory[6].address = direccion + 6;
accessory[6].durationMilli = impulso + 200;
accessory[6].outputPin = 16;
accessory[6].outputPin2 = 17;
accessory[6].highlow = 0; // Do not change this value
accessory[6].highlow2 = 0; // Do not change this value
accessory[6].finished = false; // Do not change this value
accessory[6].finished2 = true; // Do not change this value
accessory[6].output = 0; // Do not change this value
accessory[7].address = direccion + 7;
accessory[7].durationMilli = impulso + 200;
accessory[7].outputPin = 18;
accessory[7].outputPin2 = 19;
accessory[7].highlow = 0; // Do not change this value
accessory[7].highlow2 = 0; // Do not change this value
accessory[7].finished = false; // Do not change this value
accessory[7].finished2 = true; // Do not change this value
accessory[7].output = 0; // Do not change this value
// Setup output pins
for(int i=0; i<maxaccessories; i++)
{
if( accessory[i].outputPin )
{
pinMode( accessory[i].outputPin, OUTPUT );
digitalWrite( accessory[i].outputPin, LOW);
}
if( accessory[i].outputPin2 )
{
pinMode( accessory[i].outputPin2, OUTPUT );
digitalWrite( accessory[i].outputPin2, LOW);
}
}
pinMode(aviso_tiempo,OUTPUT);
} // END ConfigureDecoderFunctions
//////////////////// DCC packet handler //////////////////////////////////////
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
// Convert NMRA packet address format to human address
address -= 1;
address *= 4;
address += 1;
address += (data & 0x06) >> 1;
boolean enable = (data & 0x01) ? 1 : 0;
/////////////////////////////////////////////////////////////////////////////
//========== lectura de direccion para guardar =============================//
//Si estamos en modo programacion, se guarda la direccion //
if (bucle==1) {
while (millis()- (Tprog_Milli) < 5000) {
//digitalWrite(13, HIGH); //provisional
digitalWrite(aviso_tiempo, HIGH);
EEPROM.update(EEPROM_ADDRESS,address%256);
EEPROM.update(EEPROM_ADDRESS+1,address/256);
reset = 1;
}
bucle = 0;
}
if (reset==1) {
reset = 0;
//digitalWrite(13, LOW); //provisional
digitalWrite(aviso_tiempo, LOW);
//declara función de reset @ address 0
void(* resetFunc) (void) = 0;
resetFunc(); //Reset
}
//=========================================================================//
/////////////////////////////////////////////////////////////////////////////
for(int i=0; i<maxaccessories; i++)
{
if( address == accessory[i].address )
{
if( enable ) accessory[i].output = 1;
else accessory[i].output = 0;
}
}
} // END BasicAccDecoderPacket_Handler
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup (run once)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
ConfigureDecoderFunctions();
DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
pinMode(2,INPUT_PULLUP); //Interrupt 0 with internal pull up resistor (can get rid of external 10k)
} //END setup
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Main loop (ejecucion continua)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
if (digitalRead(pulsador)==HIGH) { //pulsador de programación
//digitalWrite(13, HIGH); //provisional
digitalWrite(aviso_tiempo, HIGH);
Tprog_Milli = millis();
bucle = 1;
}
if(millis()- (Tprog_Milli) > 5000) {
//digitalWrite(13, LOW); //provisional
digitalWrite(aviso_tiempo, LOW);
}
static int addr = 0;
DCC.loop(); // Loop DCC library
if( ++addr >= maxaccessories ) addr = 0; // Bump to next address to test
if (accessory[addr].output == 1)
{
if (!accessory[addr].highlow && !accessory[addr].finished)
{
accessory[addr].highlow = 1;
accessory[addr].offMilli = millis() + accessory[addr].durationMilli;
}
if (accessory[addr].highlow && millis() > accessory[addr].offMilli)
{
accessory[addr].highlow = 0;
accessory[addr].finished = true;
}
accessory[addr].finished2 = false;
}
else // output==0
{
accessory[addr].highlow = 0;
//accessory[addr].finished = false;
if (!accessory[addr].highlow2 && !accessory[addr].finished2)
{
accessory[addr].highlow2 = 1;
accessory[addr].offMilli = millis() + accessory[addr].durationMilli;
}
if (accessory[addr].highlow2 && millis() > accessory[addr].offMilli)
{
accessory[addr].highlow2 = 0;
accessory[addr].finished2 = true;
}
accessory[addr].finished = false;
}
if (accessory[addr].highlow) digitalWrite( accessory[addr].outputPin, HIGH);
else digitalWrite( accessory[addr].outputPin, LOW);
if (accessory[addr].highlow2) digitalWrite( accessory[addr].outputPin2, HIGH);
else digitalWrite( accessory[addr].outputPin2, LOW);
} //END loop
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Supongo que este programa no será perfecto y muy mejorable, pero es lo que conseguí elaborar para mis propósitos tras pegarme con él largas horas y sin conocer este lenguje de programación.
Tal y como está, si no se programase una nueva dirección, sería de la 33 a la 40 y los impulso de tensión a las bobinas, para accionar el desvío, de 450 ms.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Arduino DCC Solenoid Switch Decoder.
// Author: Ruud Boer - January 2015
// Modificado por Pecetero - Julio 2018
// This sketch turns an Arduino into a DCC decoder to drive max 8 dual coil solenoid switches.
// The DCC signal is optically separated and fed to pin 2 (=Interrupt 0). Schematics: www.mynabay.com
// Many thanks to www.mynabay.com for publishing their DCC monitor and -decoder code.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <DCC_Decoder.h>
#include <EEPROM.h>
#define kDCC_INTERRUPT 0
#define EEPROM_ADDRESS 2 // dode se guardara la direccion dcc
#define pulsador 3
#define aviso_tiempo 20
unsigned long Tprog_Milli; // Tiempo de espera para programar
int direccion=33;
int bucle ;
int reset = 0;
const byte impulso=250; // Se sumará 200 al valor definido
////////////////////////////////////////////////////////
//El numero de desvios que se van a controlar
const byte maxaccessories=8;
///////////////////////////////////////////////////////
typedef struct
{
int address; // Address to respond to
byte output; // State of accessory: 1=on, 0=off (for internal use only)
int outputPin; // Arduino output pin
int outputPin2; // Arduino output pin2, used for solenoid junctions
byte highlow; // State of outputpin: 1=HIGH, 0=LOW
byte highlow2; // State of outputpin2: 1=HIGH, 0=LOW
boolean finished; // Memory location that says the oneshot is finished
boolean finished2; // Memory location that says the second oneshot (for solenoid) is finished
int durationMilli; // ms flash time
unsigned long onMilli; // for internal use
unsigned long offMilli; // for internal use
}
DCCAccessoryAddress;
DCCAccessoryAddress accessory[maxaccessories];
void ConfigureDecoderFunctions()
{
accessory[0].address = direccion;
accessory[0].durationMilli = impulso + 200;
accessory[0].outputPin = 4;
accessory[0].outputPin2 = 5;
accessory[0].highlow = 0; // Do not change this value
accessory[0].highlow2 = 0; // Do not change this value
accessory[0].finished = false; // Do not change this value
accessory[0].finished2 = true; // Do not change this value
accessory[0].output = 0; // Do not change this value
accessory[1].address = direccion + 1;
accessory[1].durationMilli = impulso + 200;
accessory[1].outputPin = 6;
accessory[1].outputPin2 = 7;
accessory[1].highlow = 0; // Do not change this value
accessory[1].highlow2 = 0; // Do not change this value
accessory[1].finished = false; // Do not change this value
accessory[1].finished2 = true; // Do not change this value
accessory[1].output = 0; // Do not change this value
accessory[2].address = direccion + 2;
accessory[2].durationMilli = impulso + 200;
accessory[2].outputPin = 8;
accessory[2].outputPin2 = 9;
accessory[2].highlow = 0; // Do not change this value
accessory[2].highlow2 = 0; // Do not change this value
accessory[2].finished = false; // Do not change this value
accessory[2].finished2 = true; // Do not change this value
accessory[2].output = 0; // Do not change this value
accessory[3].address = direccion + 3;
accessory[3].durationMilli = impulso + 200;
accessory[3].outputPin = 10;
accessory[3].outputPin2 = 11;
accessory[3].highlow = 0; // Do not change this value
accessory[3].highlow2 = 0; // Do not change this value
accessory[3].finished = false; // Do not change this value
accessory[3].finished2 = true; // Do not change this value
accessory[3].output = 0; // Do not change this value
accessory[4].address = direccion + 4;
accessory[4].durationMilli = impulso + 200;
accessory[4].outputPin = 12;
accessory[4].outputPin2 = 13;
accessory[4].highlow = 0; // Do not change this value
accessory[4].highlow2 = 0; // Do not change this value
accessory[4].finished = false; // Do not change this value
accessory[4].finished2 = true; // Do not change this value
accessory[4].output = 0; // Do not change this value
accessory[5].address = direccion + 5;
accessory[5].durationMilli = impulso + 200;
accessory[5].outputPin = 14;
accessory[5].outputPin2 = 15;
accessory[5].highlow = 0; // Do not change this value
accessory[5].highlow2 = 0; // Do not change this value
accessory[5].finished = false; // Do not change this value
accessory[5].finished2 = true; // Do not change this value
accessory[5].output = 0; // Do not change this value
accessory[6].address = direccion + 6;
accessory[6].durationMilli = impulso + 200;
accessory[6].outputPin = 16;
accessory[6].outputPin2 = 17;
accessory[6].highlow = 0; // Do not change this value
accessory[6].highlow2 = 0; // Do not change this value
accessory[6].finished = false; // Do not change this value
accessory[6].finished2 = true; // Do not change this value
accessory[6].output = 0; // Do not change this value
accessory[7].address = direccion + 7;
accessory[7].durationMilli = impulso + 200;
accessory[7].outputPin = 18;
accessory[7].outputPin2 = 19;
accessory[7].highlow = 0; // Do not change this value
accessory[7].highlow2 = 0; // Do not change this value
accessory[7].finished = false; // Do not change this value
accessory[7].finished2 = true; // Do not change this value
accessory[7].output = 0; // Do not change this value
// Setup output pins
for(int i=0; i<maxaccessories; i++)
{
if( accessory[i].outputPin )
{
pinMode( accessory[i].outputPin, OUTPUT );
digitalWrite( accessory[i].outputPin, LOW);
}
if( accessory[i].outputPin2 )
{
pinMode( accessory[i].outputPin2, OUTPUT );
digitalWrite( accessory[i].outputPin2, LOW);
}
}
pinMode(aviso_tiempo,OUTPUT);
} // END ConfigureDecoderFunctions
//////////////////// DCC packet handler //////////////////////////////////////
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
// Convert NMRA packet address format to human address
address -= 1;
address *= 4;
address += 1;
address += (data & 0x06) >> 1;
boolean enable = (data & 0x01) ? 1 : 0;
/////////////////////////////////////////////////////////////////////////////
//========== lectura de direccion para guardar =============================//
//Si estamos en modo programacion, se guarda la direccion //
if (bucle==1) {
while (millis()- (Tprog_Milli) < 5000) {
//digitalWrite(13, HIGH); //provisional
digitalWrite(aviso_tiempo, HIGH);
EEPROM.update(EEPROM_ADDRESS,address%256);
EEPROM.update(EEPROM_ADDRESS+1,address/256);
reset = 1;
}
bucle = 0;
}
if (reset==1) {
reset = 0;
//digitalWrite(13, LOW); //provisional
digitalWrite(aviso_tiempo, LOW);
//declara función de reset @ address 0
void(* resetFunc) (void) = 0;
resetFunc(); //Reset
}
//=========================================================================//
/////////////////////////////////////////////////////////////////////////////
for(int i=0; i<maxaccessories; i++)
{
if( address == accessory[i].address )
{
if( enable ) accessory[i].output = 1;
else accessory[i].output = 0;
}
}
} // END BasicAccDecoderPacket_Handler
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup (run once)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
ConfigureDecoderFunctions();
DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
pinMode(2,INPUT_PULLUP); //Interrupt 0 with internal pull up resistor (can get rid of external 10k)
} //END setup
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Main loop (ejecucion continua)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
if (digitalRead(pulsador)==HIGH) { //pulsador de programación
//digitalWrite(13, HIGH); //provisional
digitalWrite(aviso_tiempo, HIGH);
Tprog_Milli = millis();
bucle = 1;
}
if(millis()- (Tprog_Milli) > 5000) {
//digitalWrite(13, LOW); //provisional
digitalWrite(aviso_tiempo, LOW);
}
static int addr = 0;
DCC.loop(); // Loop DCC library
if( ++addr >= maxaccessories ) addr = 0; // Bump to next address to test
if (accessory[addr].output == 1)
{
if (!accessory[addr].highlow && !accessory[addr].finished)
{
accessory[addr].highlow = 1;
accessory[addr].offMilli = millis() + accessory[addr].durationMilli;
}
if (accessory[addr].highlow && millis() > accessory[addr].offMilli)
{
accessory[addr].highlow = 0;
accessory[addr].finished = true;
}
accessory[addr].finished2 = false;
}
else // output==0
{
accessory[addr].highlow = 0;
//accessory[addr].finished = false;
if (!accessory[addr].highlow2 && !accessory[addr].finished2)
{
accessory[addr].highlow2 = 1;
accessory[addr].offMilli = millis() + accessory[addr].durationMilli;
}
if (accessory[addr].highlow2 && millis() > accessory[addr].offMilli)
{
accessory[addr].highlow2 = 0;
accessory[addr].finished2 = true;
}
accessory[addr].finished = false;
}
if (accessory[addr].highlow) digitalWrite( accessory[addr].outputPin, HIGH);
else digitalWrite( accessory[addr].outputPin, LOW);
if (accessory[addr].highlow2) digitalWrite( accessory[addr].outputPin2, HIGH);
else digitalWrite( accessory[addr].outputPin2, LOW);
} //END loop
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////