4 position slider switch breaks code on the last position

I have managed to make a 3 position slider switch work although haven't managed with a 4 position one.

So far a 3 position slider switch is on-off-on. While a 4 on-off-on-on
Ground on common pin 3 of the switch

POS1 POS2 POS3 POS4
1-3 1-3-2 2-3 2-3-4 3-4 4-3-5 3-5

Any help is welcome. So far...

//4 Position Slider
Button butt {0}; //Slider 1st position
Button butt2 {1}; //Slider 3rd Position
Button butt3 {2}; //Slider 4th Position
//Position 2 connected to ground (first_subgroup)

//POS1 and POS2
if (butt.update()) { 
    if (butt.getState() == Button::Released) { 
          } else if (butt.getState() == Button::Falling) { 
      Bankable::PBPotentiometer::enable(second_subgroup);
      Bankable::PBPotentiometer::disable(first_subgroup);
    } else {
      Bankable::PBPotentiometer::disable(second_subgroup);
      Bankable::PBPotentiometer::enable(first_subgroup);
    }
  } 

//Up to here ^^^ everything works for positions 1 and 2. Back and forth

//POS2 and POS3
if (butt2.update()) {
    if (butt2.getState() == Button::Released) {
    } else if (butt2.getState() == Button::Falling) {
      Bankable::PBPotentiometer::disable(first_subgroup); 
      Bankable::PBPotentiometer::enable(third_subgroup);
    }else{
      Bankable::PBPotentiometer::disable(third_subgroup);
      Bankable::PBPotentiometer::enable(first_subgroup);
      }
    }

//Up to here ^^^ everything works for positions 2 and 3. Back and forth

//Between position POS3 and POS4 but Position 2 and 4 is how is works as the base is first_subgroup
      if (butt.update() && butt2.update() && butt3.update()){ //if I don't add butt && butt1 && butt2 it breaks the code when switching to position 4. Now I can go to position 4 and continue with the program but not back to the other programs
        if (butt3.getState() == Button::Released){
          }
         else if (butt3.getState() == Button::Falling) { 
          Bankable::PBPotentiometer::enable(fourth_subgroup);
          Bankable::PBPotentiometer::disable(first_subgroup);

//IT WORKS UP TO HERE. I CAN'T GO BACK TO POSITION 3 OR 2 OR 1 WITHOUT BREAKING THE CODE OR REBOOTING ARDUINO        

} else { 

     Bankable::PBPotentiometer::disable(fourth_subgroup);
     Bankable::PBPotentiometer::enable(first_subgroup);
          }
}

I even thought of making a return; to start from scratch whenever I change position as if I restart the Arduino in the right position everything works but while it's broken the only way is pressing the reset button which isn't something I want to do every time

1 Like

I'm having trouble visualising your switch.
It appears to have 7 discrete postions

a 1-3
b 1-3-2
c 2-3
d 2-3-4
e 3-4
f 4-3-5
g 3-5

I guess I'd simply try to determine from the contacts which position the switch is in and act accordingly.

Assuming contact 3 (common) is low and the rest are pulled high with a pullup resistor and read with a digitalRead() :

if ( !contact1 && contact2  && contact4 && contact5 )  {
   // only contact 1  LOW  (position a )
}
else if ( !contact1 && !contact2  && contact4 && contact5 )  {
   // only contact 1  and contact 2 LOW  (position b )
}
etc.

It actually has 4 selectable position. The graph shows how the ground is shared between them too.

The problem I am having is that the first 3 positions work perfectly but the last one I can only get in and not out of it.
At first I tried creating the variable within the loop.
Now I created a void Function(); containing everything which is called in the loop see if this could solve it but nothing yet.

Is there any other way to do this? Case?

I’m still very new at this

Please draw the graph again using dots so the spacing doesn’t mess up.

You listed seven combinations and four positions.

We get that above means position 1 shorts 1 and 3, which already is off the rails.

