Working RS485 sketches wanted

Would one of you kind individuals help me in obtaining a working multidrop sketch of Nick Gammons RS485 master and slave sketches.
OR
is there somthing i am missing with his two example sketches on his website.
I must admit i was hoping for plug and play, the RS485 is just a small part of my overall aim.

Im wanting to set up initially with one master and one slave on Arduino Uno's
my goal is to build somthing like a WAGO programmable controller/PLC for use in a homebuilt submersible vehicle (ROV)

Ive gone through the pain of discovering i had to go back to IDE version 0023 to get it to upload i also installed the IDE version 1.0 Sreial library into the Ver 023 lib folder to get the sketches to upload without errors.
I have 2 PCBs made up as per Nicks drawing with Max485 Ics and they are linked with 2m of CAT5 twisted pair wire.

Am i able to monitor the boards using the USB and the serial monitor or does this clash with the RS485 operation.
do i have to create data to send -my understanding of the code is that the master is reading its analogue port A0 and if it changes it transmits its response to the slave - i have left the analogue input floating so it should be jumping all over the place creating good data.

the slave just sits there and if i connect to it with the serial monitor, there is nothing from it. (baudrate and ports were set up correctly)

any assistance would be greatfully appreciated.

He's referring to this page:

This circuit:

@OP: don't make people work too hard to help you. Give them some links and clues about what you are asking.

Ive gone through the pain of discovering i had to go back to IDE version 0023 to get it to upload

It was written a while ago. I deleted the first line of the example sketch, namely:

#include "WConstants.h"

Then it compiled OK under version 1.0.1 of the IDE.


How about posting the actual master and slave sketch you are trying? You should be able to get them both to compile under 1.0.1 using the method I described above.

i have left the analogue input floating so it should be jumping all over the place creating good data.

Random noise != good data.

It was a handy way of getting it to produce values without having to connect up a whole load of test instruments just to acheive the same outcome

i didnt pick up on was the difference between Hardware and Software and how it pertained to my setup.
Ie. if you used the hardware config it was the USB link i was using to upload the sketch etc.

I did discover it had been working all along, I quickly coupled the circuit together and must have skimmed over the part indicating the LED on pin 11. once inserted the Uno pair started working as expected.

I have a couple of quick questions if you don’t mind.
Im not able to find a way of breaking into the code on the master to allow PC interface/interaction, i want to be able to send and receive serial data from the master.

I have added a second serial connection in the code with a 9600 baud rate and it works at sending and receiving from the master whilst its running the 485 link however i don’t quite understand how to write or read data to be used in the 485 message.

The second question is how to understand the slaves return message, are you able to provide an explanation as to how this is achieved.
as far as i can figure out there is a return response which the master hears and hold LED on pin13 low unless there is a broken link, corrupted message or i guess a time out.

JT007:
Im not able to find a way of breaking into the code on the master to allow PC interface/interaction, i want to be able to send and receive serial data from the master.

I don't know what you mean by "breaking into the code". If you want to have device-to-device and also communicate with a PC you probably need two serial connections (eg. software serial and hardware serial).

I have added a second serial connection in the code with a 9600 baud rate and it works at sending and receiving from the master whilst its running the 485 link however i don’t quite understand how to write or read data to be used in the 485 message.

I don't understand that question, if it is a question.

The second question is how to understand the slaves return message, are you able to provide an explanation as to how this is achieved.
as far as i can figure out there is a return response which the master hears and hold LED on pin13 low unless there is a broken link, corrupted message or i guess a time out.

As far as the RS485 stuff goes, with only 2 wires you can only have one master. So the master has to send a message "addressed" to one slave and stop being a master. Then the addressed slave becomes a master and replies. Then the master resumes being a master again. You would need some sort of time-out in case the slave doesn't reply.

I think you are struggling with two different concepts. First is the RS485 standard which just defines the physical electrical properties of the communications hardware that makes up a RS485 link. With the proper external chips, wire, termination resistors, and possibly a little tweaking of the serial driver you use to switch from transmit mode to receive mode that is pretty much a done deal, many have and are doing it and much should be avalible to help you implement this physical communications link.

