5

I was considering several different ways to send simple data from one Arduino to another when I though, why not connect a PWN pin of one Arduino to the analog pin on another? I could send simple messages for one to the other by setting different values on the PWM pin. This seems like it would work, except for the fact the the PWM pins mimic voltages with pulses.

Is this a reliable way to link two Arduinos, If I only want to communicate 4 states? Also, will I need to include some additional components in the connection (resister, capacitor, etc.)

All it needs to do is send a 2v pulse for yes and a 5 v pulse for no. It needs to do this about 6 times an hour.

Hoytman
  • 747
  • 5
  • 13
  • 27

4 Answers4

7

Yes, you can do this with "a little programming" or more easily by adding two cheap components.

If you connect a say 47k resistor from PWM_Out to Analog_In and a say 100 uF capacitor from Anaolg_In to ground you will be able to read the equivalent analog value to an accuracy of around 1%. Read it N times (maybe 10 times) with a delay of say 12 ms between reads and average it for a better result. This works because the PWM period is about 1 mS so delaying for a period of multiple cycles but not an exact multiple means you sample semi randomly.

For the sort of resolution that you want (4 levels) a MUCH smaller capacitor could be used (maybe 1 uF.) But even a 100 uF capacitor is cheap.

You could instead use PWM out (analogWrite) and a digitalRead.
Perform say 100 digital reads with say 12 ms between reads (so about 1.2 seconds total) and keep two counts - PinWasHigh and PinWasLow for (obviously) high or low conditions. The contents of PinWasHigh tells you what % of reads was high. Due to random sampling you cannot rely on this for 100 levels but determining say 10 levels should give good accuracy. The sum of PinWasHigh and PinWasLow should total 100 as a sanity check.

While use of a serial port (hardware or software) or SPI allows more data transfer per time and without much effort, this simple analog method is good enough for many applications.

Russell McMahon
  • 2,421
  • 11
  • 14
5

It is possible, but not the best idea. The analog inputs require a reasonably stable input - this can be achieved with a RC filter to smooth the PWM output. This would work for reasonably slow data rates.

You would be better to use one of the many communication protocols supported by Arduino (serial, SPI, I²C).

Milliways
  • 1,655
  • 2
  • 18
  • 29
4

For greater precision, less code, faster execution and no need for capacitors read the PWM "analog" signal on the other Arduino from a digital input pin with

pulseIn(pin, HIGH, timeout)

The timeout is optional (1 second by default). As soon as the line goes high, a timer engages and automatically stops the instant the line goes low.

The primary reason to use PWM communcation (as opposed to i2c, SPI, etc.) is to broadcast to an unlimited number of devices simultaneously without the need for a clock signal or acknowledgement.

We are currently using this method of communication for neural networks composed of separate tiny processors for each neuron substructure (one processor for each synapse and activation function).

1

Full solution to receive PWM signal and convert to a like analogRead() one. Its based on @Cortex_systems answer and Id like to share it to help others with a more comprehensive answer.

int var = pulseIn(digitalPin, HIGH, 4200);
if (var == 0 && digitalRead(digitalPin) == 1) {
    var = 2100;
}
var= map(var, 0, 2100, 0, 1023);

Here is the why:

  • You can not just read PWM signal to analog pin in arduino. We will receive the PWM in a digital pin with its pinMode set to input and read it with pulsIn(pinNum, high/low, timeout).
  • pulseIn() records the length of the pulse. Longest pulse in PWM is 2100 microseconds.
  • Timeout is set to 4200 for 2 cycles of PWM. Without this it will wait for a new high and freeze the code in cases that PWM is 0 or 255.
  • At max and min this will read 0, so in that case check with digitalRead() to determine and adjust.
  • Finally, map the result so it appears like an analogRead().

Note! This adds a delay of up to 4.2 milliseconds to code.

bets
  • 141
  • 4