Here's the code. I moved it around a little bit so my arduino sketches are a little easier to work with.
"rs485network.h" (Nick's code, but "message" is now called "networkPacket", and the loop and setup functions were made into separated functions called from my actual setup and loop. Also, his debugging code removed for the sake of brevity in this post)
#include <RS485_non_blocking.h>
byte rs485_xmit = 4;
const unsigned long BAUD_RATE = 9600;
const float TIME_PER_BYTE = 1.0 / (BAUD_RATE / 10.0); // seconds per sending one byte
const unsigned long PACKET_LENGTH = ((sizeof (networkPacket) * 2) + 6); // 2 bytes per payload byte plus STX/ETC/CRC
const unsigned long PACKET_TIME = TIME_PER_BYTE * PACKET_LENGTH * 1000000; // microseconds
const unsigned long TIME_BETWEEN_MESSAGES = 3000;
unsigned long noMessagesTimeout;
byte nextAddress;
unsigned long lastMessageTime;
unsigned long lastCommsTime;
unsigned long randomTime;
void processMessage(); // defined in sketch
void updateNetwork(); // defined in sketch
// what state we are in
enum {
STATE_NO_DEVICES,
STATE_RECENT_RESPONSE,
STATE_TIMED_OUT,
} rs485state;
// callbacks for the non-blocking RS485 library
size_t fWrite (const byte what)
{
Serial1.write (what);
}
int fAvailable ()
{
return Serial1.available ();
}
int fRead ()
{
// lastCommsTime = micros ();
return Serial1.read ();
}
// RS485 library instance
RS485 myChannel (fRead, fAvailable, fWrite, 20);
byte myAddress; // who we are
// Initial seed for JKISS32
static unsigned long x485 = 123456789,
y485 = 234567891,
z485 = 345678912,
w485 = 456789123,
c485 = 0;
// Simple Random Number Generator
unsigned long JKISS32 ()
{
long t485;
y485 ^= y485 << 5;
y485 ^= y485 >> 7;
y485 ^= y485 << 22;
t485 = z485 + w485 + c485;
z485 = w485;
c485 = t485 < 0;
w485 = t485 & 2147483647;
x485 += 1411392427;
return x485 + y485 + w485;
} // end of JKISS32
void Seed_JKISS32 (const unsigned long newseed)
{
if (newseed != 0)
{
x485 = 123456789;
y485 = newseed;
z485 = 345678912;
w485 = 456789123;
c485 = 0;
}
} // end of Seed_JKISS32
void rs485setup (){
// serial for talking to other devices
Serial1.begin(BAUD_RATE);
// initialize the RS485 library
myChannel.begin();
// calculate how long to assume nothing is responding
noMessagesTimeout = (PACKET_TIME + TIME_BETWEEN_MESSAGES) * numberOfDevices * 2;
pinMode(rs485_xmit, OUTPUT);
// seed the PRNG
Seed_JKISS32(myAddress + 1000);
rs485state = STATE_NO_DEVICES;
nextAddress = 0;
randomTime = JKISS32() % 500000; // microseconds
} // end of setup
// set the next expected address, wrap around at the maximum
void setNextAddress (const byte current) {
nextAddress = current;
if (nextAddress >= numberOfDevices){
nextAddress = 0;
}
} // end of setNextAddress
// Here to send our own message
void sendMessage ()
{
memset (&networkPacket, 0, sizeof networkPacket);
networkPacket.address = myAddress;
updateNetwork(); // defined in sketch
digitalWrite (rs485_xmit, HIGH); // enable sending
myChannel.sendMsg ((byte *) &networkPacket, sizeof networkPacket);
digitalWrite (rs485_xmit, LOW); // disable sending
setNextAddress (myAddress + 1);
lastCommsTime = micros (); // we count our own send as activity
randomTime = JKISS32 () % 500000; // microseconds
} // end of sendMessage
void rs485loop ()
{
// incoming message?
if (myChannel.update ())
{
memset (&networkPacket, 0, sizeof networkPacket);
int len = myChannel.getLength ();
if (len > sizeof networkPacket){
len = sizeof networkPacket;
}
memcpy (&networkPacket, myChannel.getData (), len);
lastMessageTime = micros ();
setNextAddress (networkPacket.address + 1);
processMessage ();
rs485state = STATE_RECENT_RESPONSE;
} // end of message completely received
// switch states if too long a gap between messages
if (micros () - lastMessageTime > noMessagesTimeout){
rs485state = STATE_NO_DEVICES;
}
else if (micros () - lastCommsTime > PACKET_TIME){
rs485state = STATE_TIMED_OUT;
}
switch (rs485state)
{
// nothing heard for a long time? We'll take over then
case STATE_NO_DEVICES:
if (micros () - lastCommsTime >= (noMessagesTimeout + randomTime))
{
sendMessage ();
}
break;
// we heard from another device recently
// if it is our turn, respond
case STATE_RECENT_RESPONSE:
// we allow a small gap, and if it is our turn, we send our message
if (micros () - lastCommsTime >= TIME_BETWEEN_MESSAGES && myAddress == nextAddress)
sendMessage ();
break;
// a device did not respond in its slot time, move onto the next one
case STATE_TIMED_OUT:
setNextAddress (nextAddress + 1);
lastCommsTime += PACKET_TIME;
rs485state = STATE_RECENT_RESPONSE; // pretend we got the missing response
break;
} // end of switch on state
} // end of loop
Arduino #1:
#include "rs485network.h"
struct {
byte address;
byte num;
char messageChar;
byte buttonPressed;
} networkPacket;
const byte numberOfDevices = 2;
char updatedChar = 0;
byte updatedDigit = 0;
const byte button = 2;
byte buttonState = 0;
void setup()
{
Serial.begin(9600); // debugging. Serial1 is begun inside rs485setup and is for the network
pinMode(button, INPUT_PULLUP);
myAddress = 0;
rs485setup();
Serial.println("Setup complete.");
}
void loop()
{
rs485loop();
checkSerial();
}
void checkSerial(){
if(Serial.available()){
char input = Serial.read();
if(isDigit(input)){
updatedDigit = input - '0';
Serial.print("Updated digit: ");
Serial.println(updatedDigit);
}
else{
updatedChar = input;
Serial.print("Updated char: ");
Serial.println(updatedChar);
}
}
}
void processMessage() // called from rs485loop() in rs485network.h
{
Serial.print("From ");
Serial.print(networkPacket.address);
Serial.print(": ");
Serial.print(networkPacket.num);
Serial.print(", ");
Serial.print(networkPacket.messageChar);
Serial.print(", ");
Serial.println(networkPacket.buttonPressed);
}
void updateNetwork() // called from sendMessage() in rs485network.h
{
networkPacket.messageChar = updatedChar;
networkPacket.num = updatedDigit;
networkPacket.buttonPressed = !digitalRead(button);
}
Arduino #2:
#include "rs485network.h"
struct {
byte address;
byte num;
char messageChar;
byte buttonPressed;
} networkPacket;
const byte numberOfDevices = 2;
char updatedChar = 0;
byte updatedDigit = 0;
const byte led = 9;
void setup()
{
Serial.begin(9600); // debugging. Serial1 is begun inside rs485setup and is for the network
pinMode(led, OUTPUT);
myAddress = 0;
rs485setup();
Serial.println("Setup complete.");
}
void loop()
{
rs485loop();
}
void processMessage() // called from rs485loop() in rs485network.h
{
digitalWrite(led, networkPacket.buttonPressed);
updatedChar = 'f';
updatedDigit = networkPacket.num + 1;
}
void updateNetwork() // called from sendMessage() in rs485network.h
{
networkPacket.messageChar = updatedChar;
networkPacket.num = updatedDigit;
}
When the button on arduino 1 is pressed, the led in 2 goes on (only works when the enable pin to arduino #1 is disconnected). #2 just sends back the updated struct (if pin 4 from #2 is disconnected). When both pins are connected, nothing happens. When neither pin is connected, nothing happens.