The second concept is what software communications protocol will you use for stuff you hook up to your RS485 link? There is no single standard software protocol that works, but rather several, and of course your free to design your own protocol that the master and slave devices will utilize in their software design. Modbus is one popular protocol often using RS485 type links.

So there are no simple answers for you questions. If you are trying to communicate to existing slave devices then you need to find out what software protocol they are expecting to be used with. If not you are free to design your own or just find a decent Modbus library and utilize that protocol.

Lefty

Hi Lefty/Mike
Your help has been really useful.
i am aware from having worked offshore for the last ten years that what i wanted is possible i just needed pointed in the right direction.
i think its peoples lazy description of the communication protocol which has confused me.
we use RS485 links to talk to an array of underwater instruments such as dopler, sonar, altimeter, bathy, profilers etc, many of which are on a RS485 bus called arcnet, believe it or not they all pass data back at very high speeds. Eg, a sonar would be useless if it couldnt return a message showing its signal its returns. The general description is to call it RS485 instead of actually saying what communication protocol it is using.

*second serial port.
i tried to describe my intention to use both a hardware and software serial link in the master so that i could communicate via a PC to the BUS, i appolegise for any confusion. I have come to the conclusion im really crap at asking questions, the guys on the forum seem to have dificulty understanding mine.
I do appreciate you are all unpaid for your assistance on the forum and have a life.

I have taken a look at modbus and over the next week or so will have a go at getting it to work for my simple Arduino programable logic controller.

I want to use RS485 because i want communication with devices over a 100m distance.

good,i didnt pick up on was the difference between Hardware and Software and how it pertained to my setup.

Thanks Chaps,
This is how far i have managed to get
Basic RS485 Master/Slave example from Nick Gammons code.
The changes made are the introduction of a bit weighted digital output on the slave and a PC host serial connection to the master module.

The design idea is to be able to use a host PC with a USB connection to a master module to control several slaves for use in hobby based micro controlled logical interface, this will differ from a programmable logic controller PLC as the code will be written to the device once and then the multiple devices will have various fixed functions which will only respond when controlled from the master commands.

Industrial systems would be like the Wago or an intelligent relay for example.
this system/project will be perfect for home automation, model railways, flight sims, robotic control to name but a few uses.

C# is not my preferred programming language so if its crap code, get over it

You need to do the following prerequisites before you can use this code.

I used Nick Gammons schematic for setting up my RS485 link
The code was loaded onto two separate Arduino Uno’s – master on one slave on the other

The Software serial version of the Arduino RS485 code was used – this leaves the USB serial link free for programming and interfacing with the devices
Nick code example used an analogue input to generate a value to be transmitted to the slave as a message, I commented this out and set up a variable to hold the incoming value – this value is used to hold the value to be used for driving the digital outputs D5,D6,D7,D8,D9,D10,D11,D12 these outputs are bit weighted, ie
255 =( 11111111) D5=1,D6=1,D7=1,D8=1,D9=1,D10=1,D11=1,D12=1
000 =( 00000000) D5=0,D6=01,D7=0,D8=0,D9=0,D10=0,D11=0,D12=0
127 =( 11111111) D5=1,D6=0,D7=0,D8=0,D9=0,D10=0,D11=0,D12=0
Got it – cool don’t forget to attach LEDs to the digital outputs (with a load resistor).
D13 was left as an error indication LED
It’s a pain writing to two devices on one machine, remember to change serial port between uploading to devices – two masters or two slaves isn’t a good start, been there.

The initial problems I had using Nicks code was I didn’t read his instruction fully or correctly, sorry Nick. This led to me misunderstanding that using the hardware example was using the same pins as the USB port the second issue was I built the MAX485 physical link and for some reason felt that was it and it should work – I needed an LED on pin D11 of the master and an analogue input A0 on the slave.
Don’t make the same mistakes I made, getting impatient with Angry Mike,PaulS and Nick Gammon is not a good move, im still left out in the dark, sorry guys.

The next stage will be to add more Slave units for analogue input, analogue/PWM output and digital input.
On completion of basic operation, I plan to use the various modbus examples to actually incorporate a proper communication protocol.

