How to read ON-OFF-ON switch on a single analog pin

Hello!

I had a panel with some 3 states switches (ON-OFF-ON) and I wanted to spare some input pins.

Here is what I did :slight_smile: if you have the same need!

I soldered two 10kOhm resistors like this

Then the analog value read by the arduino is : around 0 / around 512 / around 1023 depending on the switch’s position.

Here is the code:

void setup() {
     pinMode(A0, INPUT); 
//  pinMode(0, INPUT_PULLUP); // not necessary because I have soldered a pull down resistor
//  https://playground.arduino.cc/CommonTopics/PullUpDownResistor
  
  int sensorReading;
  byte range, switchState;
  
    sensorReading=analogRead(A0);
    range = map(sensorReading,0,1024,0,3);
    switch (range) {
 case 0:  // 0 ohm - switch middle
  switchState=0;
  break;
 case 1:   // 512 ohm - switch up
  switchState=1;
  break;
 case 2:   // 1023 ohm - switch down
  switchState=2;
  break;
    }
}


void loop() 
{ 
//
}

edit : code edited with final correct syntax :slight_smile:

Here is a tutorial for 5 switches on a single pin:

I have a question though

sensorReading=analogRead(A0)+50;
range = map(sensorReading,0,1023,0,2);

without '+50' on the analog value read, it doesn't work... and I would like to understand why, if someone can explain it to me ::slight_smile:

with the combination of map and switch functions, I thought it would be straightforward

like seen in Tutorial 14.5: Switch Case Statement - Programming Electronics Academy

Thanks
Mat

edit : first post modified with the answer

The code looks basically correct, except you'd probably want it in your loop() rather than your setup().

Analog pins are not exact (they're analog after all). So switching the pin to the middle position - and assuming your resistors are perfectly equal, you normally will have 5% tolerance there already - will give you one time 505, the next time 510, and the third time maybe 508. Try another pin and the values may hover around 516, or even 520. That's why you must include a range for your readings to make this work.

The range of 50 (5% of the scale) is not even enough if you have really bad luck and one resistor is at the top end of the tolerance, and the other is at the bottom end. In practice, though, most will be within 2-3% from the nominal value. But just in case one of your settings doesn't work, do have a Serial print of the value read, and see if it happens to be just out of range and amend your ranges (or replace resistors) accordingly.

thanks for your answer!

sorry but tolerance of reading is much higher than the 5% tolerance of resistor with the map/switch function…

1024/3 = 341

  • from 0 to 341 ohm, it goes to 0
  • from 341 to 682 ohm, it goes to 1
  • from 682 to 1024, it goes to 2

In your case you'll be safe.

By the way, the reading from the analog port is normally used dimensionless. It's a number 0-1023, not a resistance. It's actually a representation of the voltage level measured.

By the way, the reading from the analog port is normally used dimensionless. It's a number 0-1023, not a resistance. It's actually a representation of the voltage level measured.

indeed! :-[

do have a Serial print of the value read, and see if it happens to be just out of range and amend your ranges (or replace resistors) accordingly.

back at home, i print to serial

0 511 1023 are the three values read (for both resistor): that's OK

I made some new investigation and I found that:

range = map(sensorReading,0,1023,0,2);

gives :confused:
0 from 0 to 511
1 from 512 to 1022
2 for 1023

range = map(sensorReading,0,1024,0,3);

gives the awaited results
0 from 0 to 341
1 from 341 to 682
2 from 682 to 1023

tadaaa ! it works... and he tutorial linked looks wrong

@wvmarle thanks for your interest!

Mmm... Never used map() myself before, good to know it doesn't work as expected.