# Sending minimal data between two Arduinos far away from each other

Problem: I need to send small integer numbers (single-digit numbers suffices) between two arduinos located approximately 50-60m away from each other.

The connection must be made through cables. I have read that the mentioned distance is too long for using serial communication. I do not care if the method is not fast, delays up to one or two seconds are ok for this. If it helps: the devices (Arduino UNO or similar) will run not yet written codes for a simple alarm system (with no cameras/images).

Question: What is a good way to this?

My efforts: I thought a couple of alternatives to solve this problem. Both involve the use of PWM signals sent from a device A to another B.

• One of them requires some DAC in A and read the analog input in B. The values read are then mapped to the small integer lists. I found some disadvantages with this approach:
• Increment of hardware complexity and cost. Although I have read that the digital to analog conversion can be made with cheap capacitors I would have many problems to acquire them because of the lock-down of my country.
• Probably I will need to do many test to set up the mapping procedure due to voltage drop.
• The second is just read the digital input in B many times during a fixed period (e.g. 0.1 or 1 second) and average the values that were read in that period. My bet is that the devices are not synchronized and then the average (times 1023) in such longs periods would be close to the value sent by analogWrite(somepin, value). Finally, the accepted value would be the closest value in alist of acceptable values. Example: For passing one of the numbers 0,1,2 or 3 the A device will output 0, 341, 682 or 1023, respectively. Eg. for passing "1" A will do analogWrite(somepinA, 341). B will read int lecture = digitalRead(somepinB) and get the time average of lecture for some time period. After multiplication by 1023 it could return something like "312". Then, it must find the value in [0, 341, 682,1023] closest to 280 (341) and map to 1.
• Even if they were synchronized some way, I think that I could send 0 or 1 using random numbers or digitalWrite(somepinA) (Is it possible? Advantages? Disadvantages?)

I'm a novice in this field so I do not known if there is something wrong with my approach. I would also appreciate if a better alternative is proposed.

• RS485 RS485 RS485
– Juraj
Jul 17, 2020 at 16:50
• you can use 10 levels of current, which unlike voltage, is the same on both ends. Jul 17, 2020 at 20:18
• @dandavis, I am not sure what you mean, sorry. Jul 17, 2020 at 20:52
• look into "4-20ma" reading for example. it's used over very long distances. in a loop, current is the same everywhere, so if the sensor provides a current instead of a voltage, you can read that current far away. the simplest is to read the drop over a known resistor. Even the on-board ADC should be able to distinguish 10 stable voltage levels. Then you need to turn sensor voltage to current, using a ready-made driver, or a simple opamp circuit. Jul 17, 2020 at 21:19
• one of the answers at diy.stackexchange.com/questions/197992/… gave me an idea to use a modem ... google `arduino fsk modem module` Jul 18, 2020 at 21:38

RS-485 is best (you can buy some modules for this from Adafruit, Amazon, eBay, etc), but you can use the built-in hardware RS-232 serial UARTs from each on pins 0 and 1 so long as the baud rate is really really low. The lower the baud rate, the longer the range can be because lower baud rates reject noise better (and the longer the cable, the worse the noise, since the longer the cable the more it acts like an antenna and an inductor and a capacitor). Here are some rough estimates of how far you can transfer regular-logic-level unbalanced RS-232 signals:

If this trend continues, you should be able to get like 120m at 1200 bps (baud), 240m at 600 bps, 480m at 300 bps, etc. maybe even up to > 1000m at 50 bps. I don't think the trend will continue like that, and we are using 5V TTL logic (signal voltage) levels here instead of RS-232's +/- 12V or so, so our logic levels are much worse and will have less range, so just use `50` baud and give it a shot:

``````// do on each Arduino
Serial.begin(50); // 50 baud = 10 bytes/sec throughput rate; see below
``````

