Arduino Remote Control With RS485 Over UTP

by Big_OO in Circuits > Arduino

648 Views, 2 Favorites, 0 Comments

Arduino Remote Control With RS485 Over UTP

concept.jpg

When your Arduino project gets bigger, or more complex, you want communication between parts. I2C and SPI are great for communication between ICs, and UART/serial for greater distance. If that is not enough, you can extend it with RS485.

Supplies

Supplies.png
  • 2x Arduino [Uno, Nano, etc].
  • 2x breadboard or 1 big one.
  • 2x RS485 module [buy 5 cheap Chinese ones, usually one is not working].
  • jumper wires. [male-male & female-male]
  • option: Cat5 RJ45 double wall socket, remove the 2 connectors.
  • option: 1m network installation wire, solid copper.
  • option: common Cat5 patch cable, not a crossover cable.

Cat5 is phased out, and many stores sell only the faster more expensive versions for home/office internet connection.

Serial

RS485 - serial_bb.png
serial.jpg

This is Simplex communication, the transmitter [Master] is not aware of the receiver, and the receiver [Slave] is not aware of the transmitter. It is not possible to ask or acknowledge data, it is coming in or not . . . For more complex things you can use half-duplex or full-duplex, but for simple remote-control simplex will do.

Notice that only the Tx of the Master is connected to the Rx of the Slave, making it a one-wire communication. Because we use a common powersource, there is a common ground that will be important to remember later in RS485.

Sending data

Your Master may have any input device or sensor connected. The Slave may have a display, process data, record data, resent data or control any device. In the example we use a master clock and remote display.

On the picture just another way of power supply, connect the 5V and GND of both Nano's [not the VIN]. The USB powers both devices, that are placed in terminal adaptors.

Coding

Master Code

You need to get it working with serial, that is very basic for the Master. The Master can transmit anything it likes, when it likes to do it.

Slave Code

The Slave is a bit more complex, it needs to listen always because it does not know when the data will be coming in. Serial has a buffer, but you need to do the loop a few times per millisecond, if you don't want to miss any. You can't use delay() anywhere in the loop.

The basics

Serial at 9600 baud is very slow for the modern Arduino, but that makes it very reliable. This is about 1 byte per millisecond. If you need to send more data faster, 115200 will do about 10 bytes per millisecond. You need to set the baud rate the same on Master and Slave.

The hardware serial is always the best, don't use a software serial unless you want to receive from 2 sources at the same time. This means that you have to disconnect the Slave if you want to upload your Sketch, the Rx PIN is also connected to the USB port of your Arduino Nano.

To make it easy for the Slave Code, use start and stop markers. I use <...> in my code and put the data between them, the rest is ignored. Also use Serial.print and not Serial.println for your data.

Any data send by Serial.print is converted for you to human readable chars, on the Slave we have to transform it back to the original value. This seems strange, but it is easier to debug your code this way.

Masterclock Example

We store the Unix timestamp in a 32-bit unsigned long, this is 4 bytes binary format. That is converted to 10 bytes in text format. The <1672578000> tells the slave this is a value, that it has to convert back. If the code works, it will display "Sun Jan 01 2023 13:00:00".

In this example we use a clock simulator, for a compleet master clock look here

/*
  Clock simulator, for testing RS485 communication
*/

unsigned long t = 1672578000;  // Unix time 01-01-2023 13:00:00

void setup() {
  Serial.begin(9600);
  Serial.println();
  Serial.println("-Arduino Master Reboot-");
}

void loop() {
  SendTime();
  delay(1000);
}

void SendTime() {
  char startmarker = '<';
  char endmarker = '>';
  Serial.print(startmarker);
  Serial.print(t);
  Serial.println(endmarker);
  t += 1;
}

// End


Serial monitor:

-Arduino Master Reboot-
<1672578000>
<1672578001>
<1672578002>
<1672578003>

Also notice your Master Tx LED blinks, and if connected like STEP 1 also the Slave Rx LED will blink. If not, probably one of your onboard LEDs is broken.

