Using an array for multiple toggle switches

Hi,
I am planning to use several on-off toggle switches for a project. When switch number one is moved to the on position it will send the command Serial.println ("SW1_on") and when it goes to the off position it will send the command Serial.println ("SW1_off"). For switch number 2 it will be Serial.println ("SW2_on") for on and Serial.println ("SW2_off") for off and so on for the other switches. Basically, I just want to do a state change detection (edge detection). I have it working for one switch with the following code:

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to

// Variables will change:
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  // initialize the button pin as an input:
  pinMode(buttonPin, INPUT_PULLUP);
  // initialize serial communication:
  Serial.begin(115200);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the current state is HIGH then the button went from off to on:
    if (buttonState == HIGH) {
      Serial.print("SW1_on");
    }
    else {
      // if the current state is LOW then the button went from on to off:
      Serial.print("SW1_off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;
}

Now I would like to use an array for the inputs like this:

byte switch[] = {2, 3, 4, 5}; //define the 4 switches that we'll use.
#define numSwitches sizeof(switch) //determine how big the array up above is, by checking the size

void setup(){
  byte i;
  // Make input & enable pull-up resistors on switch pins
  for (i=0; i< numSwitches; i++) {
  pinMode(switch[i], INPUT_PULLUP);
  }
  Serial.begin(115200); //start serial connection
}

I don't know how to proceed from here. I guess first of all I would need a for loop to do a digitalRead of the switches. How do I implement the state and last state of the switches in arrays? Can someone give me a hint of how to proceed?

Best regards,
Isak

You could just duplicate the code in if (buttonState != lastButtonState) {, but change the variable names to something like if (buttonState1 != lastButtonState1) {, and repeat for the switches.

Or you could read the switches all at once and set their states in the array, then test each switch from the array.

one approach

#define N_BUT   3

byte pins  [N_BUT] = { A1, A2, A3 };
byte last  [N_BUT] = {};

// -----------------------------------------------------------------------------
void setup() {
    for (int n = 0; n < N_BUT; n++)  {
        pinMode (pins [n], INPUT_PULLUP);
        last  [n] = digitalRead (pins [n]);
    }

    Serial.begin(115200);
}

// -----------------------------------------------------------------------------
void
butPress (
    int  n)
{
    byte state = digitalRead (pins [n]);
    if (last [n] != state)  {
         last [n] = state;
         char s [20];
         if (state)
            sprintf (s, "SW%d_on", n);
         else
            sprintf (s, "SW%d_off", n);
         Serial.println (s);
    }
}

// ---------------------------------------------------------
void loop() {
    delay (10);     // debounce
    for (int n = 0; n < N_BUT; n++)
        butPress (n);
}

Thank you so much for your replies. Like always there are many ways to approach a desired function. Greg's example code is very elegant and works exactly how I wanted it. By using the sprintf function and a char array the code will remain the same no matter how many switches you want to use (except for inserting the pin numbers and defining the number of pins). :smiley:

I just swapped the two sprintf functions around, otherwise the switches would show "off" when pressed and "on" when released:

void
butPress (
    int  n)
{
    byte state = digitalRead (pins [n]);
    if (last [n] != state)  {
         last [n] = state;
         char s [20];
         if (state)
            sprintf (s, "SW%d_off", n);
         else
            sprintf (s, "SW%d_on", n);
         Serial.println (s);
    }
}

Thank you again. This was a huge help!!!

Best regards,
Isak

Hi again,
To get even more inputs for my arduino, I am using multiple 74HCT4051 IC's. With the following code, for Switch 2 for instance, the serial monitor shows "SW2" when I turn the switch on and the same ("SW2") when I toggle it to the off position:

// Sketch for connecting one or more multiplexers (74HC4051/74HCT4051) to the Arduino
// This gives you more digital input pins for your project.  The 74HC4051/74HCT4051 IC´s
// can also be used for analog inputs. You then have to connect the common pin(s) to the
// analog pin(s) of the Arduino and do an analogRead.

int ChannelValue[16]; // [8] for one multiplexer, [16] for two multiplexers; add 8 for every additional multiplexer
int ChannelValueOld[16]; // Used to store the previous, and compare with the new value

int i = 0; // Counter for the "for loop"

int bit1 = 0;
int bit2 = 0;
int bit3 = 0;

void setup() {
 //Select-Pins 4051s
 pinMode(8, OUTPUT);  // S0
 pinMode(9, OUTPUT);  // S1
 pinMode(10, OUTPUT); // S2
 
 Serial.begin(115200);
}

void loop() {
 for (i = 0; i <= 7; i++) {
 bit1 = bitRead(i,0); // Reading the bits
 bit2 = bitRead(i,1); // for the eight
 bit3 = bitRead(i,2); // different channels
 
 digitalWrite(8, bit1);  // Sending the single bits
 digitalWrite(9, bit2);  // to the three different
 digitalWrite(10, bit3); // select pins
 
 channelQuery(i,40);   // Calls the "channelQuery" function to check the memory locations 0 -  7 on the first  IC (Digital Pin 40 on the Arduino)
 channelQuery(i+8,41); // Calls the same funtion again,  but now for the memory locations 8 - 15 on the second IC (Digital Pin 41 on the Arduino)
// channelQuery(i+16,42);
// channelQuery(i+24,43);
 }
}

// Function for what to do with the switches on the different channels:
void channelQuery(int counter, int digitalPin) {
 ChannelValue[counter] = digitalRead(digitalPin);
 if (counter == 0 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW0"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 1 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW1"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 2 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW2"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 3 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW3"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 4 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW4"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 5 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW5"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 6 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW6"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 7 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW7"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 8 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW8"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 9 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW9"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 10 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW10"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 11 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW11"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 30 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW12"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 13 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW13"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 14 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW14"); ChannelValueOld[counter] = ChannelValue[counter];}
 if (counter == 15 and (ChannelValue[counter] != ChannelValueOld[counter])) {
  Serial.println("SW15"); ChannelValueOld[counter] = ChannelValue[counter];}
}

To simplify the code, I modified it with the sprintf function like you showed, Greg. Now the serial monitor still shows the same both in the ON and OFF-position ("SW2_off"):

int ChannelValue[16]; // [8] for one multiplexer, [16] for two multiplexers; add 8 for every additional multiplexer
int ChannelValueOld[16]; // Used to store the previous, and compare with the new value

int i = 0; // Counter for the "for loop"

int bit1 = 0;
int bit2 = 0;
int bit3 = 0;

void setup() {
 //Select-Pins 4051s
 pinMode(8, OUTPUT);  // S0
 pinMode(9, OUTPUT);  // S1
 pinMode(10, OUTPUT); // S2
 
 Serial.begin(115200);
}

void loop() {
 for (i = 0; i <= 7; i++) {
 bit1 = bitRead(i,0); // Reading the bits
 bit2 = bitRead(i,1); // for the eight
 bit3 = bitRead(i,2); // different channels
 
 digitalWrite(8, bit1);  // Sending the single bits
 digitalWrite(9, bit2);  // to the three different
 digitalWrite(10, bit3); // select pins
 
 channelQuery(i,40);   // Calls the "channelQuery" function to check the memory locations 0 -  7 on the first  IC (Digital Pin 40 on the Arduino)
 channelQuery(i+8,41); // Calls the same funtion again,  but now for the memory locations 8 - 15 on the second IC (Digital Pin 41 on the Arduino)
// channelQuery(i+16,42);
// channelQuery(i+24,43);
 }
}

// Function for what to do with the switches on the different channels:
void channelQuery(int counter, int digitalPin)
{
    ChannelValue[counter] = digitalRead(digitalPin);
    if (ChannelValue[counter] != ChannelValueOld[counter])  {
        ChannelValueOld[counter] = ChannelValue[counter];
         char s [20];
         if (ChannelValue)
            sprintf (s, "SW%d_off", counter);
         else
            sprintf (s, "SW%d_on", counter);
         Serial.println (s);
    }
}

I would like to know how to modfiy the code, to get Serial.print("SW2_on") in the ON-position and Serial.print("SW2_off") when the switch goes to the OFF-position.

Regards,
Isak

you're checking the value of "ChannelValue", which is the address of the array, instead of testing the value of an element, "ChannelValue[counter]"

void channelQuery(int counter, int digitalPin)
{
    ChannelValue[counter] = digitalRead(digitalPin);
    if (ChannelValue[counter] != ChannelValueOld[counter])  {
        ChannelValueOld[counter] = ChannelValue[counter];

         char s [20];
         if (ChannelValue)
            sprintf (s, "SW%d_off", counter);
         else
            sprintf (s, "SW%d_on", counter);
         Serial.println (s);
    }
}

Of course! I changed the code according to your comment, and it workes as expected:

void channelQuery(int counter, int digitalPin)
{
    ChannelValue[counter] = digitalRead(digitalPin);
    if (ChannelValue[counter] != ChannelValueOld[counter])  {
        ChannelValueOld[counter] = ChannelValue[counter];
         char s [20];
         if (ChannelValue[counter])
            sprintf (s, "SW%d_on", counter);
         else
            sprintf (s, "SW%d_off", counter);
         Serial.println (s);
    }
}

Thank you once again, for your quick response and help! :smiley:

Cheers,
Isak