Holding hands and connecting points: voltage too low?

I am trying to determine whether two or more analog input/outputs by holding hands are connected to each other by looping through them (on Arduino UNO). The problem seems to be that the voltage is too low.

For this setup, would an op-amp work to drive up the voltage range? As the analog pins are both in- and outputs, I’m not sure if this will work.

It works perfectly when I connect the wires, although I still get ~550, while you’d think it shouldn’t have any resistance so should be 0.

First I set the first five analog inputs to be an input, and write a high voltage to them.

Then, every loop:

  1. Set A0 as an output and drive it low voltage
  2. See which other pins are now low voltage – they are connected to A0
  3. Return A0 to be an input.
  4. Set A1 as an output and drive it low voltage
  5. See which other pins are now low voltage – they are connected to A1

    When A4 has been reached, repeat.

Thanks in advance!

static const uint8_t analog_pins[] = {A0,A1,A2,A3,A4};

void setup() {
  Serial.begin(9600);
  
  for (int thisPin = 0; thisPin < 5; thisPin++) {
  pinMode(analog_pins[thisPin], INPUT);
  analogWrite(analog_pins[thisPin], 1023);
  }
  Serial.println("starting up!");

}

void loop() {
  
  for (int thisPin = 0; thisPin < 5; thisPin++) {
  pinMode(analog_pins[thisPin], OUTPUT);
  analogWrite(analog_pins[thisPin], 0);
  delay(200);
  
    for (int checkPin = 0; checkPin < 5; checkPin++) {
      
      if (checkPin != thisPin) {
        int curCheck = analogRead(analog_pins[checkPin]);
        Serial.println(curCheck);
        
        if (curCheck < 900) {
          Serial.print("PINS CONNECTED: ");
          Serial.print(thisPin);
          Serial.print("&");
          Serial.println(checkPin);
          }
          
        }
        
      }
      delay(200); // delay per pin check

      pinMode(analog_pins[thisPin], INPUT);
      analogWrite(analog_pins[thisPin], 1023);
      
      Serial.println("...");
    }

  Serial.println("===");
  delay(2000); // delay between rounds
}

Hi,

Think you need to have a pin as Output before you can do analogWrite. But if you just want to set the pin high, just do digitalWrite(Pin.HIGH);

THEN you can change it back to input.

The small capacitance will keep it 'near high' for a short time.

Maybe you need to do this action within the loop..

I believe the analogWrite() function calls pinMode() internally to set the pin to the analog output mode, so all pins except the analogRead() pin and the pin set output low are driving high. Generally one doesn't want multiple sources driving a single net.

Also the range for analogWrite() is 0-255, not 0-1023.

I believe the analogWrite() function calls pinMode() internally to set the pin to the analog output mode

Can someone test this? The Reference shows a pinMode(pin,OUTPUT) before the analogWrite.

Original Poster: Please tell us exactly how you want this to work!

MrMark:
I believe the analogWrite() function calls pinMode() internally to set the pin to the analog output mode, so all pins except the analogRead() pin and the pin set output low are driving high. Generally one doesn't want multiple sources driving a single net.

Also the range for analogWrite() is 0-255, not 0-1023.

Pretty sure it does indeed internally call pinMode().
And you're right about the analogWrite() range, indeed! :slight_smile:

But to get back to my question at hand:

For this setup, would an op-amp work to drive up the voltage range? As the analog pins are both in- and outputs, I'm not sure if this will work.

terryking228:
Original Poster: Please tell us exactly how you want this to work!

I would like to be able to touch the leads coming from A0 and A4 for example, and this would read as a connection.
The above code does work fine when I directly connect the wires, but the voltage is too small to travel through the human body and still register on the analog pin.

I would like to be able to touch a lead coming from A0 and A4 for example, and this would read as a connection.

OH. THat's different. That is a "Capacitive Touch Switch"..

LOT of info HERE:

terryking228:
Can someone test this? The Reference shows a pinMode(pin,OUTPUT) before the analogWrite.

