Saturday 16 January 2016

RS-485 Implementation on an Arduino

RS-485 Standard

The RS-485 allows to implement a low-cost network for several devices. The aim of this post is not to copy the information gathered by Wikipedia regarding RS-485.

The RS-485 is a half-duplex protocol, so this means that its devices cannot listen and speak at the same time. The RS-422 is a protocol based on RS-485 that allows this.

Wiring RS-485

Anyway the RS-485 allows to connect several devices with only 3-wires:
  • Data+ (non-inverting)
  • Data- (inverting)
  • GND (ground or voltage reference)
Some devices mark the Data+ and Data- as B and A. I prefer to call them Data+ and Data-, because this is how they are driven and most PLC manufacturers call them so.

Its important to use the GND wire to make use that Data+ and Data- are refered along the network.

It is important to add bias 120 ohm resistors between Data+ and Data- at both edges of the network, when designing bus type networks. In star type networks, I use to install them on the longest arms.

Before starting

  • The Arduino based on the ATMEGA328 has only an UART.
  • Its UART is used for programming purposes.
  • This UART may also be used for RS-485 communication taking some precautions.

How to implement it on an Arduino 328

RS485 transceivers


The MAX485 family is a very popular set of RS485 transceivers, but there are others like those from Texas Instruments or Linear Technology.

An RS-485 typical transceiver consists on the next pins:
  • RO is a TTL output to be connected to the microcontroller RxD pin.
  • DI is a TTL input to be connected to the microcontroller TxD pin.
  • RE and DE use to be connected together and are used for the flow control: At high level RO is at high impedance and at low level RO sends everything broadcasted from the RS-485 side.
  • A (Data+) and B (Data-) are connected to the network side.

Simplest Arduino implementation

This schematic is borrowed from here.

This is the simplest implementation for RS-485 on an Arduino. Its only drawback is that RO interferes with the USB transceiver, unless D2 is at High level to put RO at high impedance.

The UNO and duemilianove include a 10K-ohm resistor in series between D0 and the FTDI chip to allow to mount other devices to the UART. Unfortunatelly the USB port is lost, unless reprogramming the Arduino.

The Modbus port

The Modbus library implements the RS-485. One of the Modbus constructors is declared as:

Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);

where

u8txenpin may be an Arduino pin number different of 0. If so, this pin handles the transceiver flow control pins RE/DE. This is automatically done by the Library.

The Modbus library includes an example for an slave:

/**
 *  Modbus slave example 3:
 *  The purpose of this example is to link a data array
 *  from the Arduino to an external device through RS485.
 *
 *  Recommended Modbus Master: QModbus
 *  http://qmodbus.sourceforge.net/
 */

#include <ModbusRtu.h>

// assign the Arduino pin that must be connected to RE-DE RS485 transceiver
#define TXEN 2 

// data array for modbus network sharing
uint16_t au16data[16] = {
  3, 1415, 9265, 4, 2, 7182, 28182, 8, 0, 0, 0, 0, 0, 0, 1, -1 };

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus slave(1,0,TXEN); // this is slave @1 and RS-485

void setup() {
  slave.begin( 19200 ); // baud-rate at 19200
}

void loop() {
  slave.poll( au16data, 16 );
} 
 
The slave contains an array au16data, which is available in the RS-485 network either for read or write. Pin 2 is used for the RS-485 flow control.

No comments:

Post a Comment