Rotary Switch to change Arduino Scripts

HI. Complete newbie here - about 7 days playing with the kit. I’m needing some help scripting an IF statement to allow me to use a rotary switch to change between sections of code. I’ve just figured out how shift registers work so now have a couple of rows of LEDS’s I can light up and off in different patterns etc. All good so far I think.

I’m keen to create very specific lighting sequences/timing in the code and have invested in a rotary switch to change between each sequence. That’s where I’m struggling to write the code as nearly all the google resources I can find related to rotary encoders. This is definitely an analog rotary switch - basically 1 pole and 3 position.

I’ve created a resistor ladder around the pins using 2 x 1K resistors, have 5v going in on position 1 and ground out on position 3 and the ’ analog’ sensor input lead on the common. I get 0 resistance at position 1, 998 at position 2 and 1.998 at position 3 so the switch and resistors appear to be working.

From googling I believe i can use the resistance readings and an Analog input pin to tell arduino which piece of the script to run. I have attached my script for running the 2 shift registers as well as the additional ( what I think I need - Second and Third swithc positions ) script for the extra LED patterns. It’s how to tie these and the switch together that’s causing me pain. Thanks for any advice or indeed free bit of script to 'borrow…

Ged

int dataPin = 2;        //Define which pins will be used for the Shift Register control
int latchPin = 3;
int clockPin = 4;

int seq[16] = {128,64,32,16,8,4,2,1,128,64,32,16,8,4,2,1};       
int seq2[16]= {128,1,128,1,128,1,128,1,128,1,128,1,128,1,128,1};

void setup()
{
    pinMode(dataPin, OUTPUT);       //Configure each IO Pin
    pinMode(latchPin, OUTPUT);
    pinMode(clockPin, OUTPUT);
}

void loop()
{
    for (int n = 0; n <16; n++)
    {
        digitalWrite(latchPin, LOW);             //Pull latch LOW to start sending data
        shiftOut(dataPin, clockPin, LSBFIRST, seq[n]);         //Send the data
        shiftOut(dataPin, clockPin, LSBFIRST, seq2[n]); 
        digitalWrite(latchPin, HIGH);            //Pull latch HIGH to stop sending data
        delay(200);
    }
}

//Void Second Switch Position


// int seq3[8]={1,2,4,8,1,2,4,8}
// int seq4[8]=[2,8,2,8,2,8,2,8}

