Hi,
I have a system containing one master arduino (UNO), and 11 slaves (arduino UNO).
I'm using the RS485 module for communication, see
https://arduino-info.wikispaces.com/RS485-Modules
, with the MAX 485 chip.
I'm also using the library by Nick Gammon, see Gammon Forum : Electronics : Microprocessors : RS485 communications
to make sure no corrupt messages are read (interpreted as ok messages).
The communication works fine for longer periods, but from time to time, the connection fails (and is never recovered).
Sometimes the master loses the connection to all the slaves, and sometimes the communication works for e.g slave 1 and 2, and fails for slave 3-11. Resetting the slaves "solves" the problem.
What may be the issue here ?
Is it a buffer somewhere in the SoftwareSerial library that is never emptied, or is it a hardware issue ?
Or something else ?
Master code:
#include <SPI.h>
#include <avr/wdt.h>
#include <SoftwareSerial.h>
#include <RS485_protocol.h>
#define SSerialRX 5 //Serial Receive pin
#define SSerialTX 6 //Serial Transmit pin
#define SSerialTxControl 3 //RS485 Direction control
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
const boolean debug = false;
void fWrite(const byte message)
{
RS485Serial.write(message);
}
int fAvailable()
{
return RS485Serial.available();
}
int fRead()
{
return RS485Serial.read();
}
byte slaveAddresses[11] = {
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
};
byte slaveValues[11] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
byte slaveIdCounter = 0;
unsigned long statusTimer = 0;
unsigned long statusDelay = 2000;
void setup() {
Serial.begin(9600);
sbi(UCSR0B, TXEN0);
pinMode(SSerialTxControl, OUTPUT);
digitalWrite(SSerialTxControl, LOW); // Init Transceiver
RS485Serial.begin(4800); // set the data rate
statusTimer = millis() + statusDelay;
}
void loop() {
if (slaveIdCounter >= sizeof(slaveValues)) {
slaveIdCounter = 0;
}
readSlaveStatus(slaveIdCounter);
}
void readSlaveStatus(byte slaveId) {
if((unsigned long)(millis() - statusTimer) >= statusDelay) {
// Write to RS485 bus, using address for given slave
byte address = slaveAddresses[slaveId];
byte message[2] = {address, 9};
Serial.println("sending to");
Serial.println(address);
UDR0 = 1;
digitalWrite(SSerialTxControl, HIGH); // Enable RS485 Transmit
sendMsg(fWrite, message, sizeof(message));
flushTransmissionBuffer();
digitalWrite(SSerialTxControl, LOW); // Disable RS485 Transmit
// Wait for answer on RS485 bus, save answer to slaveValues array
byte received[3] = {0, 0, 0};
unsigned long ms = millis();
while (!recvMsg(fAvailable, fRead, received, sizeof(received)))
{
if (millis() > ms + 3000) {
Serial.println("not receiverd any message");
break;
}
}
if (received[1] == 9 && received[0] == address)
{
Serial.println("received message");
Serial.println(received[2]);
slaveValues[slaveId] = received[2];
}
statusTimer = millis();
slaveIdCounter += 1;
}
}
void flushTransmissionBuffer() {
while (!(UCSR0A & (1 << UDRE0))) // Wait for empty transmit buffer
{
UCSR0A |= 1 << TXC0; // mark transmission not complete
}
while (!(UCSR0A & ( 1 << TXC0))); // Wait for the transmission to complete
}
slave code:
/*-----( Import needed libraries )-----*/
#include <RS485_protocol.h>
#include <SoftwareSerial.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define SSerialRX 6 //Serial Receive pin
#define SSerialTX 7 //Serial Transmit pin
#define SSerialTxControl 5 //RS485 Direction control
/*-----( Declare objects )-----*/
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
int slave_id = 11;
const int numberOfPins = 6;
const int pinArray[numberOfPins] = {13, 12, 11, 10, 9, 8};
static int counter = 0;
template<class T> inline Print &operator <<(Print &obj, T arg) {
obj.print(arg);
return obj;
}
void fWrite(const byte command)
{
RS485Serial.write(command);
}
int fRead()
{
return RS485Serial.read();
}
int fAvailable()
{
return RS485Serial.available();
}
void setup()
{
Serial.begin(9600);
for (int i = 0; i < numberOfPins; ++i) {
pinMode(pinArray[i], INPUT);
digitalWrite(pinArray[i], HIGH);
}
pinMode(SSerialTxControl, OUTPUT);
digitalWrite(SSerialTxControl, LOW); // Init Transceiver
RS485Serial.begin(4800); // set the data rate
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
byte received[3];
if(recvMsg(fAvailable, fRead, received, sizeof(received)))
{
Serial << "Received = " << received[0] << " slave_id = " << slave_id << "n";
if(received[0] == slave_id)
{
byte command = received[1];
byte message[] = {
slave_id,
command,
0
};
if(command == 9) // send connection status
{
message[2] = getStatus();
Serial << "Sending = " << message[2] << "n";
delay(10);
digitalWrite(SSerialTxControl, HIGH);
sendMsg(fWrite, message, sizeof(message));
while(!(UCSR0A & (1 << UDRE0)))
UCSR0A |= 1 << TXC0;
while(!(UCSR0A & ( 1 << TXC0)));
digitalWrite(SSerialTxControl, LOW);
}
}
}
}
byte getStatus()
{
byte result = 0;
for(int i = 0; i < numberOfPins; ++i)
{
if(digitalRead(pinArray[i]) == LOW)
{
result = result + 1;
}
}
return result;
}
