An Arduino and RS485 | RF Circuits

Monday, August 15, 2011

An Arduino and RS485

I love being a student! It gives you tonnes of perks, such as free industrial samples from semiconductor companies. I just got my order of MAX485 ICs through the post this morning, so I've spent the day playing around with Arduino and RS485 comms. I'm now going to share my experiences with you


The aim of this demo is to simulate some serial data on an Arduino and send it via RS485 to a computer.

RS485? Say what?
485 is a standard very similar to RS232 (the serial port used on an Arduino and your PC). RS485 improves upon 232 by removing the limitation of distance (up to 4000ft) and allows more than two devices to communicate using a single line, though it does this at the cost of using more wires between the devices

What you'll need for this demo:
  • 2x MAX485 ICs (or equivalent)
  • 1x Arduino
  • 1x breadboard (2 preferably)
  • Jumper wires
  • 2x 150R resistors
  • FTDI cable or breakout board

Ok, so how's it done?
For this you're going to need a Maxim MAX485 (or equivalent) IC. This IC will take RS232 signals and perform the voltage level conversions required to turn them into 485 signals.

The MAX485 has 8 pins:
  1. RO - Receiver out
  2. RE - Receiver enable (enabled when this pin is LOW)
  3. DE - Driver enable (enabled when this pin is HIGH)
  4. DI - Driver in (the transmitter pin)
  5. GND - Ground (0V)
  6. A - Connect to pin A of the other 485 IC
  7. B - Connect to pin B of the other 485 IC
  8. Vcc - Power, in my case +5V
I'm not going to go into the basics on breadboarding, but you should place one MAX485 on each breadboard (or on two halves of one breadboard).
  • Wire up the power and ground. Try to use a battery for the transmitter. You can take power from the FTDI board for the receiver. This proves that there's only two wires (the comm) wires going between the devices.
  • Wire pin A to the other pin A
  • Wire pin B to the other pin B
  • On each IC, a 150R resistor goes between pin A and B
  • On the receiver side, wire pin RE to 0V
  • On the transmitter side, wire pin DE to 5V
  • On the transmitter, wire digital pin 0 (TX) from the Arduino to DI
  • On the receiver, wire pin RO on the 485 to the RX pin of the FTDI board
Ok.. that's about it as far as wiring goes. Now for some code.

Code:
The code for this project is reallllly simple. We're just wanting to simulate some data coming from the Arduino, and pick it up using the FTDI. I uploaded this simple sketch to my Arduino:

#define LED_PIN 13;
int i;
boolean b;

void setup() {
Serial.begin(57600);

i = 0;
b = false;
pinMode(LED_PIN, OUTPUT);

Serial.println("Init() complete");
}

void loop() {
i ++;

Serial.println(i);

b = !b;
digitalWrite(LED_PIN, b);

delay(1000);
}



Upload that to your Arduino and you should see the LED flashing roughly every 1 second. This means that it's sending serial data every 1 second. Now plug in your FTDI board to the PC and open up serial monitor in the Arduino IDE. If you have everything wired correctly, you'll see a number appearing in the window each time the Arduino sends something. Cool eh?


[UPDATE]
Handling two way communications:
The MAX485 and equivalents are only half duplex, meaning that they only support sending data in one direction at a time. This is fine, but it means you're going to need to account for that in your code.

It is possible to get full duplex versions of the MAX485 (I can't remember the part number right now). These bypass the need for any of the stuff below, but you will need four wires running between each device. Not a problem if you're running short distances, but it gets expensive if you have ~4000ft of cable. Anyway, it's pretty easy to get past the limitations of half duplex...

Remember the RE and DE pins? They specify whether the chip is in receive (RX) or transmit (TX) mode. If we control these from a pin on the Arduino we can leave the chip in RX mode, wait till something is received, and then change to TX mode to reply. Luckily the DE pin has a NOT gate on it, so you can drive both pins from one pin on your Arduino.

Note: From this point on you will need two Arduinos, as the FTDI board can't control the MAX485 in the way we want.

If you take a wire from your Arduino's digital pin 2, and wire it to DE, and then take another jumper wire and wire DE to RE, that will handle the TX/RX mode of the chip. Do this for both chips.

One of your Arduinos will need to be the master of the "network". This is typical in 485 applications, where there are several slave devices taking cues from a master. The master will query a slave, then change to RX mode. The slave will receive the command, and change to TX mode to send its response. After the response both devices change back to their normal mode.

At this point in your project you should probably specify exactly what a "command" is. They usually go along the lines of:
[START BYTE][COMMAND][PARAMS][END BYTE]
or even:
[START BYTE][DEVICE NUMBER][COMMAND][PARAMS][END BYTE]

It's up to you to specify what the start byte and end byte are. You also have to specify how long and what the commands are (1 byte will provide 255 commands), and how long the parameters are (whether they're a fixed length or not).

Below, I'll use 0xFF (255) as the start and end bytes, and 0x01 as the command (send status). The slave device will be number 0x05. Params are optional and may be any length (zero or more whole bytes).

The resulting communications between the two devices would look something like this:
StepMasterSlave
1Prepare command
0xFF 0x05 0x01 0xFF
Waiting
2Send commandWaiting
3Change to RX mode
Set pin 2 to LOW
Receive serial data
0xFF 0x05 0x01 0xFF
4WaitingParse serial data
Start byte ok, ID byte OK, command = send status, end byte ok
5WaitingChange to TX mode
Set pin 2 to HIGH
6WaitingSend response (0x05 = ID, 0x01 = status ok)
0xFF 0x05 0x01 0xFF
7Receive serial dataChange back to RX mode
Set pin 2 to LOW
9Change back to TX mode
Set pin 2 to HIGH
Waiting
10Parse data....Waiting


This is just an example of very basic comms between two device, but you can do a lot with it. I'm using something similar for my Arduino Backplane Experiment, only with I2C instead of serial.

I haven't gotten around to writing the code for two-way communications yet. Hopefully I've explained it well enough so you can have a stab at it. If anyone's feeling really stuck, give me a shout in the comments or on Twitter (@paddypluggedin) and I'll try and throw some code together

No comments:

Post a Comment