Trying to learn I2C (was RS485) to control things on my hobby railroad

EDIT

Since discovering that I2C was an easier and more appropriate method I have altered the title to reflect the new direction

End of edit

Hi all new here and relatively new to Arduino stuff. I have been using Arduino Nanos to help me with my model railroad to change track switches, semaphores and stop lights for a while. Some are simple so say a toggle switch will set LED's in a certain way, or move a servo or stepper motor to move a track switch to a certain position then read microswitches to give visual feedback. Other more complicated sketches do a combination. However none of the sketches I have produced are particularly complicated compared to the stuff I see on the internet as I am really not that proficient. I'm retired, learning is trickier now

What I have managed to do works fine, but the downside is all the control switches and feedback LED's need wires from the control position to the bit of the layout where they perform their function. As my layout has grown, so have the number of wires!

Reading online I have seen that RS485 can allow me to use four wires connected from a master to slaves, so if I understand correctly I can connect the control switches and feedback LED's to a master, and then have the slaves connect to the servos, steppers and semaphores and stop lights. The master can then read feedback from the slave to light the feedback LED's.

Firstly am I right in that this is possible?

If it is, then I'm hoping that you can help me learn how to implement it in my simple sketches

I have read the Arduino tutorials and have become more confused rather than less. Unfortunately that is a function of my age and the way my brain processes things. However one way that I have been able to learn previously is to see sketches doing something simple, then seeing another sketch with the same function but with extra functions.

In that way I have been able to figure out how to put stuff like switch commands, stepper control into my sketches.

What I don't want is for someone to tell me how to do everything, as I will never learn anything that way, so what I want to do is to get a simple sketch I made, and then see how that sketch would look separated into a master and slave sketch respectively

This sketch is just a test to use as my example.

It uses an ON-ON SPDT switch as the control switch, and for these purposes would light LED's 1 and 2 dependent on the switch position. A microswitch is connected so that a third LED will be lit if it is closed to provide feedback

bool buttonState1, buttonState2, buttonState3;
const int buttonPin1 = 8;   // the number of the control switch position A pin
const int buttonPin2 = 9;   // the number of the control switch position B pin
const int buttonPin3 = 10;  // the number of the feedback microswitch pin
const int ledPin1 = A0;     // the number of the LED pin
const int ledPin2 = A1;     // the number of the LED pin
const int ledPin3 = A2;     // the number of the feedback LED pin



void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin1, INPUT_PULLUP);
  pinMode(buttonPin2, INPUT_PULLUP);
  pinMode(buttonPin3, INPUT_PULLUP);
}

void loop() {
  // read the state of the pushbutton value:
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);
  buttonState2 = digitalRead(buttonPin3);

  // check if control switch is in Position A. If it is, the buttonState is HIGH:
  if (buttonState1 == LOW) {
    // turn LED on:
    digitalWrite(ledPin1, HIGH);
  } else {
    // turn LED off:
    digitalWrite(ledPin1, LOW);
  }
  // check if control switch is in Position B. If it is, the buttonState is HIGH:
  if (buttonState2 == LOW) {
    // turn LED on:
    digitalWrite(ledPin2, HIGH);
  } else {
    // turn LED off:
    digitalWrite(ledPin2, LOW);
  }
  // check if feedback microswitch is pressed. If it is, the buttonState is HIGH:
  if (buttonState3 == LOW) {
    // turn LED on:
    digitalWrite(ledPin3, HIGH);
  } else {
    // turn LED off:
    digitalWrite(ledPin3, LOW);
  }
}


The master control switch and feedback LED would be connected to the master, while LED's 1 and 2 plus the mircoswitch would be connected to the slave number 1.

I want to see how the sketch above would be implemented in a simple RS485 setup, and see what the Master and Slave sketches look like so that I can and try to figure out how to convert my other sketches. If someone is able to help me with those examples I would be grateful

Shaun

I realized that I have not given hardware details, please accept my apologies

I would be using a Mega 2560 as the master due to the number of available pins, and would use Nanos as slaves. I am using the RS485 to TTL modules which I have connected following one of the tutorials here https://www.instructables.com/RS485-Serial-Communication-Between-Arduino-Mega-an/ but I struggled with the Visuino thing. I got it working but it didn't help me understand

I have also reviewed this https://www.gammon.com.au/forum/?id=11428

but found it too confusing for me

I'm not a model railroader but a quick search using your favourite search engine should bring up quite a few projects/articles on the subject. The danger there may be that there are too many to choose from and you end up totally confused.

RS485 is certainly one choice. It's pretty simple to implement and understand. It gets a little bit complicated when starting from scratch - especially if you are a beginner - as not only do you need to handle the RS485 control signals but them you would need to invent a messaging system to send data to slave devices and request data back.

