2-way switch as digital input

Hello gentlepeople,

I am not entirely new to Arduino’s, have been learning for about half a year now and fiddled with LCD’s, I2C, sensors, voltage dividers, LED-strips, loadcells etc. My first “paid” project is reading a 4-20mA pressure sensor and switching optocouplers according to the measured value. The measurement and optocouplers are working fine.

In the summer, the optocouplers must be switched at different levels than in the winter. I added a two-way switch that tells the Aruino which season it is. With this type of switch (see attached drawing), I thought I was able to eliminate a floating input (in my case D12). The switch is either connecting 5V to the input for a HIGH state or GND to the input for the LOW state. However, the input seems to float. When I measure the input voltage on the D12 pin, it is 5V or 0V as expected, but the Arduino doesn’t digitalread it as such.

My next attempt will be programming D12 as an INPUT_PULLUP and only connecting the GND to one side of the switch. For now, I am just wondering why the described set-up will not work. Many thanks in advance!

How to post an image

There is nothing wrong with what you have done based on the schematic.
There might be something wrong with the code you have not shown us. Please, when you post it use code tags </>
It is also possible that your actual wiring is not as you think it is, maybe a photo of what you have would help us to know.

I suggest you create a simple program that reads D12 every 250ms or so then send ‘High’ or ‘Low’ to the serial monitor to show its status.
Please also read:
General guidance and
How to use this forum

Thanks.

There will be a period of "floating in hyperspace" whilst the switch is passing through its travel. It shouldn't be a problem if you have debouced it in software, but I would go with a decent pullup externally (10K or so) and pull the D12 input to ground via the switch.

Why use a 2 way switch when you can use INPUT_PULLUP as one state and a switch to take the input LOW for the other state ?

(deleted)

I have no idea what a digitalRead() on an output shows....

It returns the state of the pin, HIGH or LOW

A common way to change the state of an output pin is

digitalWrite(pinNumber, !digitalRead(pinNumber));

UKHeliBob:
Why use a 2 way switch when you can use INPUT_PULLUP as one state and a switch to take the input LOW for the other state ?

Because of the millions of megawatts wasted in the resistor... No, I just had that switch laying around already and wanted to try my theory as described above. I will try your suggestion soon!

gose91:
Because of the millions of megawatts wasted in the resistor

And therein lies one of the causes of global warming: The energy wasted in one device can be utterly trivial, but when there are millions and millions of the same device the energy use adds up to something very significant.

AJLElectronics:
There will be a period of “floating in hyperspace” whilst the switch is passing through its travel. It shouldn’t be a problem if you have debouced it in software, but I would go with a decent pullup externally (10K or so) and pull the D12 input to ground via the switch.

The floating during switching doesn’t bother me. It will likely be switched four times a year, so the brief hyperspace will not affect the functioning of the device.

PerryBebbington:
There is nothing wrong with what you have done based on the schematic.
There might be something wrong with the code you have not shown us. Please, when you post it use code tags </>
It is also possible that your actual wiring is not as you think it is, maybe a photo of what you have would help us to know.

I suggest you create a simple program that reads D12 every 250ms or so then send ‘High’ or ‘Low’ to the serial monitor to show its status.
Please also read:
General guidance and
How to use this forum

Thanks.

Thanks for all the startup tips with this forum!

My code is in Dutch, so it’s a bit harder to understand for you. I commented in the code at the relevant points.

#include <LiquidCrystal_I2C.h>

//2x sensor and 1x switch
#define SensorBassinS1 A1
#define SensorSiloS2 A2
#define ZomerstandS3 12                      //<input definition

//9x optocouplers
#define BassinStartBronpompUitK11 2
#define BassinStopBronpompUitK12 3
#define BassinStopInfiltrerenK13 4
#define BassinStartInfiltrerenK14 5
#define SiloMinimumNiveauK21 6
#define SiloStopInfiltrerenK22 7
#define SiloStartInfiltrerenK23 8
#define SiloStartVulpompK24 9
#define SiloStopVulpompK25 10