Note that for 8-N-1 serial communication baud rate, which is the default on Arduino, there are 10 bits per byte sent over the wire. This is because there is "one start bit, the eight data bits, and the one stop bit" for every 8-bit byte sent. That's an effective throughput data rate of 80%. This means a baud rate of 50 bps (bits per second) only can transmit 50/10 = 5 bytes per second. That's it! That's suuuuuper slow, but if it's fast enough for your application, it's fast enough!

I hypothesize 5V TTL twisted quad RS-232 communication between two Arduinos would have a maximum range at `50` baud of about 1000m/(24V span for regular RS-232 / 5V span for 5V TTL logic RS-232) = 208m. Just a crude guestimate. Please report back any findings you get from your experiments. I'd like to hear about it.

Assuming that this all does work, it would also be useful to start increasing the baud rate on each device until the data starts getting corrupted. Back off on the baud rate a little, and that's your maximum baud rate. Take that maximum baud rate and divide by 2 or 3, and that's your maximum "safe" baud rate perhaps. If you need throughput that is as high as possible, then that's what I'd do. Ex: maybe in your case `50` baud works just fine, so you increase it. At `1000` baud you start seeing corrupted data, so you back off to `800`. At that point you no longer see corrupted data. So, divide that by 2 or 3 and you get a maximum "safe" baud for your setup of perhaps 800/3 = `267` to 800/2 = `400`.

Try using a twisted quad cable (wires are twisted together in groups of 4) to reduce noise and increase range, and set the baud rates on each Arduino to like `50`. You will need 3 wires connected between the Arduinos:

1. GND to GND
2. Tx to Rx
3. Rx to Tx

Power them each separately with ungrounded power supplies.

Communicate via `Serial.write()` and `Serial.read()` (so long as `Serial.available()` shows some data is available in the read buffer).

# More on balanced vs unbalanced lines, and why I recommend "twisted quad" wire:

Normally, RS-232 is considered to be an unbalanced line transimission system. This means the impedance in the transmission wire is not equal to the impedance in the return wire, which would be a common ground between the sender and receiver, in conjunction with (in parallel with) an Earth ground through the building wiring and/or actually through the Earth...literally, the dirt you walk on. By powering each Arduino with an ungrounded power supply, such as a 2-prong power supply, however, which is common, there is no Earth ground connected to the Arduino. Furthermore, by only having a single transmission line active at any moment between two Arduinos, you have just balanced the transmission between them. Now, the out path is a single Tx signal from one Arduino to the other, and the return path has matching impedance, as it is your single, common GND wire between the two Arduinos. You now have balanced line RS-232 TTL logic level transmission between the two Arduinos. Balanced line transmission can have improved noise rejection and range by using a twisted pair between the two lines. In this case, however, there are 3 lines: Tx --> Rx, Rx --> Tx, and Gnd --> Gnd. So, you should use twisted quad wire, which means 4 wires at once are twisted together. Connect all 3 lines to the same twisted quad bundle. Again, remember, this assumes only one Arduino is transmitting at a time on one single wire in one single direction at a time (so as to not negate your return current through the GND line when transmitting on two lines, one in each direction, or double your return current through the GND line when transmitting on two lines each in the same direction [assuming you had multiple UARTS on each device]), thereby this usage creates a balanced line system since they also aren't truly grounded through a 3-prong grounded power supply. If these 2 requirements are met (1 Arduino transmits at a time, and at least one of them is not grounded to the building wiring), use twisted quad wire, as the system is balanced line communication. If it is not the case, because you are transmitting from each Arduino to the other at exactly the same time, or because both (not one) Arduinos are grounded to the building, thereby offering an alternative return path through the building ground wiring, then twisted quad cable will not benefit you, and you should use regular untwisted wiring.

Having said all that, experimentation is the real boss here. Try it out. if I didn't have twisted quad wire I'd try twisted pair, and if I didn't have twisted pair, I'd try untwisted wire.

# Regarding your approach about using PWM to produce an analog output to be read by the receiving end:

Using PWM to produce an analog voltage to be read by the receiving end is an interesting approach. Without filtering, I think what you'd be doing is producing tremendous noise, however, literally producing electromagnetic radiation (think like low frequency radio or TV waves or something), where this huge 60m wire is your broadcasting antenna. If you put a 20k~50k resistor right at the sending end, however, and a 1uF capacitor right at the receiving end, however, to filter this PWM into an analog output immediately at the sending end, I think it would then eliminate your antenna effect where you are broadcasting something, and work much better, but still be highly susceptible to external noise influencing it. Give it a shot, but I suspect a simple set of digital pins to set HIGH or LOW on different pins to match different states would be much much much better than any analog signal at those lengths, with a 50 baud serial signal being the next best for signal-to-noise thereafter.

So, in order of best to worst signal-to-noise ratio (SNR):

1. differential pair (referenced to each other) digital HIGH/LOW values to represent states, which you update very slowly
2. RS-485 differential pair serial transmission
3. Note: for all of the following really low-speed digital signal sending scenarios, you might try it with the low-pass filter shown in the schematic below too, as it may help reject noise.
4. single-ended (referenced to GND) digital HIGH/LOW values to represent states, which you update very slowly
5. super low-speed SPI (including bit-banging it); ie: declare any digital pin a `CLOCK_PIN`, and any other digital pin a `DATA_PIN`. Set a clock pin LOW, set a data pin HIGH, set the clock pin HIGH. The clock transition tells the receiver (you have to code this up) to read the data pin, so you just read a `1` bit. Set the data pin LOW, set the clock pin LOW. The clock transition tells the receiver to read the data pin, so you just read a `0` bit. Leave the data pin low, set the clock pin HIGH again. You just sent another `0` bit, etc etc. Send data like this really slowly. It will work at great lengths--even better than asynchronous serial since it's synchronous.
6. asynchronous serial (+/- 12V true RS-232) at 100 baud
7. asynchronous serial (+/- 12V true RS-232) at 50 baud
8. asynchronous serial (5V TTL RS-232) at 50 baud
9. asynchronous serial (3V TTL RS-232) at 50 baud
10. analog value filtered with resistor and capacitor low-pass RC filter; update: I'd try this filtering layout for sending analog values via PWM (see schematic below, but use the higher resistor value I describe in my bullets underneath the schematic, rather than the lower value I show in the schematic); the filter may also be beneficial to help filter noise when doing low-speed digital communication too, so give it a shot in your 50-baud rate serial setup above too:
1. Send with `analogWrite()` (PWM); receive with `analogRead()`.
2. Report back on this too please. I'm very curious if it would work.
11. unfiltered PWM---square wave antenna broadcasting who knows what--could result in an interesting broadcasting system for you. Add a transistor and you could really amp up the power and broadcast some interesting signals out! Get some good high power going here (1W~10W+) and maybe even get the government to find out who's jamming GPS and cellular? I don't know: could be interesting!

Schematic of low-pass RC filter to reduce noise between the two Arduinos when sending really low-speed digital signals (better), or slowly-changing analog signals (worse) between the two sides:

simulate this circuit – Schematic created using CircuitLab

1. For filtering the digital signals (ex: 5V TTL pseudo-RS232 serial at 50 to 100 baud):
1. Use 470 Ohms for each resistor, as shown above.
2. This results in a cutoff freq of 847 Hz, so stay below ~169 baud (`cutoff_freq/5 = 847Hz/5 = 169` or so) for digital signal sending through this filter.
2. For filtering analog signals sent via `analogWrite()`:
1. Since most Arduino pins have a PWM Frequency of 490 Hz, we need a cutoff frequency of ~490Hz/10 = 49Hz or lower to cleanly filter out the PWM frequency and result in a true analog output.
2. Using the calculator linked-to below, that means you should use R values of at least 10k each, which results in a cutoff freq. of 40 Hz. You can use 20k resistors each too, for a cutoff freq. of about 20 Hz.
3. To increase cutoff frequency to allow higher baud rates, decrease either R or C or both.
4. For a cutoff frequency calculator, see: https://electronicbase.net/low-pass-filter-calculator/#rc-low-pass-calculator --> "RC Low Pass Filter Calculator" --> enter, for example, 940 Ohms (470 x 2) as the resistor value and 0.2uF (0.1uF x 2) as the capacitor value to see that the resulting cutoff frequency for this low-pass filter is 846.57 Hz.

I'm no filter expert, but this is what I'd try. If someone sees some glaring errors in this filter or ways to improve it, please comment below the answer.

# Extras:

Here's the Bode plot for the above series filter I show except with a 1k resistor and 0.1uF (100nF) capacitor followed by the same thing again. The purple line is the voltage we care about. Source: godfreyl, here.

The cutoff frequency here is 398Hz, which is where the -3db drop occurs, which corresponds to the half power and 70.7% voltage attenuation point. (`sqrt(0.50) = 0.707`, so `0.707^2 = 0.5`)). You can read more about cutoff frequency here.

• twisted pair for TTL?
– Juraj
Jul 17, 2020 at 17:06
• Just a point of terminology: “5V TTL” and “RS-232” are incompatible terms; a link can be either but not both at the same time. The built-in hardware UART is 5V TTL, therefore not RS-232. Jul 17, 2020 at 18:52
• I tend to use “asynchronous serial”, or just “UART”, although the latter refers to the hardware port. For example: “you can use the built-in hardware UART”, “I hypothesize 5V TTL twisted quad serial communication [...]” (at this point it is already clear it's from the UART), “5V span for 5V TTL asynchronous serial”. Then it could be that some people don't know what those terms mean... Jul 17, 2020 at 19:40
• +1 Thank you for your very enlightening explanation! I read it carefully and also I read the linked contents. The approach I will follow depend heavily on the local product availability and prices. I could not find the twisted quad wire in my country (at least in "our eBay"). I think I will go for the RS-485 but I'll also do some tests with RS-232, just to play around. I am curious about your opinion about if the method I suggested could work (even if it's not the best choice) or if it has any major misconceptions. Jul 17, 2020 at 20:50
• I addressed your PWM question just now in the bottom of my answer. Report back please if you try my recommended approach. I'm very curious about it now. Just remember, sending square waves down a long line is...a wireless broadcasting antenna. The lower the frequency, the longer the antenna needs to be to broadcast properly. Has to do with matching the frequency and the wavelength to the speed of light and the antenna length or something like that to get a good wireless signal broadcasted. So, you'd need to filter it to try NOT to broadcast wireless signals that way. Jul 17, 2020 at 22:23

It appears the easiest would be to use a simple CAN transceiver on each end, one set to transmit and the other to receive. You did not mention bidirectional communications although both Physical layers suggested below will support that quite easily. The electrical characteristics of the CAN bus cable restrict the cable length according to the selected bit rate. You can use cabling up to 250 meters with the baud rate of 250 kbit/s. The maximum bus length with a bit rate of 10 kbit/s is 1 km, and the shortest with 1 Mbit/s is 40 meters. Another approach would be to used RS485. RS485 is popular for inexpensive local networks, multidrop communication links and long haul data transfer over distances of up to 4,000 feet. The use of a balanced line means RS485 has excellent noise rejection and is ideal for industrial and commercial applications. Note these typically are driven with Async signals from a uart or similar device. Software serial would work great and leave the onboard serial port for debugging. the Async communications does the syncing automatically, nothing for you to do, just keep the baud rates the same.

• The CAN protocol seems significantly more complex than the typical UART (async serial) over RS-485, and the Arduino has no hardware support for it. Or are you suggesting to do UART over the physical layer of CAN? Nov 30, 2020 at 8:44
• Great you have it. Use the physical layer but what you send on it is up to you. I believe in your case it will be a simple 1 way transmission to a slave. The baud rate you use is whatever you like and is convenient. I generally run software serial at 9600 baud and my terminal at 115200 that way the terminal can get whatever is sent without flooding. Have fun and let us know how it works out.
– Gil
Dec 1, 2020 at 16:13