ArduinoCMRI and RS485

A fun little side project of mine is Arduino C/MRI, a library that lets you easily connect your Arduino projects up to the JMRI layout control software, by pretending to be a piece of C/MRI hardware. Hence the name.

In previous episodes, we've looked at various methods of expanding the capabilities of Arduino C/MRI; be it by using shift registers, or emulating larger boards. But at some point you're going to need more than just one board, and that's where things get confusing.

The logical answer, you would think, is to connect multiple Arduino's to your computer. Simple. One USB cable for each one. The problem is, JMRI is not designed to address more than one C/MRI system at once. Trust me, I've done everything including hacking the XML config files to make it work! It doesn't.

So how then does one do it? Well, the original C/MRI system used a shared serial bus, and that is what we'll do to.

RS485

RS485 is a electrical standard designed for connecting multiple masters together on a single bus. We've all heard of RS232 which is ye olde tried-and-tested two device connection. RS485 bumps things up a notch by allowing more than just two devices on a network, and allowing any of them to be the boss; there are no fixed master and slave roles. It also uses differential signals, excellent for long distances or split grounds.

Each node connects to the bus using a small bus transceiver IC. These little 8 pin chips (such as the MAX485 and its many clones) have a pair of pins to control the direction, or mode of communication. That is, at any point in time you can be either talking or listening on the bus.

This is a half-duplex bus, which means you can't both talk and listen at the same time, but that's just fine for us. It also means that only one device may be transmitting at any point in time, and that's where things get a little complicated. We basically run the bus like we wish children would run: don't talk unless you're asked to.

RS485 is pretty common and you may well have used it already. Both NCE and Digitrax use RS485 for their cab busses, though in vastly different ways. DMX lighting control networks use it. Miniatur Wunderland use it for their lighting control networks. It's used in aircraft cabins, and was used on old Macs to connect printers. Even TV studios use it. It's well proven.

And now ArduinoC/MRI uses it too.

How to set up RS485 with Arduino C/MRI

Ingredients:

Instructions:

Connect the USB/485 adapter to your computer. Wire up the MAX485 as follows:

That's it.

Now we need to write some code for it:

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

#define CMRI_ADDR 0

#define    DE_PIN 2
#define   LED_PIN 13

Auto485 bus(DE_PIN); // Arduino pin 2 -> MAX485 DE and RE pins
CMRI cmri(CMRI_ADDR, 24, 48, bus); // defaults to a SMINI with address 0. SMINI = 24 inputs, 48 outputs

void setup() {
  pinMode(LED_PIN, OUTPUT);
  bus.begin(9600);
}

void loop() {
  // 1: main processing node of cmri library
  cmri.process();
  
  // 2: update output. Reads bit 0 of T packet and sets the LED to this
  digitalWrite(LED_PIN, cmri.get_bit(0));
  
  // 3: update input. Flips a bit back and forth every second
  cmri.set_bit(0, (millis() / 1000) % 2 == 0);
}

So what does all this do? Well the magic starts on the very first line when we #include <auto485.h> â€” Auto485 is a cute wee library I wrote that lets you transparently talk over an RS485 bus using just the standard Arduino Stream functions like .printl(), .write(), .available(), .read(), .peek(), .poke(), etc. Auto485 will sit in the background and handle toggling the /RE and DE pins to ensure the MAX485 is correctly in transmitting or receiving mode, all without us having to write any tedious state logic ourselves.

The next few lines are normal Arduino C/MRI stuff.

Auto485 bus(DE_PIN); is where we actually set up the Auto485 bus. Into its constructor we pass the Arduino pin number that is connected to the /RE and DE pins on the MAX485. This is how it knows which pin to toggle. The resulting bus object implements Stream, so is just the same as creating additional HardwareSerial or SoftwareSerial objects.

When we set up the CMRI object, we pass in the Stream object created above, and so now the code knows to use this for all serial communications, instead of the default Arduino serial port.

