Masterless serial communication between multiple arduinos.

I'm working on device that will have 3 arduinos.

I'm looking for a way to have any of the arduinos broadcast a stream of data to any of the other arduinos at any time. for example, if a button is pressed on Arduino 2 it will instantly send a message to Arduino 1.

The problem with I2C and SPI, and other master/slave protocols is the master must ask for the data first. The slaves cant send data to the master if it didnt request anything.

Asynchronous Serial doesnt necessarily have a master role, but Async Serial is really only for communication between 2 devices. no more.

I'm looking for something in between I2C/SPI and Async Serial. I dont want the master to have to ask for data first, the slaves should be able to send whenever they like and the intended recipient Arduino will receive/action the data when it can, and I also need to have more than 2 arduinos sending and receiving.

So I am imagining something like an Async Serial port that uses 1 wire for transmit and receive, plus a transmit indicator wire, plus common ground. All arduinos would be connected to all 3 wires.

The idea is, all arduinos are receiving on the transmit/receive wire. When an Arduino wants to transmit:

  1. it checks if the transmit indicator wire is low, if it is low something else is transmitting. Its transmit operation fails. the program will need to handle this and retry if necessary.
  2. it pulls the transmit indicator wire low telling other Arduinos a transmit operation is happening and not to transmit. It also switches from receiving mode to transmitting mode on the transmit/receive wire.
  3. The arduino transmits its data over the transmit/receive wire. All arduinos have to be configured for the same baud rate.
  4. When it is finished it lets the transmit indicator wire go high telling the other arduinos there is no one transmitting, it then switches back to receiving mode on the transmit/receive wire.

To receive data would be the same as usual, poll Serial.available(). If theres bytes in the buffer, retrieve them, process them, then go back to polling for available bytes.

Anyone know of any existing libraries to do this ? or any clues how to make this work with the Serial or software serial libraries? Or, anyone have any better ideas?

RS-485 uses only two wires. You don't need an extra indicator wire. Just use a timer to know that a character was received "recently", like a few character times at whatever baudrate you're using. At 9600, each character takes ~1ms, so you should wait 5ms (plus random amount?) before sending anything. If it was addressed to you, respond immediately to keep other Arduinos from hopping on.

This is just like radio transmissions. Receiving data is the indicator that the "network" is busy.

Cheers,
/dev

"Asynchronous Serial doesnt necessarily have a master role, but Async Serial is really only for communication between 2 devices. no more."

You could not be more wrong. You need to design a protocol to handle this. The main frame computer industry communicated with dozens of devices on one async line. Each device has a unique address that is in a specific location in the message text. The host computer then "polls" the remote device to see if it has anything to send. All the mainframe manufactures used this method. Each one used a different protocol, but effectively they all worked the same way. IBM normally used synchronous communication.

Paul

Often it's easier to have a master. You can have the master self-select. If your device hasn't heard from a master within the last 1000 milliseconds, then it can take over as the master and let all the others that it's the new master. Obviously add some randomness there so that they don't all claim the master role simultaneously.

You can do that with I2C but the Arduino I2C library is pretty poor when trying to switch roles.

For RS485 you need the correct driver chips. You can't do that with just Arduino pins.

CAN-BUS is another system where a master isn't required. It has a really neat way of resolving conflicts that always allows messages with higher priority to step on lower ones. Once again, it does need proper driver chips.

Or just make your own bus on the Arduino pins like you said.

For RS485 you need the correct driver chips. You can't do that with just Arduino pins.

LOL, thanks for pointing that out! I just realized you could use NeoSWSerial to "listen" to one pin most of the time. When you want to send something, start a 2nd NeoSWSerial on the same pin, but use it as a TX pin instead:

const uint8_t BUS_PIN = 3;

NeoSWSerial bus_listen( BUS_PIN, 255 );
NeoSWSerial bus_talk( 255, BUS_PIN );

const int BUS_SPEED = 9600;

void setup()
{
  bus_listen.begin( BUS_SPEED );
}

void loop()
{
  if (something to transmit and ok to talk) {
    bus_listen.stop();

    bus_talk.begin( BUS_SPEED );
    bus_talk.print ...
    bus_talk.flush();
    bus_talk.stop()

    bus_listen.begin( BUS_SPEED );
  }

Cheers,
/dev