for (int n = 0; n <8; n++)
    {
        digitalWrite(latchPin, LOW);             //Pull latch LOW to start sending data
        shiftOut(dataPin, clockPin, LSBFIRST, seq[n]);         //Send the data
        shiftOut(dataPin, clockPin, LSBFIRST, seq2[n]); 
        digitalWrite(latchPin, HIGH);            //Pull latch HIGH to stop sending data
        delay(200);
        
        
// Void Third Switch Position 

// Void Fourth Switch Position etc etc

This is definitely an analog rotary switch - basically 1 pole and 3 position.

If it has three positions it is definitely not an analogue device.

please use code tags when posting code.

Sorry. You are correct. I was kind of thinking of it as a stepped/ fixed position potentiometer.

As a first step read the analogue input from the switch into a variable and print it. Now, armed with the value at the 3 different positions (actually you only need the value for the centre position as the 2 ends can be at 0V and 5V) you can construct a series of if statements to test the value and execute the appropriate code for the switch position.

Note, however, that due to the use of the delay() function in your light sequences, changing the switch position will not immediately make the light sequence change to the newly selected one as the current sequence must end before the switch position is read again. There are ways round this but get the basic version working first.

Gedc:
From googling I believe i can use the resistance readings and an Analog input pin to tell…

yes, you can do what you want.

Set the switch to output to an analog pin.

use a simple sketch to return the values it creates on the pin:

int switchPin = 0; // or whatever analog pin you are on

void setup()
{
  Serial.begin(9600);
}
void loop()
{
  Serial.print(analogRead(switchPin));
  delay(500);
}

then in your sketch, trap the output values within ranges (they may vary).

it may be a lot easier for you to just let your switch output to three digital pins, FYI.

Ok. So got there in the end I think. Tried using the digital pins as well, and setting them to inputs so I didn’t need the external resistors but managed to short the board so will need to read a bit more on that. Having removed the resistors and using internal pull ups I can see a straight +5v to Ground in my wiring so no surprises the board shorted. Back to getting it to work through Analog input first…

Through following your advice I was reading 0 on pin 3, 510/ 511 on Pin 2 and 1023 on Pin 1. I then coded the following to display the switch inputs through the serial monitor. All seems to work so far and the change appears onscreen as soon as I turn the switch. I’m presuming it’s easy enough to swap out the serial.print command with some other scripts that control the LED lighting sequence. Can the more smarter folks i.e currently most people on here other than me, look over the script and see if there are possible issues or indeed tidy it up from the clunky workings. Thanks again for your help.

const int analogPin = A0;

void setup()

{Serial.begin(9600);}

void loop() {
  
// read the value of the Switch:
int analogValue = analogRead(analogPin);

// IF/Else statements regarding Values through switch
  if (analogValue >=0 && analogValue <505)
  {Serial.println("Rotary Position 3");}
  
else 

if (analogValue >=506 && analogValue <=1020)
{Serial.println ("Rotary Position 2");}

else

if (analogValue >=1021&& analogValue<=1025) 
{Serial.println ("Rotary Position 1"); }

 delay(100);}
if (analogValue >=0 && analogValue <505)

It’s never going to be less than zero.

analogValue<=1025

It is always going to be less than 1024 (unless you’re on a Due)

Yup. Got that :slight_smile:

Good points cheers.

Gedc:
Can the more smarter folks i.e currently most people on here other than me, look over the script and see if there are possible issues or indeed tidy it up from the clunky workings.

Bulldog disqualified...

Good for you in getting it working but you should be able to simplify the tests for switch position.

// IF/Else statements regarding Values through switch
if (analogValue < 200)  //switch at zero volt end
{
  Serial.println("Rotary Position 3");
}

else if (analogValue > 1000) //switch at 5V end
{
  Serial.println ("Rotary Position 1");
}

else
{
  Serial.println ("Rotary Position 2");   // not at either end so it must be in the middle
}

Your next task is to make it print a message only when the switch position is changed using the principle shown in the state change detection example in the IDE

Gedc:
.I'm presuming it's easy enough to swap out the serial.print command with some other scripts that control the LED lighting sequence.

You can do some function calls in the loop() function while you are learning:

else if (analogValue > 1000) //switch at 5V end
{
  Serial.println ("Rotary Position 1");
  coolBlinkyLedThingy():
}

and try to learn BlinkWithoutDelay to execute your functions with non-blocking code.

and try to learn BlinkWithoutDelay to execute your functions with non-blocking code.

. . . but remember that reading your rotary switch with analogRead will block for around 100us.

Gedc:
Ok. So got there in the end I think. Tried using the digital pins as well, and setting them to inputs so I didn't need the external resistors but managed to short the board so will need to read a bit more on that. Having removed the resistors and using internal pull ups I can see a straight +5v to Ground in my wiring so no surprises the board shorted. Back to getting it to work through Analog input first..

Digital is the way to go if you have enough pins.

Connect the common to GND and the three position contacts to three different pins. In your code, set the pins to INPUT_PULLUP. A position will be active when the pin is LOW.

If you shorted your board it's because you connected the common to +5 and the positions to the pins, putting the short in parallel with the internal pullups.

Hi Lar3ry.

Thanks for your comments. I had the circuit connected as per below. I found the schematic and accompanying code online.

I am not sure why the schematic has pin 7 connected to output 1 on the switch yet his arduino code only deals from pins 3 to 6 ? No doubt my lack of electronic understanding. It was connected exactly as the schematic minus the resistors. This shorted my board.

Image Location http://s3.amazonaws.com/satisfaction-production/s3_images/101962/arduino-rotary-switch.png

From the site :-" In setup() I turn each pin into an input and turn on the internal pull-up resistor (so you don’t need the external resistors shown in the diagram). There’s also a function called getRotaryValue()that you can use to get back a value that indicates the position of the rotary switch. Then you can do if() statements off that and do whatever you want. In this case, I have it printing to the serial port, but you can add the appropriate BlinkM commands you want."

// RotarySwitch.pde -- test out a rotary switch (not a rotary encoder)
// Tod E. Kurt, http://todbot.com/blog/

const int firstRotaryPin = 3;
const int lastRotaryPin = 6;

void setup() {
for( int i=firstRotaryPin; i<= lastRotaryPin; i++) { 
pinMode( i, INPUT); 
digitalWrite( i, HIGH); // turn on internal pullup resistor
}
Serial.begin(9600); // let's talk to the world
Serial.println("RotarySwitch ready!");
}

// returns the position of the rotary switch, 1-5
// or returns 0 if no rotary switch is hooked up
int getRotaryValue() {
for( int i=firstRotaryPin; i<= lastRotaryPin; i++) { 
int val = digitalRead( i ); // look at a rotary switch input
if( val == LOW ) { // it's selected
return (i - firstRotaryPin + 1); // return a value that ranges 1 - 5
}
}
return 0; // error case
}

void loop() { 

int rotaryPos = getRotaryValue();

if( rotaryPos == 1 ) { 
Serial.println("Rotary Position 1");
} 
else if( rotaryPos == 2 ) {
Serial.println("Rotary Position 2");
} 
else if( rotaryPos == 3 ) {
Serial.println("Rotary Position 3");
} 
else if( rotaryPos == 4 ) {
Serial.println("Rotary Position 4");
} 
else if( rotaryPos == 5 ) {
Serial.println("Rotary Position 5");
} 
else { 
Serial.println("uh oh, somethings wrong");
}
delay( 100 ); // slow down the loop() so we don't spam the serial port 
}

Gedc:
I am not sure why the schematic has pin 7 connected to output 1 on the switch yet his arduino code only deals from pins 3 to 6 ? No doubt my lack of electronic understanding. It was connected exactly as the schematic minus the resistors. This shorted my board.

Image Location http://s3.amazonaws.com/satisfaction-production/s3_images/101962/arduino-rotary-switch.png

Connecting pins that way will not short your board. Well, I should qualify that by saying that you can short 5V to GND with that connection if the pin that’s grounded is set to output and is then set HIGH. The code you just posted should not have caused any problems, though I do wonder what you had connected to pin 6

Is the code you posted the code you are using now? If so, you may be counting up to one pin too high. You are setting 4 pins to INPUT, and I gather from your first post, you are only using 3 pins.

Anyway, there is another way of setting a pin to input and enabling the pullup resistor. It can be done with just one statement. Assuming you have 3 pins connected to switch positions, going to pins 3, 4, and 5, the start of your code can look like this:

const int firstRotaryPin = 3;
const int lastRotaryPin = 5;

void setup() {
  for( int i=firstRotaryPin; i<= lastRotaryPin; i++) { 
    pinMode( i, INPUT_PULLUP); 
  }
  Serial.begin(9600); // let's talk to the world
  Serial.println("RotarySwitch ready!");
}

I would be interested to know what makes you think you “shorted the board”.

Hi again.

Thanks heaps for that code. It worked a treat when i inserted it into the other code I posted.

By shorting out, I'm using a Sparkfun RedBoard and it has a built in safety that kills the board if I try to do something stupid.
I'm completely new to electronics and completely new to Arduino so I think this may be a knowledge gap for me.

Here's the knowledge question - I also had 5V connected to switch position 1 as I assumed I needed to drive power through the switch to get a reading ? When I plugged it all up, uploaded your code then also connected that 5v pin into the board, the inbuilt safety kicked in and the board died again until I reset it.

Everything works fine with no 5v input, common connected to ground and Positions 1,2 and 3 on the switch connected to digital pins 3,4 and 5.

IS that correct ? The switch is creating a reading even though it isn't connected to the +5v source?

Thanks heaps folks. I really appreciate your help and just hope I get to a level where I can pay it onto other newbies.

Ged