Modelbaan – deel 9 – Ontkoppelrail

In een eerder deel (deel 7) heb ik beschreven hoe middels de combinatie Arduino en de MOSFET-module wissels omgezet kunnen worden. Deze MOSFET-modules kunnen ook gebruikt worden om bijvoorbeeld ontkoppelrails aan te sturen. Hiervoor gebruiken we weer de DCC Accessory sketch (zie hieronder).

Minitrix 4969 ontkoppelrail.

In dit geval wordt de hierboven getoonde K-83 vervangen door de Arduino en MOSFET-module.

Arduino in adapter
De MOSFET
IRF520-module
Minitrix ontkoppelrail
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DCC Accessory / Function Decoder
// Author: Ruud Boer - September 2015
// This sketch turns an Arduino into a DCC decoder with max 17 function outputs.
// Output pins used: 3-19 (14-19 = A0-A5). Pin becomes LOW when accessory is switched ON
// Modes: 1-continuous, 2=oneshot, 3=flasher with 2 alternatin outputs, 4=signal with 2 inverted outputs
// The DCC signal is fed to pin 2 (=Interrupt 0).
// Optocoupler schematics for DCC to 5V conversion: www.rudysmodelrailway.wordpress.com/software
// Many thanks to www.mynabay.com for publishing their DCC monitor and -decoder code.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORTANT: GOTO lines 20 and 43 to configure some data!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <DCC_Decoder.h>
#define kDCC_INTERRUPT 0

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in the number of accessories / functions you want to control
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const byte maxaccessories = 4;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

typedef struct {
  int               address;          // User Configurable. DCC address to respond to
  byte              mode;             // User Configurable. Mode: 1=Continuous, 2=Oneshot, 3=Flasher
  byte              outputPin;        // User Configurable. Arduino pin where accessory is connected to
  byte              outputPin2;       // User Configurable. 2nd pin for AlternatingFlasher (e.g. railway crossing)
  int               ontime;           // User Configurable. Oneshot or Flasher on time in ms
  int               offtime;          // User Configurable. Flasher off time in ms
  byte              onoff;            // User Configurable. Initial state of accessory output: 1=on, 0=off (ON = pin LOW)
  byte              onoff2;           // User Configurable. Initial  state of 2nd output: 1=on, 0=off
  byte              dccstate;         // Internal use. DCC state of accessory: 1=on, 0=off
  byte              finished;         // Internal use. Memory that says the Oneshot is finished
  unsigned long     onMilli;          // Internal use.
  unsigned long     offMilli;         // Internal use.
} 
DCCAccessoryAddress;
DCCAccessoryAddress accessory[maxaccessories];

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in the attributes for every accessory / function
// COPY - PASTE as many times as you have functions. The amount must be same as in line 18 above!
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ConfigureDecoderFunctions() // The amount of accessories must be same as in line 26 above!
{
  accessory[0].address = 50; // DCC address
  accessory[0].mode = 1; // Continuous: HIGH until DCC switches the address off again
  accessory[0].outputPin = 3; // Arduino pin to which this accessory is connected

  accessory[1].address = 51;
  accessory[1].mode = 2; // Oneshot: HIGH for ontime ms, then LOW and stays LOW.
  accessory[1].outputPin = 4;
  accessory[1].ontime = 1000;
 
  accessory[2].address = 52;
  accessory[2].mode = 3; // Flasher: HIGH for ontime ms, LOW for offtime ms, repeats till DCC off
  accessory[2].outputPin = 5;
  accessory[2].outputPin2 = 6; // Flasher can use 2 outputs, they will flash  on/off alternatively
  accessory[2].ontime = 500;
  accessory[2].offtime = 500;
  
  accessory[3].address = 53; // DCC address
  accessory[3].mode = 4; // Continuous: HIGH until DCC switches the address off again
  accessory[3].outputPin = 7; // Green signal
  accessory[3].outputPin2 = 8; // Red Signal
  accessory[3].onoff2 = 1; // Initially set Red signal to ON
  
}  // END ConfigureDecoderFunctions

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // DCC accessory 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;

    for (int i=0; i<maxaccessories; i++)
    {
      if (address == accessory[i].address)
      {
        if (enable) accessory[i].dccstate = 1;
        else accessory[i].dccstate = 0;
      }
    }
  } //END BasicAccDecoderPacket_Handler

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup (run once)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() 
{ 
  ConfigureDecoderFunctions();
  DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
  DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
  pinMode(2,INPUT_PULLUP); // Interrupt 0 with internal pull up resistor (can get rid of external 10k)

  for(int i=3; i<20; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW); //all function outputs are set to 0 at startup
  }
} // END setup

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Main loop (run continuous)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
  static int addr = 0;

  DCC.loop(); // Loop DCC library
    
  if( ++addr >= maxaccessories ) addr = 0; // Next address to test

  if (accessory[addr].dccstate)
  {
    switch (accessory[addr].mode)
    {
    case 1: // Continuous
      accessory[addr].onoff = 1;
      break;
    case 2: // Oneshot
      if (!accessory[addr].onoff && !accessory[addr].finished)
      {
        accessory[addr].onoff = 1;
        accessory[addr].offMilli = millis() + accessory[addr].ontime;
      }
      if (accessory[addr].onoff && millis() > accessory[addr].offMilli)
      {
        accessory[addr].onoff = 0;
        accessory[addr].finished = true; //this is reset to flase below in the 'else' statement
      }
      break;
    case 3: // Flasher, is always an 'alternating' flasher together with .outputPin2
      if (!accessory[addr].onoff && millis() > accessory[addr].onMilli)
      {
        accessory[addr].onoff = 1;
        accessory[addr].onoff2 = 0;
        accessory[addr].offMilli = millis() + accessory[addr].ontime;
      }
      if (accessory[addr].onoff && millis() > accessory[addr].offMilli)
      {
        accessory[addr].onoff = 0;
        accessory[addr].onoff2 = 1;
        accessory[addr].onMilli = millis() + accessory[addr].offtime;
      }
      break;
    case 4: // Signal
      accessory[addr].onoff = 1;
      accessory[addr].onoff2 = 0;
      break;
    }
  }
  else //accessory[addr].dccstate == 0
  {
    accessory[addr].onoff = 0;
    if (accessory[addr].mode == 4) accessory[addr].onoff2 = 1; else accessory[addr].onoff2 = 0;
    if (accessory[addr].mode == 2) accessory[addr].finished = false; // Oneshot finished by DCCstate, not by ontime
  }

  // activate outputpin, based on value of onoff
  if (accessory[addr].onoff) digitalWrite(accessory[addr].outputPin, LOW);
  else digitalWrite(accessory[addr].outputPin, HIGH);
  if (accessory[addr].onoff2) digitalWrite(accessory[addr].outputPin2, LOW);
  else digitalWrite(accessory[addr].outputPin2, HIGH);
  
} //END loop

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Deze site gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie gegevens worden verwerkt.