Again don’t follow in my footsteps and ask general questions about how to use RS485 for communication, the guys on the forum are unforgiving and will eat you alive, yep we all know there are various communication methods/protocols when using RS485 links – so spell it out. Thanks to Lefty for intervening and calming the waters.

Ok so once set up
Open the serial monitor tool and send digital values to the master
The format is as follows:
O*** where O is capital letter “O” followed by 0 to 255 formatted to 3 digits, 0 = 000 and 255 = 255
The modified master code is as follows

#include "WConstants.h"
#include <NewSoftSerial.h>
#include "RS485_protocol.h"

NewSoftSerial rs485 (2, 3);  // receive pin, transmit pin
const byte ENABLE_PIN = 4;
int channel = 0;
int data=0;
const byte LED_PIN = 13;
int incomingByte=0; // for incoming serial data
int thousands=0; int hundreds =0; int tens =0; int ones=0;
int inByte=0;
// callback routines
  
void fWrite (const byte what)
  {
  rs485.print (what);  
  }
  
int fAvailable ()
  {
  return rs485.available ();  
  }

int fRead ()
  {
  return rs485.read ();  
  }

void setup()
{
  rs485.begin (28800);
   Serial.begin(9600);
  pinMode (ENABLE_PIN, OUTPUT);  // driver output enable
  pinMode (LED_PIN, OUTPUT);  // built-in LED
}  // end of setup
  
byte old_level = 0;

void loop()
{

  // read potentiometer

 // byte level = analogRead (0) / 4;// commented out as it is now variable being written
  byte level = (incomingByte);
  // Serial.print(level);// print to serial monitor - for testing only
   
   if (Serial.available() > 0) {       //read value from host PC
    hostprotocol(); 
   }
  // no change? forget it
  if (level == old_level)
    return;
      
  // assemble message
  byte msg [] = { 
     1,    // device 1
     2,    // turn light on
     level // to what level
  };

  // send to slave  
  digitalWrite (ENABLE_PIN, HIGH);  // enable sending
  sendMsg (fWrite, msg, sizeof msg);
  delayMicroseconds (660);
  digitalWrite (ENABLE_PIN, LOW);  // disable sending
  
// receive response  
  byte buf [20];
  byte received = recvMsg (fAvailable, fRead, buf, sizeof buf);
 
  digitalWrite (LED_PIN, received == 0);  // turn on LED if error  
  
  // only send once per successful change
  if (received)
{
    if (buf [0] != channel)
      return;  // not my device
      
    if (buf [1] != 2)
      return;  // unknown command
    
byte msg [] = {
       0,  // device 0 (master)
       data,  // turn light on command received
       //data

};
  
    old_level = level;

}

}  // end of loop

void hostprotocol()      //Serial commands received from host
{
  inByte = Serial.read();
    switch (inByte)
    {
      
 case 79: //O  out
 
        DigitalOut();
   break;
  
  }
}
void DigitalOut() {
    
 // send data only when you receive data:
Serial.print("Digital OK");
  
 // only if there are bytes in the serial buffer execute the following code
  if(Serial.available()) {
   
     //keep reading and printing from serial untill there are bytes in the serial buffer
     //while (Serial.available()>0){
       if (Serial.available()>2){ // got 3 characters
        
// assume comes in as hundreds, tens, ones
hundreds = Serial.read() - 0x30;  // read the byte & convert from ASCII to a number
tens = Serial.read() - 0x30;
ones = Serial.read() - 0x30;

// now make into a digit
incomingByte =  hundreds*100 + tens*10 + ones;
     
 }
 Serial.print(incomingByte);
    }
 
//int value = (incomingByte);
 }

2nd part

The modified RS485 slave code is as follows

#include "WConstants.h"
#include <NewSoftSerial.h>
#include "RS485_protocol.h"

NewSoftSerial rs485 (2, 3);  // receive pin, transmit pin
const byte ENABLE_PIN = 4;
int channel = 1;// Device ID

int Inputvalue =0; // Input value from Master

