Using a 4-pin dip switch to set value

For my Arduino Uno I've programmed a very simple count-down timer script for a LED ring (see code below). Instead of a fixed duration of 60 seconds, I would like to add a 4-pin dip switch with which one can set the duration:
switch #1: 30 seconds
switch #2: 60 seconds
switch #3: 120 seconds
switch #4: 300 seconds

So, for example, if switch #1 and #3 are on, the duration would be 150 seconds.
How do I wire such a dip switch and how do a get the values into my program?

#include "FastLED.h"

#define LED_PIN 6
#define NUM_LEDS 24
CRGB leds[NUM_LEDS];

unsigned long previousMillis = 0;
const long interval = 1000; // count down every 1 second (in milliseconds)
int count = 60; // start at 60 seconds

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(2); // set brightness to 2
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(0, 255, 255); // set all LEDs to white (0° hue, 255 saturation, 255 value)
  }
  FastLED.show();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // it's been 1 second since the last count, so count down again
    if (count > 0) {
      count--;
      leds[count] = CRGB::Black; // turn off LED
      FastLED.show();
    }
    previousMillis = currentMillis;
  }
}

Between an input pin and ground, and use INPUT_PULLUP as the pinMode

Using digitalRead and bitWrite

1 Like

Hello adamsmi

Try, test and modify the sketch to the project needs.

enum Names {One,Two,Three,Four};
constexpr byte DipSwitchPin[] {A0,A1,A2,A3};
struct DIPSWITCH 
{
  const byte Pin;
  const unsigned long Tvalue; 
}dipSwitchs[] {
  {DipSwitchPin[One],30000},
  {DipSwitchPin[Two],60000},
  {DipSwitchPin[Three],120000},
  {DipSwitchPin[Four],300000},
};
unsigned long interval=0;
void setup() 
{
  for (auto dipSwitch:dipSwitchs) pinMode(dipSwitch.Pin,INPUT_PULLUP);
  for (auto dipSwitch:dipSwitchs) if (!digitalRead(dipSwitch.Pin)) interval +=dipSwitch.Tvalue;
  Serial.begin(115200);
  Serial.println(interval);
}
void loop() {}

Have a nice day and enjoy coding in C++.

1 Like

Why two near-identical for loops?

To split the pinMode action from the digitalRead action.

Because. . ?
Anti-plagiarism?
Don't like braces?

It´s up to the TO to implement these lines of code.

That's a strange thing to say, when you've already done it for them

Why the somewhat esoteric auto keyword in code for a new user with no explanation of how it works?

So far, the TO has not asked, or have I missed something?

An option, which gives 2^3 states:. The example sends commands to the serial command console on a Raspberry Pi in the event the Pi keyboard becomes unresponsive... a push-button reads the 3 DIP switches and performs pre-programmed code to send serial commands.

/* Pro Micro Test Code
    M. Ray Burnette, published on Hackster 2017/06/13 License: MIT
    ArduinoGUI: 1.6.13 on Linux Mint 17.3
      Sketch uses 6,458 bytes (22%) of program storage space. Maximum is 28,672 bytes.
      Global variables use 351 bytes (13%) of dynamic memory, leaving 2,209 bytes for local variables. Maximum is 2,560 bytes.
*/

#include <Streaming.h>
#include "./functions.h"


void setup()
{
  pinMode(Pin1, INPUT);
  digitalWrite(Pin1, HIGH);       // enable pullup
  pinMode(Pin2, INPUT);
  digitalWrite(Pin2, HIGH);       // enable pullup
  pinMode(Pin4, INPUT);
  digitalWrite(Pin4, HIGH);       // enable pullup
  pinMode(Button, INPUT);
  digitalWrite(Button, HIGH);     // enable pullup

  Serial1.begin(115200);          // This pipes to the serial TxRx
  Serial.begin(9600);             // USB serial, BAUD is just a placeholder
  if (debugPrint) Serial << "Serial ports initialized...\n\r";
}
void loop()
{
  if (! digitalRead(Button))
  {
    Results = nValue(); if (debugPrint) Serial << F("Results value: ") << Results << F("\n\r");
    {
      switch (Results)
      {
        case 0:
          if (debugPrint) Serial << F("Case 0\n\r");
          zero();                   // Function to perform
          delay(LoopCycleTime);
          break;
        case 1:
          if (debugPrint) Serial << F("Case 1\n\r");
          one();
          delay(LoopCycleTime);
          break;
        case 2:
          if (debugPrint) Serial << F("Case 2\n\r");
          two();
          delay(LoopCycleTime);
          break;
        case 3:
          if (debugPrint) Serial << F("Case 3\n\r");
          three();
          delay(LoopCycleTime);
          break;
        case 4:
          if (debugPrint) Serial << F("Case 4\n\r");
          four();
          delay(LoopCycleTime);
          break;
        case 5:
          if (debugPrint) Serial << F("Case 5\n\r");
          five();
          delay(LoopCycleTime);
          break;
        case 6:
          if (debugPrint) Serial << F("Case 6\n\r");
          six();
          delay(LoopCycleTime);
          break;
        case 7:
          if (debugPrint) Serial << F("Case 7\n\r");
          seven();
          delay(LoopCycleTime);
          break;
        default:
          if (debugPrint) Serial << F("Results value: ") << Results << F("\n\r");
          delay(LoopCycleTime);
      }
    }
  }
}


You would use your own functions here in header file

#define CommandDelay   1000       // mS
#define LoopCycleTime  1000       // mS

// Pins "7 8 9" on uC connect to encoder "1 2 4" respectively, C == Gnd
const byte  Pin1     = 7;         // Pin is "high" to represent 0 and "low" to represent 1
const byte  Pin2     = 8;         // "" ditto
const byte  Pin4     = 9;         // "" ditto
const byte  Button   = 10;        // button pulls pin to Gnd to represent "press" state

boolean debugPrint   = !false;    // change to !false (true) to echo activity over USB port to PC

uint8_t Results = 0;


int nValue (void) {               // Positive logic - 7 high, 8 high, 9 high == 7 (all Gnd == 0)
  uint8_t temp = 0;               // could be accomplished by masking and directly reading port
  if( digitalRead( Pin4)) temp += 4;
  if( digitalRead( Pin2)) temp += 2;
  if( digitalRead( Pin1)) temp += 1;
 return temp;
}

/*
Logic Table x == no connection(default)     0 == Grounded

          2^0     2^1     2^2
Decimal   /-------Pins------/       Function call
Value     D7      D8      D9
0         0       0       0         zero()
1         x       0       0         one()
2         0       x       0         two()
3         x       x       0         three()
4         0       0       x         four()
5         x       0       x         five()
6         0       x       x         six()
7         x       x       x         seven()
*/


// function zero logs in as user pi with password, flushes disk queue, then reboots the RPi
void zero( void )                 // called when Pins D7, D8, D9 are all low (jumpered to ground)
{
  Serial1 << F("\n\r");
  if(debugPrint) Serial << F("\n\r");
  delay(CommandDelay);
  if(debugPrint) Serial << F("Attempting to login as user Pi\n\r");
  Serial1 << F("pi\n\r");
  delay(CommandDelay);
  Serial1 << F("raspberry\n\r");
  delay(CommandDelay);
  if(debugPrint) Serial << F("Attempting to write cache to SD\n\r");
  Serial1 << F("sudo sync\n\r");
  delay(CommandDelay);
  Serial1 << F("sudo sync\n\r");
  delay(CommandDelay);
  if(debugPrint) Serial << F("Issuing the sudo reboot now command\n\r");
  Serial1 << F("sudo reboot now\n\r");
}

// function one logs in as user pi with password, flushes disk queue, then shutdowns the RPi
void one( void )
{
  Serial1 << F("\n\r");
  if(debugPrint) Serial << F("\n\r");
  delay(CommandDelay);
  if(debugPrint) Serial << F("Attempting to login as user Pi\n\r");
  Serial1 << F("pi\n\r");
  delay(CommandDelay);
  Serial1 << F("raspberry\n\r");
  delay(CommandDelay);
  if(debugPrint) Serial << F("Attempting to write cache to SD\n\r");
  Serial1 << F("sudo sync\n\r");
  delay(CommandDelay);
  Serial1 << F("sudo sync\n\r");
  delay(CommandDelay);
  if(debugPrint) Serial << F("Issuing the sudo shutdown now command\n\r");
  Serial1 << F("sudo shutdown now\n\r");
}

void two( void )
{
}

void three( void )
{
}

void four( void )
{
}

void five( void )
{
}

void six( void )
{
}

void seven( void )
{
}

1 Like

You have four options. You only need two switches, combinations are HH, HL, LH, LL.

OP seems to want 15 options.
Leo..

1 Like

Suppose the switches are connected to pins 8 - 11 configured as input-pullup.
they are connected to the lower 4 bits of portB

then

int duration;

duration = PINB & 0b00001111;  //mask off upper 4 bits; 
duration*= 30; //now in seconds

is that not simpler (and doesnt need "auto")

3 Likes

The TO has to select the best solution for their project.

Yes, that's right, I want to implement 15 options.
Before I can choose the best solution, I'll have to grasp the different concepts mentioned from all above contributions — it will take some time, because I'm quite a beginner!
Thanks to all contributers!

@johnerrington I don't know how to implement your code snippet in my code respectively what part it replaces in the code of the other contributions here. I would be happy if you could describe it for me.

see pins 8,9,10,11 are connected to port B as PB0, PB1, PB2, PB3
connect your switches to those pins, with the other side of each switch grounded.
in SETUP Set pins 8 - 11 as INPUT-PULLUP. eg pinMode(8, INPUT_PULLUP);

now

duration = PINB & 0b00001111;

reads ALL of portB as a binary value, and sets the 4 upper bits to zero.
so duration = 0b0000xxxx where xxxx is the value from your switches; a number in the range 0-15.

duration * = 30; //multiplies that value by 30 so duration is now 0, 30, 60, 90 ... (15*30)

1 Like

@adamsmi

How is it going with your problem?

I reused @paulpaulson sketch and came up with following adoptions:

// https://forum.arduino.cc/t/using-a-4-pin-dip-switch-to-set-value/1070190/2


// declare a structure of pin and interval
struct DipSwitch
{
  const uint8_t pin;        // the gpio
  const uint16_t interval;  // the interval in seconds
};

// make an array of dipswitches and initialize the values
DipSwitch dipSwitch[]
{
  {A0, 30},
  {A1, 60},
  {A2, 120},
  {A3, 300},
};

// calculate the setted interval
uint32_t getInterval()
{
  const uint16_t factor = 1000; // from milliseconds to seconds
  uint32_t interval = 0;
  for (auto &i : dipSwitch)
    if (digitalRead(i.pin) == LOW) interval += i.interval;
  return interval * factor;
}

void setup()
{
  Serial.begin(115200);
  for (auto &i : dipSwitch)
    pinMode(i.pin, INPUT_PULLUP);
  Serial.println(getInterval());  // print the setted interval
}

void loop() {
  Serial.println(getInterval());
  delay(1000); // dirty delay just to make the output visible
}

@adamsmi, If you still have questions - ask.
If your problem is solved, mark one post as solution.
You can say thank you to helpers by pressing the heart - it will come without costs for you.

2 Likes

Tested on a nano:

/*
ARDUINO   PORT 
  PIN     NAME
-------   ----  
   8      PB0
   9      PB1
  10      PB2
  11      PB3
*/
void setup() {
  Serial.begin(57600);

  // DDRB (R/W) pin direction (0 = INPUT / 1 = OUTPUT)
  // PORTB (R/W) pin state (INPUT: 0 = LOW / 1 = HIGH | OUTPUT: 0 = PULL-UP DEACTIVATED / 1 = PULL-UP ACTIVATED)
  // PINB (R) pin state (INPUT ONLY: 0 = LOW / 1 = HIGH)
  DDRB &= 0x0F;   //set pins 8-11 as inputs;  0x0F is 0B00001111
  PORTB |= 0x0F;  // set pullups on pins 8-11 as inputs
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  int interval;
  // read switch value from portB
  int switches = PINB & 0x0F;  // 0x0F = 0B00001111 = set upper 4 bits of value to zeros.
  switches ^= 0x0F;            //^ is XOR: change values from lower 4 bits so 0011 becomes 1100
  Serial.println(switches);    //this now holds a value between 0b0000 and 0b1111 depending on the switch settings
  interval = 1000 * switches;
  delay(interval);  //or you can use the "switches" value in your millis timing.
}

1 Like