That isn't as complicated as it sounds and you could invent a really simple messaging system that sends out a device id, command and optional data. Your slaves would all listen for messages and only react to those addressed to their unique id.

I did have a really simple demo using RS485 that I created some time back that used 1 UNO as a master and several UNOs as slaves. The master could send out simple commands to get the slaves to turn on and off the on board LED. I could dig it out if that would help.

There are also a few forum members who have an interest in this field. I'm sure they can advise you on existing projects and libraries so you didn't have to start from scratch.

Thanks for the reply Mark

I have searched in vain for a tutorial that shows a sketch without and then with RS485 in it so that I can compare

All I find are either straight to RS485 use, or are so complicated that I am lost at the beginning. The other thing about tutorials is, when you have done something wrong or don't understand, you can't ask it a question.

Perhaps I don't phrase the search correctly, if there is a better way to ask the question let me know

S

Start simple

Connect a Nano and the Mega using two TTL to RS485 converters.

On the Mega, connect the serial pins of the converter to pins 18 and 19. This is the Serial1 interface. Pin 18 (Tx) goes to Rx on the module and 19 (Rx) goes to Tx on the module. Use Serial1.begin(9600); to initialise the interface. Anything that you print to Serial1 will now be passed to the Nano

A small test sketch for the Mega


void setup()
{
    Serial1.begin(9600);
}

void loop()
{
    static byte x = 0;
    Serial1.println(x++);
    delay(1000);
}

On the Nano you need to use SoftwareSerial to create a second serial port on pins other than 0 and 1. Do not be tempted to use them. As on the Mega, connect the chosen Rx pin and Tx pin to the module and initialise the interface using yourSerial.begin(9600); where yourSerial is the name you gave to the SoftwareSerial interface. Anything received on that interface can be printed to the Nano Serial monitor. That is why you avoid using pins 0 and 1

A small test sketch for the Nano

#include <SoftwareSerial.h>
SoftwareSerial yourSerial(9, 10);  //Rx, Tx

void setup()
{
    Serial.begin(9600);
    yourSerial.begin(9600);
}

void loop()
{
    if (yourSerial.available()) //if data is available
    {
        Serial.write(yourSerial.read());  //read data and print it
    }
}

Bob, you missed Serial.begin()

Whoops !

I have added it

Thanks - a quick confirmation question for this test, pertinent to my RS485 modules
RO is RX and DI is TX
pints DE and RE are shorted and not connected to the Arduino

Correct?

Please post a link to the RS485 modules that you are using

These

https://www.ebay.com/itm/143503959079?_trkparms=amclksrc%3DITM%26aid%3D1110006%26algo%3DHOMESPLICE.SIM%26ao%3D1%26asc%3D277940%2C277717%26meid%3D9d046f4225a7453fade67fca5dc9d42b%26pid%3D101875%26rk%3D2%26rkt%3D4%26sd%3D381374599127%26itm%3D143503959079%26pmt%3D1%26noa%3D0%26pg%3D2332490%26algv%3DSimVIDwebV3WithCPCExpansionEmbeddingSearchQueryRecallAuctionPushoutVectorPrime%26brand%3DUnbranded&_trksid=p2332490.c101875.m1851&itmprp=cksum%3A1435039590799d046f4225a7453fade67fca5dc9d42b%7Cenc%3AAQAJAAABQEaV4I9HJKT%252BAma5y%252F48RheNQOwjjhNx1TBBgHhk8esWs5z3zJx975POdrziWUU95aCb%252BcH%252Fo7l4U0%252FPi77H1Rdch6GmwDDSpDmtxcJgeZKe92RgqlwX4c6GpwrabeTANQKIScmcUDWROjra3Owexv75NCE%252BZWlsx930VgeFLiXTRV6IuaOrslAo8mXH7BsLCd9I9KniRRtYUYfYy2tmfLRos5OG62Q363yn2eItGysEL8ylQYHsMaRYiWYYpKWlJRxkAj9MRNinprwubP2NqQvN0HMYWVhx8H46mb6ip%252BCI%252B3HXPfzgihuXix4pUVVdn9p5yTbRqCvmMLdAlunMUIckBuyb63P%252BWPexmEGnog9Hgb55RMTHzp0%252FudDP7xjqlqodxxjrr0DcgR9M1QcHjY7bRuE8ACFD6NHljaImj385%7Campid%3APL_CLK%7Cclp%3A2332490&itmmeta=01JETJYE0BAB5BJBVEMQX0HPXQ

Shouldn't the shorted DE and RE pins connect to a respective pin on the Mega and Nano?

Looking at other RS485 related sketches I see a TXENABLE_PIN callout, but as you know I am not the expert

From MAX485 RS485 transceiver module

Hello shauntherailroadguy

Welcome to the world's best Arduino forum ever.

To begin with, it is highly advisable to familiarise yourself a little with data transmission before you start programming.
The OSI model of computer networks describes seven layers, whereby the first three layers are of interest for your project.

hth

Have a nice day and enjoy coding in C++.

Thanks for the info Paul, however I think that was aimed at someone 50 years younger!

I wanted to try other setups to see if I could get my head around it and found this simple example
https://www.youtube.com/watch?v=ZR9QEWpGEDo

Easy to construct everything, but I have two observations / questions, based on the two bits of code used.

Firstly, the 'Master'

#define LED       13                  
#define SLAVE_EN  8

void setup() {
  pinMode(LED , OUTPUT);                        // Declare LED pin as output
  pinMode(SLAVE_EN , OUTPUT);                   // Declare Enable pin as output
  Serial.begin(9600);                           // set serial communication baudrate 
  digitalWrite(SLAVE_EN , LOW);                 // Make Enable pin low
                                                // Receiving mode ON 
}

void loop() {
  while(Serial.available())                     // If serial data is available then enter into while loop
  {
    if(Serial.read() == 'A')                    // if available data is A
    {
      digitalWrite(LED , !digitalRead(LED));    // LED Blink
    }
  }
}

and then the 'slave'

#define LED       13    // Declare LED pin
#define MASTER_EN   8   // connected to RS485 Enable pin

void setup() {
  pinMode(LED , OUTPUT);            // Declare LED pin as output
  pinMode(MASTER_EN , OUTPUT);      // Declare Enable pin as output
  Serial.begin(9600);               // set serial communication baudrate 
  digitalWrite(MASTER_EN , LOW);    // Make Enable pin low
                                    // Receiving mode ON 
}

void loop() {
  digitalWrite(MASTER_EN , HIGH);     // Make Enable pin high to send Data
  delay(5);                           // required minimum delay of 5ms
  Serial.println('A');                // Send character A serially
  Serial.flush();                     // wait for transmission of data
  delay(1000);
  digitalWrite(MASTER_EN , LOW);      // Receiving mode ON
}

So during the video it shows the shorted DE/RE pins as connecting to pin 6 on the Arduino Nano, yet the sketch that you load to the Nano, the 'Master' sketch quotes SLAVE_EN pin as 8. I connected it physically using pin 6, and it worked fine. I then spotted the difference and moved it to pin 8, and there was no difference.

The other question I have is which is the master and which is the slave? There is not a huge amount of descriptive text but it feels like they are inverted...? I definitely don't want to kick off a troubleshooting session for that site, but as I am trying to learn I want to understand it.

I see the Uno is sending the character 'A' every second, and the Nano is looking for it (the ``if(Serial.read() == 'A') statement) but I don't see a read statement on the Uno sketch that would react to the 'digitalWrite(LED , !digitalRead(LED));' statement. The 'master' is displaying the repeated A output on the serial monitor

I'm sorry, I am trying so hard to get this into my head, but feel like I am just confusing myself

I would call the first code slave and second master. But it's not really important because in that code one is only sending and one is only receiving. In real RS485 communication master is usually sending request to one specific slave and that specific slave responds. Every time one is sending DE/RE pin is pulled high, right after back low.

This is the RS485 adapter you need:

Debugging communications is hard, because you don't know which end is at fault. If you have the ability to insert a third device you can test each end independently. I recommend using this device on a PC for debugging RS485: Amazon.com: USB to RS485 Converter Industrial Adapter Original FT232RL and SP485EEN Fast Communication Embedded Protection Circuits Resettable Fuse ESD Protection : Electronics

Although if I were starting from scratch I would be tempted to go with an ESP32 which is about the same price as a Nano but has built-in wifi and bluetooth, and make the whole thing wireless.

I second the use of ESP32s, but whichever hardware you're going to use, I suggest running two slaves. It will get you thinking about what messages should look like that are addressed to a particular slave or the master.

Rather than hardwiring the communication, have you considered using ESPNow? Then you just need to get power to each esp32.

I any trying to use the hardware I already have, as it'll keep the cost down. I may have to change my plans though!

A question, after spending a time rolling this all round my head. What I want to control is essentially a load of switches, either to turn on or off LED's or to switch on a solenoid.

Each switch can have an individual callout, assuming that I don't need feedback is there a way of linking the Arduinos so that they all act like one? I get that is a bit of a loose question, but maybe RS485 is a sledgehammer to crack a nut