The only other important line is bus.begin(9600); this is exactly the same as how you would normally call Serial.begin(9600) in a normal Arduino sketch. Without this line you will spend hours wondering why nothing is being read to or from the bus. Trust me, guess what I spent most of today trying to solve :(

The rest of the sketch is bog standard Arduino C/MRI stuff; nothing has changed here. The best part about this is that you can add RS485 support to your projects with only two new lines! That's pretty cool.

Practical Example

To prove this all works I wired up 3 Arduinos with the above sketch, changing the CMRI_ADDR for each one so that I now had 3 distinct nodes, each with their own address. Notice how each board only has the blue and white A/B wires of the RS485 bus going between them. The USB cables are just for power. At far right we have the USB to RS485 adapter board.

Then in JMRI I set up 3 inputs, and 3 outputs.

And that was it. Toggling the state buttons on the Lights panel toggles the LEDs on each board, and meanwhile the input states under the Sensors Panel toggle off and on each second, completely automatically.

I hope that explains roughly how to use Arduino C/MRI and Auto485 in order to connect up multiple Arduinos to JMRI. From here you have all the foundations to create a truly expansive control system for your railroad. Just imagine, each Arduino could control servos to toggle points, monitor RFID readers to track trains, read push buttons on the edge of the layout, drive relays or play sound files. Watch this space as I have some exciting developments in the works.

Newer Older

Comments

Sunday, Mar 2 2014, 12:15 AM Edgar (from England) says...
I'm very grateful for you taking the time to write these articles. I'm building a gritty futuristic n gauge layout and this info is perfect for my lighting and atmosphere plans. Great site layout too, I wish I had one like it.
Tuesday, Nov 25 2014, 8:07 AM David (from England) says...
Excellent post - I've found it extremely useful.<br /> <br /> I've tried to replicate what you've done using JMRI. I found that using Hall Effect Sensors the time that they are high isn't long enough to always trigger the RS485 communications. What's the way around this?<br /> <br /> Thanks
Wednesday, Nov 26 2014, 9:31 PM David (from England) says...
Thanks Michael, that helps a lot. I've never have worked that out on my own. I've got it working satisfactorily but had to implement a count loop that held the set.bit HIGH for 250 cycles before going LOW (at 57600 baud).<br /> <br /> Scruffy, but it works!
Tuesday, Dec 16 2014, 2:24 PM Ray (from USA) says...
Digitrax's LocoNet is not RS-485 it uses an Ethernet type protocol.<br /> Full C/MRI is a 4 wire Full Duplex RS-485.<br /> <br /> Ray
Wednesday, Mar 16 2016, 12:15 AM Bill (from USA) says...
Great idea! I have bench tested all of it with JMRI and have even got servos working for the turnouts. next is to get them working with the layout. Thank You, Thank You, Thank You. Saved me a lot of work.
Wednesday, Apr 22 2015, 2:09 PM Fernando Aramburu (from France) says...
Hi Michael;<br /> <br /> I implemented your JMRI- CMRI RS485 emulation and it works perfectly, at least with 3 Arduinos and several pushbuttons and lights. Thanks for your libraries and examples. Now it is time for me implementing the complete network in my layout. By the way, I'm using JMRI-MRC prodigy wireless DCC bus for locomotives and turnouts control and JMRI-CMRI for feedback bus (sensors and pushbuttons) as well as signal control.<br /> <br /> Fernando
Sunday, Apr 26 2015, 6:11 PM Fernando (from France) says...
Ray pointed out that CMRI is a 4 wires full duplex communicating system. Is there any practical advantage of the full duplex over the half duplex? Is it faster ?<br /> <br /> Fernando
Tuesday, Apr 28 2015, 9:10 AM Michael Adams says...
Hi Fernando, the benefit of full duplex is you don't get collisions between RX and TX signals. However as the bus is a polled bus controlled by the master, there should only ever be one device transmitting at a time, and so collisions shouldn't be a problem. So it's up to you whether you want to use half or full duplex. Half duplex is nice in that you don't need to run as many wires :)
Wednesday, Apr 29 2015, 2:52 PM Fernando (from France) says...
Thanks, Michael. I will keep with your half-duplex libraries as they seem to work fine.<br /> <br /> Fernando
Thursday, Nov 12 2015, 12:36 PM Daniel says...
Hello there,<br /> <br /> I've been trying to get this working but with no luck.<br /> When adding CMRI via serial in JMRI preferences, tx/rx lights on the arduino flash and JMRI acknowledges "CMRI using serial on COM18" on the main PanelPro window. However I can't get LED on pin13 on the sketch above to respond via JMRI lights list. If I add a sensor on hardware address 1, it shows "unknown". Clicking this toggles to either active or inactive and then immediately back to "unknown".<br /> I'm using a "Sparkfun redboard" as an UNO.<br /> What am I missing here?
Thursday, Nov 12 2015, 6:11 PM Daniel says...
Cancel that, I've solved it!<br /> I've used a MAX485 breakout board. For the bus connection, I used the pcb pins marked A &amp; B instead of the screw terminals marked the same.<br /> Turns out I should have used only the screw terminals....
Tuesday, Feb 16 2016, 11:44 AM Peter (from London) says...
Hi guys,<br /> Have you ever met with the following problem?<br /> I have built my slave device and can communicate with it from my PC with an own developed communication program.<br /> However, when I connect the MAX485 chip to Arduino UNO, I cannot upload the sketch. But, when I disconnect the RX and TX pins, I'm able to upload the sketch smoothly.<br /> After the uploading I reconnect the RX and TX pins and the program works properly.<br /> It is OK during the "breadboard-phase" but later on, not the best. :)<br /> <br /> I get this message:<br /> avrdude: stk500_recv(): programmer is not responding<br /> avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x86<br /> <br /> Anyone has any idea about this issue?<br /> <br /> Regads,<br /> Peter<br />
Tuesday, Feb 16 2016, 12:57 PM Peter (from London) says...
Never mind. I just forgot the 2x10K pull resistors on 2 and 3 feet of the MAX485 chip. :)<br /> I asked sooner than thought. :)<br />
Monday, Apr 11 2016, 11:26 PM JohnW (from Australia) says...
Many thanks for your work and sharing it with us.<br /> I m very new to CMRI and very keen to use Arduinos for my railway.<br /> I note that you comment in your "ReadMe" notes as follows<br /> **Please note**: Arduinos without a separate FTDI chip will not work. This includes the Arduino Leonardo, Uno, and Mega 2560.<br /> I have been using a Uno without success with Panel Pro and your Max485 multiple arduinos sketch. What arduinos did you use they appear to Micros ?<br /> Having just read you Readme notes as above, I assume that is my problem.
Wednesday, Sep 28 2016, 5:09 AM Paul (from Illinois) says...
Hi, great work! I have two of the original SMINI's running on my railroad and thought I would add a third via arduino. I have successfully used a custom rs485 shield to connect to the cmri rs 485 bus and have emulated an SMINI. I need 48 outputs and 48 inputs however so I set up JMRI has a USIC, 4 24-bit cards, 2 input and 2 output. I coded for a CMRI cmri(3, 48, 48); however when I read in the data using the cmri.get_bit function call, only the first bit is read successfully. I do not see why this would not work. Any ideas?
Tuesday, Oct 11 2016, 3:53 AM Paul (from Illinois) says...
It was the MuxShield II code, I found a updated implementation file and the Arduino CMRi is working great. 48 I/O lines, with full duplex RS485, cool.
Thursday, Nov 3 2016, 3:08 AM Frank Haymes (from FrankGHaymes@hotmail.com) says...
I have the ArduinoCMRI working on an Arduino Nano with 8 inputs and 8 outputs.<br /> <br /> I can connect one Nano to JMRI over USB.<br /> <br /> I can not connect two Nanos to JMRI over USB.<br /> <br /> JMRI tries to connect the two Nanos to the same USB port.<br /> <br /> How do I connect two Nanos to JMRI using two different USB ports?<br /> <br /> Thanks,<br /> <br /> Frank G. Haymes
Tuesday, Nov 8 2016, 8:34 AM Michael Adams says...
Hi Frank, to connect multiple Arduinos to JMRI, each with its own USB connection, you'll need to set it up as multiple connections, each with their own prefix. A bit confusing, and I'm unsure if it would work properly or not.
Thursday, Dec 8 2016, 8:39 PM Galunid says...
Hi, can you post a scheme, with instructions on how to wire. Great lib, many thanks
Thursday, Jan 12 2017, 3:09 AM steve (from s.brackstone@googlemail.com) says...
Hello Michael. I would like to say thank you for this Blog. There is not much information on using CMRI with the Arduino on the WEB, so this has been a great help. So far I have managed to connect up three Arduinos that can control turnout servos, signal lights and block current sensors. I am still in the testing stage and hope to be connecting up to my layout very soon. One question if you know the answer. Is there a limit to the number of Ardinos I could connect using this RS485. Is it unlimited with JMRI. Great web site look forward to seeing more and good luck with your modelling.
Monday, Mar 27 2017, 3:28 AM Hampton (from k4kfh.radio@gmail.com) says...
Hello Michael. I have been using your library on one Arduino for a while, but I'd like to add another. I started trying the methods in this post, using an Arduino Nano on a breadboard with a USB-RS485 adapter and a MAX485 chip. Basically exactly what you show. For some reason, I can't seem to get the LED to turn on and off. I noticed that the Arduino's LEDs stay on "RX" and never lights "TX," but beyond that I'm not really sure how to troubleshoot. I'm using the code and wiring in this post. Ideas?
Saturday, Jun 3 2017, 5:38 AM Erik (from Belgium) says...
Hi, this is such a great blog about RS485 comms in model railroading! I hope you will keep up this kind of community sharing. I have a comment/question though about the use of ground wire in RS485: in your setup you power the 3 Mini's from USB, therefo also connecting them to the same ground potential as used by the USB/RS485 converter. However, in "the field" this might often not be the case and therefor a ground connection between the USB/RS485 converter and the boards you connect the RS485 to will be required. There are converters available with the A and B comms screw connection but with a third GND screw connection too: that should be the preferred choice of purchase. Grts! Erik
Tuesday, Jul 11 2017, 2:57 AM Steve Hofmeister (from Abingdon, Maryland USA) says...
I know it is a little off track (Excuse the pun), but say you would want the ability to have have two (or more) nodes talk directly without involving JMRI in the communication. In short term have an Arduino serve as the master node with an ethernet gui via browser. I don't need any feedback other than how one would have one node address the other directly. Reason I ask. I am working on a control system for my workshop in general unrelated to my railroad endeavors, and after working with multiple RS485 examples, I keep finding myself migrating back to this library. Thanks for your time and consideration in advance,
Thursday, Dec 28 2017, 9:07 AM yogi (from Bowie, MD) says...
This is great, really interested. Been starting out with DCC++ over the last few months and C/MRI will fit in very well. Ordered USB to rs485 interface right away. Just a couple questions Will the USB/Rs485 interface work on an R Pi (I know this is kind of off base but hope someone may have tried this)? Does ArduinoC/MRI only run on Leo/Pro Micro/Nano? Thanks for your efforts
Tuesday, Jun 19 2018, 4:52 AM Jay (from Midwest US) says...
Hi! For some reason I can only get the 1st board to light. There are 5 Arduino's hooked up. They are wired the same & programmed as CMRI Address 0, 1, 2, 3, 4. That's the only thing I changed in the sketch. JMRI is set up as you showed also. I am at a loss here.
Saturday, Jun 8 2019, 5:46 PM jeffb (from usa) says...
great tools and thanks for doing this. just a couple of comments regarding the actual RS485 bus. First, the wires interconnecting the arduinos should be twisted pair. the short distances in your example are not a problem, but if you are traveling any significant distance, the twisting is important. Second, there should be a termination at each end of the device. a 120 ohm resistor across the a and b connections at each end of the bus should suffice. again, your short distances do not illustrate this issue.
Thursday, Jul 30 2020, 1:05 AM Greg (from Canada) says...
This is still a great article. I have a question about the MAX485. I'm looking around ebay and seeing several different name for MAX485 with CPA, ESA, CSA, etc in the name. What the difference and does it matter? What do you recommend?