No need to test it, the source code has the definitive answer:

Do note however, that analogRead doesn't set the pin to input again.

Pieter

terryking228:
Can someone test this? The Reference shows a pinMode(pin,OUTPUT) before the analogWrite.

Terry, I'm looking at line 111 here:

terryking228:
OH. THat's different. That is a "Capacitive Touch Switch"..

LOT of info HERE:

No, that's not what I mean. Sorry for not being clear.
I mean when the leads touch. So when A0 touches A4 for example.
But then with humans in between, carrying the signal.

EXPLANATORY PICTURE LINK

The problem is the incoming signal is too low to be registered by the arduino.
I'm aware I could use a non-inverting op-amp, but I'm not sure if this will work as all the analog ports are interchangeably being used as input and output.

I hope it's clear now.

maaark:
The problem is the incoming signal is too low to be registered by the arduino.

Perhaps, but I'm not entirely convinced this is the primary issue.

The way I would test this is to configure an Arduino analog input pin with a 1M Ohm pullup and program it to loop on analogRead of that pin and print to the serial monitor (or the IDE graph). Observe the values read when the pin is left open (it should be at or close to 1023) and when you are touching Arduino ground and the analogInput pin simultaneously.

My expectation is that you'll see the value dip when you are in the circuit and you'll probably see power line noise (50 or 60 Hz or some aliased version depending on sample rate) superimposed on that. If the power line noise is high enough you might have to do some filtering.

It works perfectly when I connect the wires, although I still get ~550, while you'd think it shouldn't have any resistance so should be 0.

It doesn't make sense to connect two inputs together.
If the other end of the wire is connected to +5V (or an output pin writing high) you should read (about) 1023. If the other end is connected to ground (or an output pin writing low) you should read (about) zero.

With the other end of the wire unconnected (or connected to another input) the input is "floating" and undefined. It can read anything but in my (limited) experiments it seems to read somewhere in the middle. Then, depending on the length of the wire and the environment you will pick-up some electro-magnetic noise which will make the readings jump around.

For this setup, would an op-amp work to drive up the voltage range? As the analog pins are both in- and outputs, I'm not sure if this will work.

An op-amp probably won't help.

The above code does work fine when I directly connect the wires, but the voltage is too small to travel through the human body and still register on the analog pin.

Your body has resistance that varies a lot. If you are holding onto big metal handles or if your hands are wet you'll get "better contact" and lower resistance. The Arduino has even higher resistance so the resistance of your body probably isn't a problem. But again, the other hand needs to touch +5V or ground.

A bigger problem is that your body acts as an antenna and it picks-up electromagnetic noise from the environment. The noise may be bad enough to make your readings useless. The high impedance of the Arduino's input in combination of the high impedance of your body makes it very-sensitive to noise* and you can pick-up 1V or more of noise. (If you've ever touched an audio input and heard a "buzz", that's your body picking-up electromagnetic radiation from the AC power lines all around you.)

  • The noise has very-little energy , so you can't get much current (or power) from your body. With a lower-impedance input (such as a pull-down-or pull-up resistor) or low impedance source, the voltage drops (Ohm's Law) and the noise is lowered. But, that lower input resistance will "overpower" the resistance of your body so your setup won't work if the pull-up or pull-down resistor value is too low (and there may not be a compromise that works).

All these questions tell me you have not even tested your theory using an Ohmmeter.

Paul

DVDdoug:
It doesn't make sense to connect two inputs together.
If the other end of the wire is connected to +5V (or an output pin writing high) you should read (about) 1023. If the other end is connected to ground (or an output pin writing low) you should read (about) zero.

With the other end of the wire unconnected (or connected to another input) the input is "floating" and undefined. It can read anything but in my (limited) experiments it seems to read somewhere in the middle. Then, depending on the length of the wire and the environment you will pick-up some electro-magnetic noise which will make the readings jump around.
An op-amp probably won't help.