boolean Zomerstand;                            //<depends on the input
float S1V0 = 180; // 0.88 * (1023/5)
unsigned int S1m3pV = 3100;
float S2V0 = 180; // 0.88 * (1023/5)
unsigned int S2m3pV = 88;
const int BassinGrootteKuub = 3000;
const int SiloGrootteKuub = 22;
const byte SampleGrootte = 40;
float KuubBassin;
float KuubSilo;
int ProcentBassin;
int ProcentSilo;
int DrempelK11;
int DrempelK12;
int DrempelK13;
int DrempelK14;
unsigned int UitlezingS1;
unsigned int UitlezingS2;
char LaatsteDisplay = 'S';

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  pinMode(SensorBassinS1, INPUT);
  pinMode(SensorSiloS2, INPUT);
  pinMode(ZomerstandS3, INPUT);                               //<the pinmode setting
  pinMode(BassinStartBronpompUitK11, OUTPUT);
  pinMode(BassinStopBronpompUitK12, OUTPUT);
  pinMode(BassinStopInfiltrerenK13, OUTPUT);
  pinMode(BassinStartInfiltrerenK14, OUTPUT);
  pinMode(SiloMinimumNiveauK21, OUTPUT);
  pinMode(SiloStopInfiltrerenK22, OUTPUT);
  pinMode(SiloStartInfiltrerenK23, OUTPUT);
  pinMode(SiloStartVulpompK24, OUTPUT);
  pinMode(SiloStopVulpompK25, OUTPUT);

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("NIVEAUPROCESSOR");
  lcd.setCursor(0, 1);
  lcd.print("START METING...");
}

void loop() {
  Meting();
  RelaisAansturen();

//Shows both tanks alternatingly
  if (LaatsteDisplay == 'B') {
    DisplaySilo();
    LaatsteDisplay = 'S';
  }
  else {
    DisplayBassin();
    LaatsteDisplay = 'B';
  }
}

void Meting() {

  UitlezingS1 = 0;
  UitlezingS2 = 0;

//takes amount of samples from each input sensor
  for (byte i = 0; i < SampleGrootte; i++) {
    UitlezingS1 += analogRead(SensorBassinS1);
    UitlezingS2 += analogRead(SensorSiloS2);
    delay(100);
  }
//determines avarage and calculates real life value
  UitlezingS1 /= SampleGrootte;
  KuubBassin = map((UitlezingS1 - S1V0), 180, 215, 0, 3320);
  ProcentBassin = ( KuubBassin / BassinGrootteKuub ) * 100;

  UitlezingS2 /= SampleGrootte;
  KuubSilo = map((UitlezingS2 - S2V0), 180, 185, 0, 22);
  ProcentSilo = ( KuubSilo / SiloGrootteKuub ) * 100;
}

void DisplayBassin() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("BASSIN");
  lcd.print(UitlezingS1); //printed for debugging

  if (Zomerstand) {                                             //<Zomerstand is defined further below
    lcd.print('Z'); //printed for debugging
  }
  lcd.setCursor(0, 1);
  if (UitlezingS1 < S1V0) {
    lcd.print("FOUT SENSOR");
  }
  else {
    lcd.print((int)KuubBassin);
    lcd.print("m3 / ");
    lcd.print(ProcentBassin);
    lcd.print("% ");
  }
}

void DisplaySilo() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("ZANDSILO");
  lcd.print(UitlezingS2);//printed for debugging
  if (Zomerstand) {                                            //<Zomerstand is defined further below
    lcd.print('Z');//printed for debugging
  }
  lcd.setCursor(0, 1);
  if (UitlezingS2 < S2V0) {
    lcd.print("FOUT SENSOR");
  }
  else {
    lcd.print((int)KuubSilo);
    lcd.print("m3 / ");
    lcd.print(ProcentSilo);
    lcd.print("% ");
  }
}

void RelaisAansturen() {

//Determines which thresholds to use for K11-K14
  if (digitalRead(ZomerstandS3) == HIGH) {         //<digitalRead of the input
    DrempelK11 = 45;
    DrempelK12 = 55;
    DrempelK13 = 65;
    DrempelK14 = 70;
    Zomerstand = true;                                        //<setting the Zomerstand variable
  }
  else {
    DrempelK11 = 40;
    DrempelK12 = 45;
    DrempelK13 = 50;
    DrempelK14 = 55;
    Zomerstand = false;                                        //<setting the Zomerstand variable
  }

  //Aansturen optocouplers
  if (ProcentBassin > DrempelK11) {
    digitalWrite(BassinStartBronpompUitK11, HIGH);
  }
  else {
    digitalWrite(BassinStartBronpompUitK11, LOW);
  }

  if (ProcentBassin > DrempelK12) {
    digitalWrite(BassinStopBronpompUitK12, HIGH);
  }
  else {
    digitalWrite(BassinStopBronpompUitK12, LOW);
  }

  if (ProcentBassin > DrempelK13) {
    digitalWrite(BassinStopInfiltrerenK13, HIGH);
  }
  else {
    digitalWrite(BassinStopInfiltrerenK13, LOW);
  }

  if (ProcentBassin > DrempelK14) {
    digitalWrite(BassinStartInfiltrerenK14, HIGH);
  }
  else {
    digitalWrite(BassinStartInfiltrerenK14, LOW);
  }

  //Aansturing optocouplers zandsilo
  if (ProcentSilo > 10) {
    digitalWrite(SiloMinimumNiveauK21, HIGH);
  }
  else {
    digitalWrite(SiloMinimumNiveauK21, LOW);
  }

  if (ProcentSilo > 60) {
    digitalWrite(SiloStopInfiltrerenK22, HIGH);
  }
  else {
    digitalWrite(SiloStopInfiltrerenK22, LOW);
  }

  if (ProcentSilo > 70) {
    digitalWrite(SiloStartInfiltrerenK23, HIGH);
  }
  else {
    digitalWrite(SiloStartInfiltrerenK23, LOW);
  }

  if (ProcentSilo > 80) {
    digitalWrite(SiloStartVulpompK24, HIGH);
  }
  else {
    digitalWrite(SiloStartVulpompK24, LOW);
  }

  if (ProcentSilo > 90) {
    digitalWrite(SiloStopVulpompK25, HIGH);
  }
  else {
    digitalWrite(SiloStopVulpompK25, LOW);
  }
}

