Seeing the Light

 

One of my hopes for the garden railroad is to be able to build some of my own electronics for it. Whether some off-track movement or lights, or a piece of automation that helps manage the trains. It would be very useful to be able to control the automation from the DCC throttle. So there is my starting point: build an Arduino system that listens to DCC and does something with the signal. 

After some searching on line I found several options and settled on the basic design from Dave Bodnar at Train Electronics. One of the components needed is an optocoupler. I wasn't familiar with this so did some reading and turns out, this is a pretty ingenious little device. It provides a way to have signals pass from a high voltage part of a circuit (for me DCC running at about 15-18V) to a low voltage part (the Arduino at 3.3 or 5V) while having them electrically isolated. The incoming signal get converted to light (hence to opto-) which is picked up by a photodetector and sent back out. For more details, see Components 101.

This appeared to be a simple enough design that I wanted to try and build a simple one for myself. And I could do it all with basic components I already have. I used it to send Morse code messages between two isolated Arduino boards. See it in operation.

It was a fun little build. But now I have ordered a real one and will start building the DCC decoder. Diagrams and code below for anyone interested.

It is a simple circuit as seen below. I made use of the Lewis library by DefProc. (As a fan of both the Inspector Morse and Inspector Lewis mysteries, I loved reference!)

Wiring Diagram

Schematic


Sending Code

*
 * Send Morse code over a  home-grown optocoupler. 
 * This is the send side. See Morse_Code_Receive for the receive side.
 * Drives an LED with some frequency and detects it using the photoresistor.
 * This is the basic mechanism behind an optocouple or optoisolator.
 * 
 * Sept 9, 2021
 * Bryan Barmore
 */
#include <Lewis.h>   // Morse code library for encoding and decoding https://github.com/DefProc/lewis/
//#define DEBUG
const int STATUS_PIN = 13;
const int SIGNAL_PIN = 11; //made it PWM so we can play with chaning intesity to see how well that is detected
Lewis Morse;   // love the naming!!!!
const int WPM = 40;
String Message = "From here to there  ";
void setup() {
  Serial.begin(9600);               //start a serial connection with the computer
  pinMode(STATUS_PIN, OUTPUT);              //set pin 13 as an output that can be set to HIGH or LOW
  digitalWrite(STATUS_PIN, LOW);          // turn the light off
  pinMode(SIGNAL_PIN, OUTPUT);
  digitalWrite(SIGNAL_PIN, LOW);          // turn the light off

  Morse.begin(SIGNAL_PIN, SIGNAL_PIN, WPM, false); 
}
void loop() {
  //Morse.print("l");
  morsePrint(Message);
  delay (1000);
}

int morsePrint(String message)
{
  int messageLength = message.length();
  for (int i=0; i<messageLength; i++) {
    Morse.print(message[i]);
  }
}

Receiving Code

/*
 * Send Morse code over a  home-grown optocoupler. 
 * This is the receive side. See Morse_Code_Sender for the send side.
 * Drives an LED with some frequency and detects it using the photoresistor.
 * This is the basic mechanism behind an optocouple or optoisolator.
 * 
 * Sept 9, 2021
 * Bryan Barmore
 */

#include <Lewis.h>

const int STATUS_PIN = 13;  // on-board LED
const int RECEIVE_PIN = A1;  // Using a photoresistor so need to read on an 
   //  analog pin but it seems the Lewis library needs a digital input
const int RELAY_PIN = 10;
const int INCOMING_PIN = 2;  // this could be an interrupt if desired

Lewis Morse;    // love the naming!!!!!  https://github.com/DefProc/lewis/
const int WPM = 47;   //Note, this needs to be a bit higher than the sender for some reason.

int receive;
const int THRESHOLD = 750;
int lastCharacterTime = 0;   //time since the last character was read
bool noReturn = true;  // haven't done a carriage return since the last character read

void setup() {
  Serial.begin(9600);               //start a serial connection with the computer

  pinMode(RELAY_PIN, OUTPUT);              //set pin 13 as an output that can be set to HIGH or LOW
  digitalWrite(RELAY_PIN, LOW);          // turn the light off
  pinMode(STATUS_PIN, OUTPUT);
  digitalWrite(STATUS_PIN, LOW);          // turn the light off

 Morse.begin(INCOMING_PIN, INCOMING_PIN, WPM, false);  // 

}

void loop() {
  receive = analogRead(RECEIVE_PIN);

  if (receive >= THRESHOLD) {      //receiving a signal
    digitalWrite(RELAY_PIN,HIGH);
    digitalWrite(STATUS_PIN, HIGH);
  }
  else {
    digitalWrite(RELAY_PIN,LOW);
    digitalWrite(STATUS_PIN, LOW);
  }

  // check to see if we have a new character
  Morse.checkIncoming();

  if (Morse.available()) {
    char c = Morse.read();
    Serial.print(c);
    lastCharacterTime = millis();
    noReturn = false;
  }

  if (millis() - lastCharacterTime > 1000 && !noReturn) {
    Serial.println();
    noReturn = true;
  }
  
}

Comments

Popular posts from this blog

How far have we come?

The Home Stretch of Construction