Your body has resistance that varies a lot. If you are holding onto big metal handles or if your hands are wet you'll get "better contact" and lower resistance. The Arduino has even higher resistance so the resistance of your body probably isn't a problem. But again, the other hand needs to touch +5V or ground.

A bigger problem is that your body acts as an antenna and it picks-up electromagnetic noise from the environment. The noise may be bad enough to make your readings useless. The high impedance of the Arduino's input in combination of the high impedance of your body makes it very-sensitive to noise* and you can pick-up 1V or more of noise. (If you've ever touched an audio input and heard a "buzz", that's your body picking-up electromagnetic radiation from the AC power lines all around you.)

  • The noise has very-little energy , so you can't get much current (or power) from your body. With a lower-impedance input (such as a pull-down-or pull-up resistor) or low impedance source, the voltage drops (Ohm's Law) and the noise is lowered. But, that lower input resistance will "overpower" the resistance of your body so your setup won't work if the pull-up or pull-down resistor value is too low (and there may not be a compromise that works).

Hi DVDoug, thanks so much for your insightful post and explanations!
If you look at my code, you can see that the analog pins are being used interchangeably as in- and outputs. The way I do this is explained in the first post. This does work!, just not with the body in between.

I realise now I should have just asked how to make contact through the body, instead of confusing it with my code and way of connecting different input pins to each other.

Paul_KD7HB:
All these questions tell me you have not even tested your theory using an Ohmmeter.

Paul

Thanks Paul. I have actually tried this, and totally realise it is hard, but I also have seen it working, for example in Erwin Stache's installations: 87,3 Kilo Ohm von Erwin Stache - YouTube
Because of this I am certain that it could work... I am just looking for the right way in! :slight_smile:

EDIT after trying just connecting an analog pin and putting my body in between it and the ground I can say that that signal is way different than the one I get connecting two analog pins to each other (having one HIGH and one LOW) as I do in my code (see original post). This leads me to believe connecting an input pin to ground is NOT the same as connecting an input pin to an output pin writing LOW.
Why is this?

EDIT2 Did some more tests of directly setting pin A0 to INPUT_PULLUP, and A1 to OUTPUT with a value of 255. This DOES work almost the same as connecting to ground. It goes back to 15/1023 instead of 0/1023 when connecting the pins (could be because of the proximity).
Then, to return to my original post, why does it not work when I switch analog pins from input to output, et cetera?

I set up a test similar to what I described in post #9, that is a 1M Ohm pullup on A0 pin and A5 alternating between input mode and a digital “0” (gnd).

I’m seeing thefollowing (“hands on” means fingers touching A5 and A0 pins):

  1. No “hands on” - clean analog full scale on A0

  2. A5 as input with “hands on” - noisy analog full scale on A0

  3. A5 as output low with “hands on” - less noisy analog less than full scale on A0. For this case value is much lower if skin is moistened.

Screenshot_2019-01-25_09-23-48.png

Code for experiment:

#define loops 100

void setup() {
  Serial.begin(115200);
}

void loop() {
  pinMode(A5, INPUT) ;
  for (int k = 0; k < loops; k++) {
    int sensorValue = analogRead(A0);
    Serial.println(sensorValue);
    delay(10);        // delay in between reads for stability
  }
  pinMode(A5, OUTPUT) ;
  digitalWrite(A5, 0) ;
  for (int k = 0; k < loops; k++) {
    int sensorValue = analogRead(A0);
    Serial.println(sensorValue);
    delay(10);        // delay in between reads for stability
  }
}

A small cap parallel to the resistor should do wonders for the noise (1-10 nF or so). Just keep in mind the 1-10 ms RC time constant you get, slowing down the reaction.

MrMark:
I set up a test similar to what I described in post #9, that is a 1M Ohm pullup on A0 pin and A5 alternating between input mode and a digital “0” (gnd).

