Go Down

Topic: Arduino RS485 communication for home automation project (Read 1 time) previous topic - next topic

JT007

It works but i can only send digital outputs, i want to acheive getting values back.
The master code:
Code: [Select]
#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;
const int NUMBER_OF_FIELDS = 4; // t_west, t_back, t_up, t_down
int fieldIndex = 0;
int values[NUMBER_OF_FIELDS]; // temp * 10
int deviceID=0;
int function =2;
int data=0;
int RXdata=0;
int data2=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;
byte Cmd = 2;
byte old_level = 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
 
void loop()
{

byte level = (data);

   if (Serial.available() > 0) {       //read value from host PC
    hostprotocol();
   }
  // no change? forget it
  if (data == old_level)
    return;
     
  // assemble message
  byte msg [] = {
     deviceID,    // device 1
     function,    // turn light on
     data // 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] != Cmd)
      return;  // unknown command
   
byte msg [] = {
       0,  // device 0 (master)
       RXdata,
}; 
     
       data2 = buf [2];
//delay (5);  // give the master a moment to prepare to receive     
//Serial.print (data2);
 
    old_level = data;
}
}  // end of loop

void hostprotocol()      //Serial commands received from host
{

if (Serial.available()) { // Read message
    delay(100);
    while (Serial.available()) {
      char ch = Serial.read();
      if (ch >= '0' && ch <= '9') {
        values[fieldIndex] = (values[fieldIndex] * 10) + (ch - '0');
      } else if (ch == ',') {
        if (fieldIndex < NUMBER_OF_FIELDS - 1) {
          fieldIndex++;
        }
      } else if (ch == '-') {
        values[fieldIndex] = values[fieldIndex] * -1;
      } else {
       
        deviceID=(values[0]);
        values[0] = 0;
     
       function=(values[1]);
        values[1] = 0;
       
        data=(values[2]);
        values[2] = 0;
       
        data2=(values[3]);
        values[3] = 0;
   
        fieldIndex = 0;
       
      }
    }
  }
}


and slave
Code: [Select]
#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 coil value to a variable for use later 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

PaulS

Quote
It works but i can only send digital outputs

What does this mean? You are sending data, not "digital outputs".

Code: [Select]
int values[NUMBER_OF_FIELDS]; // temp * 10
The comment makes no sense in terms of the code that it goes with.

Code: [Select]
void fWrite (const byte what)
  {
  rs485.print (what); 
  }
 
int fAvailable ()
  {
  return rs485.available (); 
  }

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

These functions are useless. Get rid of them. Simply call rs485.print(), rs485.available(), and rs485.read().

Code: [Select]
byte msg [] = {
       0,  // device 0 (master)
       RXdata,
}; 

What is this for?

You really should use Tools + Auto Format. That code that jerks all over the place is hard to read.

Get rid of the useless parentheses. They contribute nothing. They interfere with understanding the code.

Is recvMsg a blocking function? What does the master get back?

If the slave is always going to respond with the same values, is it necessary to call the slave at all?

JT007

OK,
Im not totally responsible for 70% of this code, its the sketches i am using written by Nick Gammon - this should already have been established.
I can send a message that operates Leds on the slave device.
in Nicks code the slave sends an acknowledge back which is an echo of the received message
the master unfortunately handels that as being a boolean response, either it received the message back or it didnt.

getting back to the very start, i want to know if the returned message contains the data which the slave built up in the echoed message (msg).
and if i can get the master to split the returned message into variables which i can then send back to the host pc.
unfortunately it appears the acknowledge message is queried to see if its tru or false then the function (received message) returns zero.

That in a nutshell is what i want to know

PaulS

I'd suggest that you refrain from using the word "it" in any future posts. When you use that pronoun, it is never clear what you are referring to.

I suggest, too, that you cite particular parts of you code when you say "it does this". It is not clear what part of the code you are referring to, or whether your understanding of the code is correct.

Quote
the master unfortunately handels that as being a boolean response, either it received the message back or it didnt.

So, stop doing that. The recvMsg function does not return a boolean (true or false). It returns a value. You need to look at the source code or the documentation to figure out what that value represents. The name, though, implies that it is the number of bytes received. Print it out and find out. Change the number of bytes sent by the slave to see if the value in received changes.

Quote
getting back to the very start, i want to know if the returned message contains the data which the slave built up in the echoed message (msg).

How? By using your psychic powers? Where are the Serial.print() statements that confirm what you actually get on the slave or back on the master?

JT007

I removed the Println statements to make the code clearer for any assisting guru's to see the code as stands
i tried to place a serial.print in the received message (function) and nothing happens, no response.

as i understand it there is a response because the led does not light indicating an error.
the function works because if i remove the RS485 data pair and send a message the error led lights

so can i deduce from your comments that i am infact looking in the right area of code to see a response
and that it is your view that i should be able to view the returned message within the received function

Go Up