Post a complete compiles and runs example sketch that exercises the switch and show how you’ve wired it and a picture of the switch would not hurt. At all.

a7

Button::update() returns the new state, so this actually checks if (butt.update() != Button::Pressed), which might not be what you expected (and if it is, I would advise you to make that explicit).

Keep in mind that the enable() and disable() functions are not idempotent: if you call enable() on an object that's already enabled, you get a runtime error.

I think you should combine the logic: read the inputs to determine what position the switch is in, and then use that position to enable()/disable() the corresponding potentiometers. In other words, don't take action based on the individual states of the three inputs, but based on the overall position of the switch. You don't know what transitions you'll get on the individual pins, especially in the presence of contact bounce, so you might end up in an inconsistent state and enable()/disable() the same object twice.

byte getPosition (){
  byte x =0;
  if (!digitalRead (but1))x|=(1 <<0);
  if (!digitalRead (but2))x|=(1 <<1);
  if (!digitalRead (but3))x|=(1 <<2);
  if (!digitalRead (but4))x|=(1 <<3);
return (x);
}
static byte Pos = getPosition();
if (Pos == 1) {...}
if (Pos == 2) {...}
if (Pos== 4) {...}
if (Pos == 8) {...}

All 4 pins should be INPUT_PULLUP

guessing that a contact could ground multiple positions. does the code need to verify that only a single contact is grounded?

some multiple pole switches, slides in particular, do that for valid switch positions.

If you meant accidentally or during transitions.

a7

don't understand the OPs logic, why there appears to be unique code for each button/position and why the logic isn't more generic -- ignoring transitions and recognizing stable contact at one position.

since it's a slide switch, do momentary contacts with in between buttons need to be ignored by effectively have a much longer debounce period, ~100 msec?

@gcjr has turned on the lamp for me.

It's just weird numbering. Or typos. :expressionless:

a7

POS.A……....….....POS.B….........……..POS.C……............… .POS.D
1-3………..1-3-2……..2-3……..2-3-4………4-3…..……4-3-5………..5-3

So.

The debouncing shouldn't need any more juice, just reject multiple simultaneous contacts.

a7

USsNX~2-1

So what was the question? :wink:

a7

not what i was suggesting.
if you want to go from 1 to 4, should the code ignore 2 & 3 while they momentarily make contact?

Or take the highest numbered contact:

void setup()
{
  pinMode(Terminal2Pin, INPUT_PULLUP);
  pinMode(Terminal4Pin, INPUT_PULLUP);
  pinMode(Terminal5Pin, INPUT_PULLUP);
}

int SwitchPosition()
{
  if (digitalRead(Terminal5Pin) == LOW)
    return 4;

  if (digitalRead(Terminal4Pin) == LOW)
    return 3;

  if (digitalRead(Terminal2Pin) == LOW)
    return 2;
    
  return 1;
}

image

It looks good but I still can't match it up with the OP's description because only 2 contacts can be joined together at any one time. How would 1-3-2 be represented ?

edit the picture changed as I was copying it !

OIC, good point.

But it should be addressed at a higher level. Upping the debounce constant for the typical wait-until lazy debouncing woukd get irritating, and probably not solve it to anyone’s satisfaction.

Either it would have to be really slow for my moms, or make “mistakes”, either of which shoukd be dealt with outside the low level handling.

In real life, such switches do momentarily invoke the in between behaviour, however briefly. Software can deal.

a7

It's a "Make Before Break" switch. The contact connects 2 to 3 before it disconnects 1 from 3. In the picture, the slider contacts would be slightly wider than the space between stationary contacts.

As @alto777 suggested, just pick the most recent contact being closed…

The button class isn’t really the right tool for the job, as it’s intended for momentary contact push buttons,,while the slider is simply the.equivalent of 4 toggle switches interlinked.

Some are break-before, and a few are make-before.

Oh yes. It is obvious to me now. I guess it was just me being slow.

2 Likes