Here is the multi-packet SerialTransfer example:
Pretend that the single Sender sketch represents 5 different RS485 slaves, and the receiver sketch represents a single master.
You can have each slave identified through a particular "packetID" byte.
When the master reads that ID byte, it knows which particular slave sent the transmission, and it then transforms the received packet, into the data which is associated with that particular slave.
You could also have a single slave, which can send multiple packets to the master, through giving that slave multiple ID bytes. For example; slave 1 has ID byte "1" and "2", and slave 2 has ID byte "3" and "4".
Finally, as you can see from "case 5" in the sender sketch, you can have multiple structs (or any group of variable's) sent in a single transmission. Very versatile!
On the opposite end, we have the single master sending data to each one of the slaves individually (probably). That is, there is 1 transmitter and multiple listeners. Every listener is going to have data sent to them, even if the data is not for them. However, each slave can accept or ignore the transmission ,based on the same packet ID byte system. That is, if the slave picks up a packet containing their particular ID byte, they accept it and parse the data. If they pick up an ID byte that isn't theirs, they dump the packet.
Of course, there is a bit more involved with getting this working bidirectionally and with RS485, such as turning on/off the write enable pins, as well as setting up timeouts if a node isn't responding. Remember, since '485 is half-duplex, you can only have 1 sender at any given time.
-
final notes:
- The sketches uses software UART pins, but a hardware UART is preferable
- The sketches were tested between 2 regular Nano's (5v), but different MCU's can have different sized variable's. However, this can be solved by specifying the sizes of the integers between the boards, such as using uint16_t for an unsigned int and uint32_t for an unsigned long.
- Struct sizes can also vary between boards. See here for fixes; Size of struct differences?
- potential fix for esp32 boards using the library Library work with Arduino UNO and ESP32 · Issue #46 · PowerBroker2/SerialTransfer · GitHub
- Level shifting is needed between board's of different logic levels.
Disclaimer: I've never actually used RS485, but this is going off what I've read from some decent sources (incl. Gammon's).
Sender:
#include<SoftwareSerial.h>
SoftwareSerial mySerial(6, 7);
#include "SerialTransfer.h"
SerialTransfer myTransfer;
byte packetID = 0; //packetID byte used to select;
//1. which variable(s) Master will send
//2. which variable(s) Slave will receive
//VARIABLES TO SEND
float singleVariableTX = 3.14;
struct structOne_TX {
int variable_1_struct_1;
unsigned long variable_2_struct_1;
char variable_3_struct_1;
}
structOneTX;
struct structTwo_TX {
boolean variable_1_struct_2;
byte variable_2_struct_2;
int variable_3_struct_2;
long variable_4_struct_2;
}
structTwoTX;
char charArrayTX[21];
unsigned long previousMillis = 0;
unsigned long interval = 1000;
void setup()
{
Serial.begin(115200);
mySerial.begin(9600);
myTransfer.begin(mySerial);
structOneTX = {100, 2000, 'a'};
structTwoTX = {1, 20, 300, 4000};
strcpy(charArrayTX, "Sent from Arduino A");
}
void loop()
{
//LOOPING THROUGH 5 PACKETS TO SEND...
if (millis() - previousMillis >= interval) {
previousMillis = millis(); //will keep looping until response
packetID++;
sending();
if (packetID == 5) { //4 options to send
packetID = 0;
}
}
}
void sending() {
// use this variable to keep track of how many
// bytes we're stuffing in the transmit buffer
uint16_t sendSize = 0;
switch (packetID) {//selector byte chooses the variable(s) to send.
case 1:
sendSize = myTransfer.txObj(singleVariableTX, sendSize);
break;
case 2:
sendSize = myTransfer.txObj(structOneTX, sendSize);
break;
case 3:
sendSize = myTransfer.txObj(structTwoTX, sendSize);
break;
case 4:
sendSize = myTransfer.txObj(charArrayTX, sendSize);
break;
case 5:
sendSize = myTransfer.txObj(structOneTX, sendSize);
sendSize = myTransfer.txObj(structTwoTX, sendSize);
break;
}
myTransfer.sendData(sendSize, packetID); //packetID is read by the receiver, to indicate which variables are coming through
Serial.print("Sent Packet #");
Serial.println(packetID);
}
Receiver
#include<SoftwareSerial.h>
SoftwareSerial mySerial(6, 7);
#include "SerialTransfer.h"
SerialTransfer myTransfer;
//VARIABLES TO RECEIVE
float singleVariableRX;
struct structOne_RX {
int variable_1_struct_1;
unsigned long variable_2_struct_1;
char variable_3_struct_1;
}
structOneRX;
struct structTwo_RX {
boolean variable_1_struct_2;
byte variable_2_struct_2;
int variable_3_struct_2;
long variable_4_struct_2;
}
structTwoRX;
char charArrayRX[21];
byte packetID;
bool flag1 = false;
void setup()
{
Serial.begin(115200);
mySerial.begin(9600);
myTransfer.begin(mySerial);
}
void loop()
{
readAndParseData();
showNewData();
}
void readAndParseData() {
if (myTransfer.available())
{
// use this variable to keep track of how many
// bytes we've processed from the receive buffer
uint16_t recSize = 0;
packetID = myTransfer.currentPacketID();
//searches for the packet ID send by sender.
switch (packetID) {
case 1:
recSize = myTransfer.rxObj(singleVariableRX, recSize);
break;
case 2:
recSize = myTransfer.rxObj(structOneRX, recSize);
break;
case 3:
recSize = myTransfer.rxObj(structTwoRX, recSize);
break;
case 4:
recSize = myTransfer.rxObj(charArrayRX, recSize);
break;
case 5:
recSize = myTransfer.rxObj(structOneRX, recSize);
recSize = myTransfer.rxObj(structTwoRX, recSize);
break;
}
flag1 = true;
}
}
void showNewData() {
if (flag1 == true) {
Serial.println("//////////////////////////////////");
Serial.println(" ");
Serial.print("Packet #");
Serial.println(myTransfer.currentPacketID());
Serial.println(" ");
switch (packetID) {
case 1:
Serial.print("Single Float = ");
Serial.println(singleVariableRX);
Serial.println("");
break;
case 2:
Serial.println("Struct 1...");
Serial.print("Int = ");
Serial.println(structOneRX.variable_1_struct_1);
Serial.print("Unsigned Long = ");
Serial.println(structOneRX.variable_2_struct_1);
Serial.print("Character = ");
Serial.println(structOneRX.variable_3_struct_1);
Serial.println("");
break;
case 3:
Serial.println("Struct 2...");
Serial.print("Boolean = ");
Serial.println(structTwoRX.variable_1_struct_2);
Serial.print("Byte = ");
Serial.println(structTwoRX.variable_2_struct_2);
Serial.print("int = ");
Serial.println(structTwoRX.variable_3_struct_2);
Serial.print("Long = ");
Serial.println(structTwoRX.variable_4_struct_2);
Serial.println("");
break;
case 4:
Serial.print("Char array = ");
Serial.println(charArrayRX);
Serial.println("");
break;
case 5:
Serial.println(" ");
Serial.println("Struct 1...");
Serial.print("Int = ");
Serial.println(structOneRX.variable_1_struct_1);
Serial.print("Unsigned Long = ");
Serial.println(structOneRX.variable_2_struct_1);
Serial.print("Character = ");
Serial.println(structOneRX.variable_3_struct_1);
Serial.println("");
Serial.println("Struct 2...");
Serial.print("Boolean = ");
Serial.println(structTwoRX.variable_1_struct_2);
Serial.print("Byte = ");
Serial.println(structTwoRX.variable_2_struct_2);
Serial.print("int = ");
Serial.println(structTwoRX.variable_3_struct_2);
Serial.print("Long = ");
Serial.println(structTwoRX.variable_4_struct_2);
Serial.println("");
break;
}
Serial.println("//////////////////////////////////");
flag1 = false;
}
}