gose91:
The floating during switching doesn't bother me. It will likely be switched four times a year, so the brief hyperspace will not affect the functioning of the device.

But during the transition, the D12 pin is floating. The Arduino will not know what to make of it, so it needs to have a pullup regardless.

(deleted)

AJLElectronics:
But during the transition, the D12 pin is floating. The Arduino will not know what to make of it, so it needs to have a pullup regardless.

So the "during transition floating" does affect the readings after the transition? Even if the input is connected to 5V or GND after the transistion?

smarts-jb:
What model ARduino is it? If I recall, some have "D12" on the screening but that's not the same as 12.

Nano v3.0

AJLElectronics:
But during the transition, the D12 pin is floating. The Arduino will not know what to make of it, so it needs to have a pullup regardless.

Hi Andy,
I don't think, given what the OP is trying to do, that this will be a problem. The time the input is floating is tiny and it will still read high or low in the transition, and on the next read the switch will most likely have settled. I don't know what the problem is, but I don't think this is it.

I agree with smarts-jb, you need to test the input only and work from there. I can't follow your code partly because of the language difficulty, partly because it is more complicated than it needs to be to resolve this problem but mostly because I am rubbish at following other people's code.

PerryBebbington:
Hi Andy,
I don't think, given what the OP is trying to do, that this will be a problem. The time the input is floating is tiny and it will still read high or low in the transition, and on the next read the switch will most likely have settled. I don't know what the problem is, but I don't think this is it.

Fairy Snuff, after the switch has settled it's true, (or FALSE!).

I can bring the code down to this if that helps. All other functions are not related or do just depend on the correct functioning of this code.

#define ZomerstandS3 12                      //<input definition
boolean Zomerstand;                            //<depends on the input

void setup() {
  pinMode(ZomerstandS3, INPUT);                               //<the pinmode setting

void loop() {
  if (Zomerstand) {                                             //<Zomerstand is defined further below
    lcd.print('Z');            
  }

  if (digitalRead(ZomerstandS3) == HIGH) {         //<digitalRead of the input
    Zomerstand = true;                                        //<setting the Zomerstand variable
  }
  else {
    Zomerstand = false;                                        //<setting the Zomerstand variable
  }
}

Maybe this helps, combined with the setup.

(deleted)

It always checks both ifs in the loop. The first if prints a 'Z' on the LCD if Zomerstand is true, the second one sets Zomerstand depending on the digitalRead of input 12. For a correct handling of Zomerstand, it is indeed better to define it first before another if looks at the value of Zomerstand. But after the first time the loop is completed, Zomerstand has always a value. (but setting that value is of course my problem now...)
I will try your suggestion of only the pin readout on the LCD and will post the code and results here!

gose91:
It always checks both ifs in the loop. The first if prints a ‘Z’ on the LCD if Zomerstand is true, the second one sets Zomerstand depending on the digitalRead of input 12. For a correct handling of Zomerstand, it is indeed better to define it first before another if looks at the value of Zomerstand. But after the first time the loop is completed, Zomerstand has always a value.
I will try your suggestion of only the pin readout on the LCD and will post the code and results here!

Correct, but you need an else after

  if (Zomerstand) {                                             //<Zomerstand is defined further below
    lcd.print('Z');           
  }

to print something different if Zomerstand is not true, so that you definitely get something printed whether the input is high or low, so you can be certain.
[EDIT]
Or just forget the if() and just print the value of Zomerstand.