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.

6

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.

  • Great answer, I eventually went with the no-component solution that you gave towards the bottom of you answer – Hoytman Apr 14 '15 at 16:40
  • 1
    @Hoytman I avoided mentioning a similar solution that takes slightly more coding knowledge but is faster to read. The Arduino PWM takes ABOUT 1 mS per cycle. If you dave the value of micros() when it goes high and compare it with the value when it goes low again you get the APPROXIMATE high time in microseconds. You can do the same thing for low time. The two should add to ~= the PWM period. Once you are confident in the ability to read the high pulse duration and have a feel for the variations to expect you can read the PM % high in maybe 2 mS. – Russell McMahon Apr 14 '15 at 16:50
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).

  • The best choice would be to use SPI, as it is the fastest communication method. Instead, the easiest to use (at least from what I learnt) is I2C – Stefa168 Apr 12 '15 at 22:24
  • 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 Apr 12 '15 at 23:57
  • 3
    @Hoytman, then why don't you send a 1 second pulse for yes, and a 10 second pulse for no? Just pull (at least once per second), and count how long it is before it goes back down? – AMADANON Inc. Apr 13 '15 at 1:38
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).

  • Indeed, this is quite a bit better than the filter methods, if the processor can be available to take the measurement then. If not, some better use of hardware timers and interrupts should handle it. But all of these schemes are generally inferrior to place-value-coded communication channels like asynchronous serial, I2S, SPI, etc. – Chris Stratton Aug 15 '16 at 13:30
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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