Slave Example

void setup() {}
void loop() {}

Try uploading this empty code, or any code you like, to the Slave. This does not work, you get an error or the Arduino IDE hangs. As explained in STEP 2, you need to disconnect something to make the Rx LED stop blinking. Depending on the hardware used, remove the jumper wire at Tx or Rx, or just remove the Master Nano if that is easier. Now try again to upload your code.


/*
  Clock display, for testing RS485 communication
*/

#include <TimeLib.h>  // https://github.com/PaulStoffregen/Time
boolean newData = false;
const byte numChars = 16;  // max n-1  char
char receivedChars[numChars];

void setup() {
  Serial.begin(9600);  // same baudrate as Master
  Serial.println();
  Serial.println("-Arduino Slave Reboot-");
}

void loop() {
  RecieveTime();  // keep listening, always and forever
}

void RecieveTime() {
  recvWithStartEndMarkers();
  if (newData == true) {
    newData = false;                // reset flag
    Serial.print("Slave in: ");     // debug
    Serial.println(receivedChars);  // debug
    PrintTime(receivedChars);       // process incoming chars
  }
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      } else {
        receivedChars[ndx] = '\0';  // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    } else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void PrintTime(char TimeChars[numChars]) {
  time_t t = atol(TimeChars);         // convert chars to value
  char DateTimeBuf[26];  // string buffer, max n-1  char
  snprintf(DateTimeBuf, sizeof(DateTimeBuf), "%.2d-%s-%d %.2d:%.2d:%.2d",
           day(t), monthShortStr(month(t)), year(t),
           hour(t), minute(t), second(t));  // 24h format
  Serial.print("Date/Time: ");
  Serial.println(DateTimeBuf);
}

// End


Serial monitor:

-Arduino Slave Reboot-
Slave in: 1672578001
Date/Time: 01-Jan-2023 13:00:01
Slave in: 1672578002
Date/Time: 01-Jan-2023 13:00:02

In this Slave example we print to the serial monitor, to keep it simple. The function 'recvWithStartEndMarkers' is the core function that reads anything from serial between the markers. This works with the 3 global variables at the top of the sketch. The function 'PrintTime' processes the incoming message, where the atol function is the most important to get from text to binary value.

RS485 Modules

RS485 - modules_bb.png

Coding and connecting

There is no extra coding needed for RS485 communication, it is only a hardware implementation. You may use an extra PIN on each Nano to put the RS485 modules in transmit or receive mode, but here we hardwired the DE/RE to 5V for the Master, and DE/RE to GND for the Slave. The Master connects Tx to DI, the Slave connects Rx to RO. On the other side connect A to A, and B to B. Also connect the GND of both RS485 modules, because of the distance they would be on a different power supply.


UTP Cable

RS485 - modules + UTP_bb.png

RJ45 and UTP cable

If you really want to test the communication over long distance, get yourself the RJ45 connectors. Wire about 10cm installation cable to the connectors, and connect the A, B, and Ground. Use one twisted pair for A/B, and another twisted pair for the GND. Usually PIN 4/5 is the middle pair in RJ45, and best for A/B. Use 1/2 or 7/8 for GND.

Power over UTP

It is possible to connect the VCC of both RS485 modules and use a free twister pair. This way you can power your remote Master module, if it has only a sensor and the Nano. But the voltage drop will become terrible if you have more current or a cable longer than 5m. The 5V drops below 3,5V very fast, and the remote unit becomes unstable. For cables that are longer than 5m use 12/24V over the UTP cable and have a buck converter converting it to a stable 5V.

If possible, better use a separate power supply for both Arduino's.

🗲 Lightning WARNING 🗲

If you put your remote device on the roof of a building, in your garden or anywhere outside: it is very unsafe or even a fire hazard🔥. The copper wires will conduct the lightning very good: at best, only your devices will melt.

Working Concept

concept.jpg

In the photo a working concept, the wires are a bit messy. It works with a 25m UTP CAT5E cable.