Saturday, June 13, 2020

How to Transfer Data from one Arduino to Another

The Arduino makes it very easy to add simple electronics functions to a device. These include outputs (lights and sounds) as well as inputs (switches, push buttons, motion sensors, temperature sensors, real time clock modules, and many more). In many cases, it can add quite a bit when two devices can communicate and therefore respond to each other.
The most flexible way to achieve this is the serial connection for data transfer. This only requires two or three cables (with no additional electronics) and a few lines of code as described below.

Example of Serial Communication

A simple example are my Back-to-the-Future movie props, which consist of six individual devices that are sitting in the DeLorean Time Machine: the TFC switch, the speedometer, the Time Circuits, the Analog gauges, the SID panel, and the Flux Capacitor. All of these communicate with each other via serial connections. E.g. the TFC switch tells all other devices when it's power switch is turned on, so the other devices start their activity, and the sound module in the Time Circuits plays the "start-up" sound . The speedometer communicates to the other devices the current speed, so the SID panel and the Flux capacitor can increase their activity with increasing speed - and, at 88Mph, the Time Circuits make the "time-jump" and display a new date.

Example Code (One Way Communication)

In this example, I assume that you just need to transfer a single byte, i.e. values in the range 0-255. Of course, this can easily be extended to multiple bytes.
The byte(s) can easily be transferred using a serial connection, using the "TX" (transmit) and "RX" (receive) pins of the two Arduinos. You just connect two cables: the "TX" pin from Arduino #1 to the "RX" pin of Arduino #2, and the GND pins of the two.

In the setup code, you need to start the serial connection with the same baud rate, e.g. 9600 bits per second.  Other possible choices are: 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, or 115200 - but 9600 is the standard value that is usually used, so unless speed becomes an issue, I would recommend to use this. Remember: whatever you use, it has to be the same for both Arduinos. So, the setup code for both Arduinos should include this:

 void setup(){
   Serial.begin(9600); // ... other setup code }

Arduino #1 is sending a byte using the following command:

  byte data = 0;         // declare the byte-type variable "data"
  data = 3;              // set the variable to any value in the range [0-255]
  // or: fill "data" by reading an input pin, or from the result of a calculation
  Serial.write(data);    // transmit the byte-variable "data"

Arduino #2 is receiving the byte. Therefore it needs to continuously check for new serial data.

  void loop() {
   byte data = 0;
   // - check for new serial data - and respond accordingly
   if (Serial.available() > 0) {
      int x = Serial.read();    // The "Serial.read" command returns integer-type
      data = x;
     // - now: do something with "data"
     if (data == 0) { 
       // "0" was received ... do something ...
     } else if (data == 1) {
       // "1" was received ... do something ...
     } else if (data == 2) {
       // ... and so on, and so on ...
     } 
   }
    // ... code to do other tasks (no delays!!!)
}

You absolutely have to make sure that in the "... code to do other tasks" you are not using the command "delay()", as this would prevent your code from checking the serial for new data in a timely manner. If your code needs to wait, you have to implement this as in the "blink without delay" example in he Arduino IDE.

Bi-Directional Communication between Two Arduinos

In the example above, Arduino #1 is sending data to Arduino #2. If you want your Arduino #2 to reply, and send data back to Arduino #1, you only need a third cable, connecting "RX" from #1 to "TX" of #2. Then, using exactly the same code as shown above, your Arduino #2 can also send data, and your Arduino #1 can read these.

Sending Data from One Arduino to Multiple Other Arduinos

For my Back-to-the-Future movie props, I want all other devices to know when the power switch of the TFC is turned on. For this purpose I connect the "TX" pin of Arduino in the TFC to the "RX" pins of all other Arduinos - and I connnect all of their GND pins.
The Arduino in the TFC is then sending the data as in the example above using "Serial.write(data)" and the Arduinos in all the other devices are independently reading the data, each running the "receiving example" above.
But notice, that only one is able to send - it is not possible for all to send data.

 
A More Complex Example

What you could also do: Have two Arduinos (say, #1 and #2) communicate with each other (i.e. bi-directional) and have a few others receive the data from either #1 or #2 (but not from both). Let's say #3 and #4 receive the data from #1. And #5, #6, and #7 receive the data from #2.

For this purpose you would connect:
  • the GND pins of all Arduinos involved
  • the TX pin from #1 to the RX pins of #2, #3, #4
  • the TX pin from #2 to the RX pins from #1, #5, #6, #7

The Timing: Be Reasonable

When implementing the transmit/receive code you should somehow consider the timing. In general, make sure that Arduino #1 is not trying to send data at a faster rate than possible at the given baud rate; and also not faster than Arduino #2 is able to process this. Personally, I try to reduce the amount of serial data as much as reasonably possible.
Two examples:
  • Device #1 has a switch or a push button, and it wants to communicate it's state to device #2. There is no point to transmit the state-of-the-switch information 1000 times per second. Device #1 can keep track of the current state of the switch, and only send serial data to device #2 whenever the state of the switch has changed.
    Alternatively, if you really want to send data continuously, it will likely be sufficient, if you do this 20 times per second (i.e. every 50 milliseconds). This way, there will be a little delay before device #2 will know that the switch has changed it's state - but for most real life applications, a delay of less than 50ms should not be noticeable for a hand-operated switch.
  • Device #1 is a speedometer and sends the current speed to device #2 (which wants to display the speed on an LED display). You do not need to have 100 or 50 or 20 readings per second. 10 readings per second would be plenty, 3 or 4 still probably enough. You could write code, according to the "blink without delay" example that transmits the current speed every 250 milliseconds.
So, do not continuously pump data through the serial connection. Adjust the frequency of the transmissions according to what is really required. 
If the data transfer does not work, maybe try to reduce the frequency at which you send data to see if that helps. If yes, then increase the frequency step by step to see how fast you can get.

Check the Voltages!!!

For all the examples above, it is, of course, essential that all Arduinos involved are operating at the same voltage. So, do NOT mix 5V and 3.3V Arduinos!! However, as long as they are operating at the same voltage you are free to mix different models. For example, you can connect Arduino Unos, Megas, Nano, Pro Minis, etc.  

No comments: