8

What I want to do is allow Arduino A to send some constant value to Arduino B.

I sense something inherently wrong with my approach, but I cant figure out what it is.

So in the diagram below you will see Arduino A setting its Analog Pin 0 as OUTPUT and write a value 2 every 500ms. On Arduino B we have Analog Pin 0 set as INPUT to receive and print data to Serial. The GND pins of both Arduinos are also connected.

When this setup is executed, Arduino B is constantly receiving data in the form of a 3 digit number starting with 3XX. I am starting to believe this is voltage value?

What is inherently wrong with this idea?

enter image description here

4
  • Have you tried connecting the ground pins together too?
    – Kynit
    Commented Feb 10, 2015 at 4:01
  • @Kynit: Yes, the GND pins were connected (forgot to draw it).
    – lucidgold
    Commented Feb 10, 2015 at 4:08
  • No I do not live in the EE world, but I can try! Excellent answers here, I am trying to absorb it all. Will update soon.
    – lucidgold
    Commented Feb 10, 2015 at 15:43
  • @lucidgold The summary at the start of my answer tells you exactly what to do. The rest tells you why. Commented Feb 11, 2015 at 12:03

6 Answers 6

10

This answer provides both Arduino specific knowledge and general electrical knowledge - both are necessary for a good solution (unfortunately).


Summary

To carry out Arduino analog to analog transfer:

  • Use analogWrite(pin, value) on a valid digital pin (see below)

  • Use analogRead(pin) on a valid analog input pin.

  • Connect a series resistor between the two pins - say 10k.
    Place a capacitor from the analog input to ground, say 100 nF to 10 uF.

The R & C act as a low pass filter to convert the PWM to DC.
Details below.


Arduino analog pins are ONLY for analog input, not for analog output.
So trying to do analog out on an analog pin dooms your attempt to failure.

Arduino analogWrite(pin, value) only works on DIGITAL pins and then only on the subset of digital pins that have PWM capability. This is typically digital pins 3 5 6 9 10 11.

"analogWrite(pin, value) produces as others have said - a PWM signal - rail to rail square waves with mark space ratio that varies so the mean DC value changes. For a 5V system =
V_DC_mean ~~= value/256 x 5V.
Where 'value' comes from analogWrite(pin, value)

To convert the PWM to good-enough DC a low pass filter with a cutoff somewhat below the PWM frame rate is needed. AFAIK Arduino PWM frame rate is about 800 Hz - so components are usually higher than that. A simple RC filter where R x C is usefully more than about 0.001S will start to work . Larger RC is smoother but with secondary effects. Using a 10 uF ceramic cap and a 10k resistor is probably OK. 10 uF x 10k = 0.1S. 1uF and 1k = 0.001 s = marginal. An electrolytic cap can be used but leakage current may slightly affect accuracy. So -


From somewhere in Arduino land (unknown) I copied the material below.
This is NOT in the basic reference, but should be.

  • Writes an analog value (PWM wave) to a pin. Can be used to light a LED at varying brightnesses or drive a motor at various speeds. After a call to analogWrite(), the pin will generate a steady square wave of the specified duty cycle until the next call to analogWrite() (or a call to digitalRead() or digitalWrite() on the same pin). The frequency of the PWM signal on most pins is approximately 490 Hz. On the Uno and similar boards, pins 5 and 6 have a frequency of approximately 980 Hz. Pins 3 and 11 on the Leonardo also run at 980 Hz.

    On most Arduino boards (those with the ATmega168 or ATmega328), this function works on pins 3, 5, 6, 9, 10, and 11. On the Arduino Mega, it works on pins 2 - 13 and 44 - 46. Older Arduino boards with an ATmega8 only support analogWrite() on pins 9, 10, and 11.

    The Arduino Due supports analogWrite() on pins 2 through 13, plus pins DAC0 and DAC1. Unlike the PWM pins, DAC0 and DAC1 are Digital to Analog converters, and act as true analog outputs.

3

analogWrite() on the Uno doesn't actually output an analog value. It outputs a PWM wave whose average is equivalent to that value. If you want to turn it into a true analog value then you need to put it through a low-pass filter in order to remove the components that make it a PWM wave instead.

3
  • What is this "low-pass filter"?
    – lucidgold
    Commented Feb 10, 2015 at 4:17
  • A low pass filter cuts off the high frequencies (ie the square-wavy bits of PWM). Google it or look around this site - there are tons of examples.
    – Kynit
    Commented Feb 10, 2015 at 4:19
  • This is hardly unique to arduino/ATmega; very few microcontrollers contain true DACs, excepting sigma-delta blocks uniquely tailored to audio. Commented Feb 10, 2015 at 4:32
3

If your aim is to send a constant value from Arduino A to Arduino B, then a really easy way is to use SoftwareSerial.

Let's say you are using Arduino Uno - you can use pins 2 and 3 for SoftwareSerial (see which pins are supported for which device at http://arduino.cc/en/Reference/SoftwareSerial)

Cross connect pin 2 and 3 from Arduino A to pin 3 and 2 of Arduino B. You can send any random data between the two Arduinos by uploading a sketch like the following on to each. You can use a program like CoolTerm to have a "SerialMonitor" open to each Arduino (using the Arduino IDE, you can open only one monitor at a time)

The advantage of this approach over using AnalogWrite/AnalogRead is that with AnalogRead, you can only get 1024 values, which is based on the voltage. With SoftwareSerial, you can send any arbitrary data.

// include the SoftwareSerial library so you can use its functions:
#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3

SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);

void setup() {
    pinMode(rxPin, INPUT);
    pinMode(txPin, OUTPUT);

    mySerial.begin(9600);

    Serial.begin(9600);
 }

void loop() {

    if ( mySerial.available() )
    {
         while ( mySerial.available() )
             Serial.write(mySerial.read());

         Serial.println();
    }

    if ( Serial.available() )
    {
        delay(5);

        while ( Serial.available() )
            mySerial.write( Serial.read() );
    }

}
0

As has been mentioned above, using analogWrite won't work. (I suppose you could sample the supposed analogue signal with a fast loop and measure the duty cycle...)

Why not use SoftwareSerial to send data between the two Arduinos?

It's a library which creates another serial port, entirely in software, so it's independent of the main UART on the USB port.

It's already part of the IDE and it's easy to use - in fact the demo code on the help page will already work for you, transferring any characters from the USB serial port to the software serial port.

1
  • AnalogWrite is perfectly OK as long as a simple 1 x resistor and 1 x capacitor filter are added (see my answer). There may be good reason to use analog which is not evident here. Commented Feb 10, 2015 at 6:07
0

As others have pointed out, your original suggestion will not work.

You could use PWM output and a filter which may work (you will need quite a large capacitor and/or resistor). The input at the other end would only be an approximation of the output (you could calculate based on detailed knowledge of component values and frequencies). Depending on the rate at which the value changes you may get different values on each read.

There are better ways. As suggested, serial will work (either hardware or software depending on other factors), and is probably easiest. You could use any of the common communication protocols (I²C or SPI) or even send values via IP.

0

The Analog In does exactly what it says - it only reads (samples) analog voltage levels.

Using AnalogWrite(0,2) does not make pin A0 in Analog In to output the voltage of 2*AVCC/1024, but instead makes the pin D0 to do that instead. (Most D0 pins on Arduino boards do not have a PWM output associated with them, so the behaviour would be undefined.) In the mean time, your A0 is doing nothing. (I suspect it's floating / not connected, hence the 3xx value. Could check the datasheet to be sure.)

So what should we do instead? For a start, connect Arduino B's A0 to Arduino A's pwm pin. If you're using Uno, you can connect to any of the pins 11,10,9,6,5,3. Then you can use the code:

int PWMPin = 11; int SignalLvl = 2; analogWrite(PWMPin,SignalLvl);

Give that a try. And you'll see that it works... sort of.

But then there's a problem. your readings will be close to what you want, but quite erratic. The reason is partly because analog signals are super unreliable and is filled with noise. But the main reason is really that Arduino's analogWrite is actually NOT designed as an analog signal output. It is a PWM, which outputs GND and AVcc levels at variable periods at a fast speed so that it approximates the voltage level you want when averaged.

If you want to experiment with this, you can connect a resistor and capacitor to the output, creating a low pass filter. (Here's more info: http://provideyourown.com/2011/analogwrite-convert-pwm-to-voltage/)


Having said all that, I guess the question most of us would like to ask is: is there a reason why you want to send data via analog? Analog signals are prone to noise. If data fidelity is critical, your best best is to use serial communication as highlighted by most answers here.

For simplicity, I suggest I2c which uses only 2 wires to communicate. If speed is of essence (like, writing to 10,000 bytes of data every second) you could try SPI or even parallel communication.

Hope this helps and good luck!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.