int ledPin = 12;// digital bit weighted outputs
int ledPin1 = 11;
int ledPin2 = 10;
int ledPin3 = 9;
int ledPin4 = 8;
int ledPin5 = 7;
int ledPin6 = 6;
int ledPin7 = 5;


void fWrite (const byte what)
  {
  rs485.print (what);  
  }
  
int fAvailable ()
  {
  return rs485.available ();  
  }

int fRead ()
  {
  return rs485.read ();  
  }
  
void setup()
{
  rs485.begin (28800);
  pinMode (ENABLE_PIN, OUTPUT);  // driver output enable
  //Bit weighted gigital outputs
  pinMode(ledPin, OUTPUT);  // initialize the LED pin as an output: 
  pinMode(ledPin1, OUTPUT); // initialize the LED pin as an output:
  pinMode(ledPin2, OUTPUT); // initialize the LED pin as an output:
  pinMode(ledPin3, OUTPUT); // initialize the LED pin as an output:
  pinMode(ledPin4, OUTPUT); // initialize the LED pin as an output:
  pinMode(ledPin5, OUTPUT); // initialize the LED pin as an output:
  pinMode(ledPin6, OUTPUT); // initialize the LED pin as an output:
  pinMode(ledPin7, OUTPUT); // initialize the LED pin as an output:
}

void loop()
{
  byte buf [20];
  
  byte received = recvMsg (fAvailable, fRead, buf, sizeof (buf) - 1);
  
  if (received)
    {
    if (buf [0] != channel)
      return;  // not my device
      
    if (buf [1] != 2)
      return;  // unknown command
    
    byte msg [] = {
       0,  // device 0 (master)
       3,  // turn light on command received
    };
    
    delay (5);  // give the master a moment to prepare to receive
    digitalWrite (ENABLE_PIN, HIGH);  // enable sending
    sendMsg (fWrite, msg, sizeof msg);
    digitalWrite (ENABLE_PIN, LOW);  // disable sending
    
    //analogWrite (11, buf [2]);  // set light level AS WAS  JT

    Inputvalue =buf [2];// write register value to a variable JT

   // digital bit weighted outputs 
   digitalWrite(ledPin, (Inputvalue >> 0 )% 2);// LSB
   digitalWrite(ledPin1, (Inputvalue >> 1)% 2);
   digitalWrite(ledPin2, (Inputvalue >> 2)% 2);
   digitalWrite(ledPin3, (Inputvalue >> 3)% 2); 
   digitalWrite(ledPin4, (Inputvalue >> 4) % 2); 
   digitalWrite(ledPin5, (Inputvalue >> 5) % 2); 
   digitalWrite(ledPin6, (Inputvalue >> 6) % 2); 
   digitalWrite(ledPin7, (Inputvalue >> 7) % 2); // MSB
    
   }  // end if something received
   
}  // end of loop

A Picture of the PCB layout for the MAX485 and a drawing showing the various connections will be provided later.

What has been achieved?

You can now drive 8 relays for example which are 1000m away from your PC over 2 wires (twisted pair TWP) a line resistor of 120 ohms will be needed between the A/B wire connections on both ends of the wire link. Look at LVR.com where Jan Alexson explains serial communication and RS485 at great depth- especially calculating the line resistor for a given wire link/distance
(The remote board will obviously require its own power)

Issues
Data type is wrong for data value being transmitted; currently it’s a byte where the input from the host PC is a formatted string/decimal value.
Where the host PC sends O237 the slave works but when the value is less than 100 the slave doesn’t change.
In the slave code the value is parsed to give 100s, 10s and units, it is not needed the value should be able to be used directly. This change has not been implemented yet.

With Nicks code above (all be it played with by me)
can someone please tell me how i can get to serial.print the received slave message from the master.
it obviously receives somthing as the Led on pin d13 does not light up indicating that there is no error and that the messege was acknowledged.

I would like the slave to pass messages back when polled and i belive this is already in place, i would like to be able to have several bytes sent in the return message which can be written to variable so that i can output them to the Host (pc connected to master module).
thanks
J.

Hi, the http://ArduinoInfo.Info WIKI now has a working RS485 example showing hardware, software and data direction control:

http://arduino-info.wikispaces.com/SoftwareSerialRS485Example