I’m seeing thefollowing (“hands on” means fingers touching A5 and A0 pins):

  1. No “hands on” - clean analog full scale on A0

  2. A5 as input with “hands on” - noisy analog full scale on A0

  3. A5 as output low with “hands on” - less noisy analog less than full scale on A0. For this case value is much lower if skin is moistened.

Screenshot_2019-01-25_09-23-48.png

Code for experiment:

#define loops 100

void setup() {
  Serial.begin(115200);
}

void loop() {
  pinMode(A5, INPUT) ;
  for (int k = 0; k < loops; k++) {
    int sensorValue = analogRead(A0);
    Serial.println(sensorValue);
    delay(10);        // delay in between reads for stability
  }
  pinMode(A5, OUTPUT) ;
  digitalWrite(A5, 0) ;
  for (int k = 0; k < loops; k++) {
    int sensorValue = analogRead(A0);
    Serial.println(sensorValue);
    delay(10);        // delay in between reads for stability
  }
}

Thank you so, so much. This gives me a lot of hope that this is indeed possible.
I’m working on getting this in order to recognise all possible combinations (A0 /w A1, A0 /w A2 … A4 /w A5 etc).
For some reason that did not work with my original code. I will refactor it and post later.

wvmarle:
A small cap parallel to the resistor should do wonders for the noise (1-10 nF or so). Just keep in mind the 1-10 ms RC time constant you get, slowing down the reaction.

Thanks for the suggestion! I’ll try it tomorrow! :slight_smile:

@MrMark & @wvmarle, I want to thank you!

I managed to get it to work: the code sample in combination with the tip to use a capacitor (100pf) & resistor (0.5Mohm) to ground on each input, in parallel, worked brilliantly!! :slight_smile:

I’m able to get a reading for every connection between each analog pin now (for example, A0 & A3, A2 & A4, A1 & A2, etc etc).

Here’s the code that reads the first five analog pins and prints when there’s a connection and what the connection is!

#define loops 10
static const uint8_t analog_pins[] = {A0,A1,A2,A3,A4,A5};
int delayTime = 2;
int thisPin = 0;
int checkPin = 0;
int sensorValue = 0;
int maxPin = 4;

void setup() {
  Serial.begin(115200);
  
  
}

void loop() { 
  if(thisPin > maxPin) {
    thisPin = 0;
  }
  
  pinMode(analog_pins[thisPin], INPUT_PULLUP);

  for (int x = thisPin; x < maxPin; x++) {
    for (int k = 0; k < loops; k++) {
      
      checkPin = x + 1;
      sensorValue = analogRead(analog_pins[checkPin]);

      if(sensorValue > 350) {
        Serial.print("CONNECTION ");
        Serial.print(thisPin);
        Serial.print(" & ");
        Serial.println(checkPin);
    }
    
      delay(delayTime);        // delay in between reads for stability
    }

  }
  
  digitalWrite(analog_pins[thisPin], 0) ;
  
  for (int k = 0; k < loops; k++) {
    delay(delayTime);        // delay in between reads for stability
  }

  thisPin++;
}

Yay! :slight_smile:

maaark:
I managed to get it to work: the code sample in combination with the tip to use a capacitor (100pf) & resistor (0.5Mohm) to ground on each input, in parallel, worked brilliantly!! :slight_smile:

That’s very small a capacitor.

  for (int k = 0; k < loops; k++) {

delay(delayTime);        // delay in between reads for stability
  }

Well done, but this is a very roundabout way of doing:

delay(delayTime * loops);

And do have a look at the Blink without Delay example, so you can get rid of those delay() calls and do something useful in that time. Or simply react faster.

wvmarle:
That's very small a capacitor.

Well done, but this is a very roundabout way of doing:

delay(delayTime * loops);

And do have a look at the Blink without Delay example, so you can get rid of those delay() calls and do something useful in that time. Or simply react faster.

Thanks! I'll try. The delay was there in MrMark's original example, and I thought it was there to make the serial printing more stable. I'll look into doing it with timers as in the Blink without Delay example :slight_smile: