Model Railway Reed Switch Sensing Locos

I am running a model railway layout computer controlled using JMRI/CMRI interface.
Arduino Uno with motor shield controls locos.
Arduino Nano’s via R485 bus connects the point servos (PCA9685).
Arduino Nano’s via R485 bus connects reed switches on the Nano input pins.
Everything works but I am having problems with missing reed switch events.
A loco runs over reed switch slowly no problems but any speed and the event is missed.
JMRI/CMRI works on a polling system and to me it seems the event is missed because the Arduino is too quick.
I have upped the R485 baud rate to 115200 which improves it but events still missed.

Is there a way to store the event for a set time to make sure it is read or am I completely on the wrong track??

Any replies please KISS as I am only a dabbler and take no credit for the program below.

#include <Auto485.h>
#include <CMRI.h>

int constexpr pin_number[] = {  3, 4,  5,  6,  7,  8,  9, 10, 11, 12, A0, A1,
                               A2, A3, A4, A5, 13};

int constexpr number_of_pins = sizeof(pin_number) / sizeof(pin_number[0]);

int previous_pin_state[number_of_pins] = {HIGH};

Auto485  bus(2);                 // Arduino pin 2 -> MAX485 DE and RE pins
CMRI     smini(              1,  // C/MRI address
                number_of_pins,  // Number of inputs
                             0,  // Number of outputs

void setup() {
  bus.begin(115200, SERIAL_8N2);
  pinMode(13, INPUT);
  pinMode(A6, INPUT);
  pinMode(A7, INPUT);

  for (int pin_index = 0; number_of_pins > pin_index; pin_index++)
    previous_pin_state[pin_index] = HIGH;

void loop()
  if (analogRead(A6)>615)(smini.set_bit (17, HIGH)); 
  if (analogRead(A7)>615)(smini.set_bit (18, HIGH)); 
  bool pin_changed = false;

  for (int pin_index = 0; number_of_pins > pin_index; pin_index++)
    if (previous_pin_state[pin_index] != digitalRead(pin_number[pin_index]))
      pin_changed |= true;
      smini.set_bit(pin_index, previous_pin_state[pin_index]);
      previous_pin_state[pin_index] =
        (HIGH == previous_pin_state[pin_index]) ? LOW : HIGH;

  if (pin_changed)


I’ve not read the code so no idea if that’s the problem area and don’t know what the interfaces you mention .

However …

There are easier bits of code around to understand - have a look at the digital input examples in the IDE or google “ Arduino state change”. You could play with those to test your hardware .

Typically you would use a reed switch on a digital input with a pull up resistor of say 10k . ( input_pull-up is not great with long leads)
You can use analog inputs , I guess, but you still need a resistor.

The code is hard to understand. When a pin changes state, why do you send the prior state to the smini object rather than the new one?

How do you know that a reed switch transmission is missed? What should happen when one is detected?

I would try getting it to work with a single switch. Lose the analogReads for that test too.

You probably already know this, but I will write it anyway.
Almost all reed switches use two steel alloy reeds in a glass envelope. They are held so the tips are not in contact. When a magnetic field with North and South poles are close to the reeds, one reed will become the South pole of a magnet and the other the South pole of a magnet and as magnets do, the poles will snap together, closing the switch.
The above only works well then the reeds are in the N-S field of the magnet. They do not work reliably when there is not a real N-S magnetic field.
Be sure your triggering magnets are oriented so their N-S field is parallel to the reeds in the switch.

1 Like

Thanks, I never knew that!

Thanks for the replies.
JMRI/CMRI is a computer interface which uses the RS$*% bus to communicate with servos and sensors.

The reeds are connected with 1.8k pullup Resistors and they all work fine.
I have checked the reed response with a multimeter and they trigger at a fast pass of the magnet.
I had a Lenz DCC system operating the same setup with no problems so I know it works.
Once the reed is triggered it should be read by JMRI/CMRI via a pooling system on the RS485 bus.
The problem I think is happening is the reed is triggered for a short time if the magnet is passing at speed.

I need to store that closed state until it is read by JMRI/CMRI and then the reed returned to open state.


You could solve a lot of your problems if you ditched reed switches and used a Hall sensor.
These are as fast as you need, they don’t bounce and work at distances as good as the reed switches, especially with the neodymium magnets.
You can get magnets as small as 2 or 3 mm diameter.
Another option might be optical with a reflective dot on the underside of the locomotive.
Allegro, Honeywell, TI all do Hall sensors.
Be aware that there are many types of Hall sensors, unipolar, bipolar, switching, latching.

Problem solved.
It was not the reed and Arduino but communications between the Arduino and CMRI.
Arduino was to fast and CMRI pooling was missing events.
I am using encapsulated reeds as they are being embedded in plaster so as not to show.


By using two reed switches in series (a fixed distance apart) and using two magnets on the train (the same distance apart) you can detect different trains by having different spacing on each train. You only get a closed circuit when both magnets are over both reeds at the same time. Not all that useful if you’re using DCC, as your controller should know the identity of each train, but on analogue layouts its a help towards automation.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.