Toggling relay outputs individually, saving and recalling their states

Hi all,

I have a little project I'm working on. I want to make loop/switcher for my guitar pedals that switches them in and out individually and allows me to save preset combinations and recall the presets. I'm mocking up a small version now that uses 4 momentary switches, 2 digital inputs that I'm using is as momentary switch inputs, and 4 relay outputs. I have the code below but here is how it all (should) works:

When pin 6 is pulled low the program is in toggle mode. In this mode each each push button toggles a relay on/off.
When pin 6 is high it is in preset mode and I want it to recall a saved configuration of outputs (not quite working yet), of which there are 4 each implemented by one of the momentary switches.
When pin 7 is pulled low I'm trying to capture the current states of the relay outputs as a 4bit word to be drawn from later.
I have 2 methods I'm trying to use for saving the stays, with bit shifts and with bitSet. In the writePrest function I serial print what it supposedly just saved and instead of getting a nice neat "preset 1 = 0110" I get a crazy "preset 1 =preset4 = 11111111111111111111111111111010". Not sure why…. looking for a sanity check.

You can see below that I've written a few functions to try and keep the logic straight.

//

#include <EEPROM.h>

const int mode = 6; 
const int save = 7;

const int pb1 =  8;
const int pb2 =  9;
const int pb3 = 10;
const int pb4 = 11;

int modeV = 12;
int saveV = 13;

const int rl1 =  2;
const int rl2 =  3;
const int rl3 =  4;
const int rl4 =  5;

int preset = 0;

int loopState1 = 0;
int loopState2 = 0;
int loopState3 = 0;
int loopState4 = 0;

int preset1 = 0;
int preset2 = 0;
int preset3 = 0;
int preset4 = 0;

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);

  pinMode(mode, INPUT_PULLUP);
  pinMode(save, INPUT_PULLUP);

  pinMode(pb1, INPUT);
  pinMode(pb2, INPUT);
  pinMode(pb3, INPUT);
  pinMode(pb4, INPUT);

  pinMode(rl1, OUTPUT);
  pinMode(rl2, OUTPUT);
  pinMode(rl3, OUTPUT);
  pinMode(rl4, OUTPUT);

  pinMode(modeV, OUTPUT);
  pinMode(saveV, OUTPUT);

  digitalWrite(rl1, LOW);
  digitalWrite(rl2, LOW);
  digitalWrite(rl3, LOW);
  digitalWrite(rl4, LOW);

  digitalWrite(modeV, HIGH);
  digitalWrite(saveV, HIGH);
  //preset = 
  //loadLoopState ();

}

void loop() {
  // put your main code here, to run repeatedly:  

  if (digitalRead (mode) == HIGH)
  {
    presetMode();
    Serial.println("PRESET MODE");
  }
  else
  {
    toggleMode();
    Serial.println("TOGGLE MODE");
  }

  if (digitalRead (save) == LOW)
  {
    saveLoopState ();
  }
}

//*************************************************

void presetMode ()
{
  if (digitalRead (pb1) == HIGH)
  {
    preset = 1;
    loadLoopState ();
    writeLoopState ();
  }
  else if (digitalRead (pb2) == HIGH)
  {
    preset = 2;
    loadLoopState ();
    writeLoopState ();
  }
  else if (digitalRead (pb3) == HIGH)
  {
    preset = 3;
    loadLoopState ();
    writeLoopState ();
  }
  else if (digitalRead (pb4) == HIGH)
  {
    preset = 4;
    loadLoopState ();
    writeLoopState ();
  }
}


void toggleMode ()
{
  if (digitalRead (pb1) == HIGH)
  {
    loopState1 = ~ loopState1;
    writeLoopState ();
    while (digitalRead (pb1) == HIGH);
    {
      delay(1);
    }
  } 
  else if (digitalRead (pb2) == HIGH)
  {
    loopState2 = ~ loopState2;
    writeLoopState ();
    while (digitalRead (pb2) == HIGH);
    {
      delay(1);
    }
  } 
  else if (digitalRead (pb3) == HIGH)
  {
    loopState3 = ~ loopState3;
    writeLoopState ();
    while (digitalRead (pb3) == HIGH);
    {
      delay(1);
    }
  } 
  else if (digitalRead (pb4) == HIGH)
  {
    loopState4 = ~ loopState4;
    writeLoopState ();
    while (digitalRead (pb4) == HIGH);
    {
      delay(1);
    }
  }
}

void loadLoopState()
{
  switch (preset)
  {
  case 1:
    loopState1 = bitRead(preset1,0);
    loopState2 = bitRead(preset1,1);
    loopState3 = bitRead(preset1,2);
    loopState4 = bitRead(preset1,3);
    break;
    loopState1 = bitRead(preset2,0);
    loopState2 = bitRead(preset2,1);
    loopState3 = bitRead(preset2,2);
    loopState4 = bitRead(preset2,3);
    break;
  case 3:
    loopState1 = bitRead(preset3,0);
    loopState2 = bitRead(preset3,1);
    loopState3 = bitRead(preset3,2);
    loopState4 = bitRead(preset3,3);
    break;
  case 4:
    loopState1 = bitRead(preset4,0);
    loopState2 = bitRead(preset4,1);
    loopState3 = bitRead(preset4,2);
    loopState4 = bitRead(preset4,3);
    break;

    Serial.print(loopState1);
    Serial.print(loopState2);
    Serial.print(loopState3);
    Serial.print(loopState4);
  }
}

void writeLoopState ()
{
  digitalWrite(rl1, loopState1);
  digitalWrite(rl2, loopState2);
  digitalWrite(rl3, loopState3);
  digitalWrite(rl4, loopState4);
}

 void saveLoopState ()
 {
 switch (preset)
 {
 case 1:
 preset1 = ((loopState4 << 3) + (loopState3 << 2) + (loopState2 << 1) + loopState1);
 Serial.print("preset1 = ");    
 Serial.println(preset1, BIN);     
 break;
 case 2:
 preset2 = ((loopState4 << 3) + (loopState3 << 2) + (loopState2 << 1) + loopState1);
 Serial.print("preset2 = ");    
 Serial.println(preset2, BIN);   
 break;
 case 3:
 preset3 = ((loopState4 << 3) + (loopState3 << 2) + (loopState2 << 1) + loopState1);
 Serial.print("preset3 = ");    
 Serial.println(preset3, BIN);   
 break;
 case 4:
 preset4 = ((loopState4 << 3) + (loopState3 << 2) + (loopState2 << 1) + loopState1);
 Serial.print("preset4 = ");    
 Serial.println(preset4, BIN);   
 break;
 }
 while (digitalRead (save) == LOW);
 {
 delay(1);
 }
 


}


/*

 
 void saveLoopState ()
{
  switch (preset)
  {
  case 1:
   if(loopState1 == 1) {bitSet(preset1,0);}
   if(loopState2 == 1) {bitSet(preset1,1);}
   if(loopState3 == 1) {bitSet(preset1,2);}
   if(loopState4 == 1) {bitSet(preset1,3);}
    
    Serial.print("preset1 = ");    
    Serial.println(preset1, BIN);     
    break;
  case 2:
   if(loopState1 == 1) {bitSet(preset2,0);}
   if(loopState2 == 1) {bitSet(preset2,1);}
   if(loopState3 == 1) {bitSet(preset2,2);}
   if(loopState4 == 1) {bitSet(preset2,3);}
   
    Serial.print("preset2 = ");    
    Serial.println(preset2, BIN);   
    break;
  case 3:
   if(loopState1 == 1) {bitSet(preset3,0);}
   if(loopState2 == 1) {bitSet(preset3,1);}
   if(loopState3 == 1) {bitSet(preset3,2);}
   if(loopState4 == 1) {bitSet(preset3,3);}
    
    Serial.print("preset3 = ");    
    Serial.println(preset3, BIN);   
    break;
  case 4:
   if(loopState1 == 1) {bitSet(preset4,0);}
   if(loopState2 == 1) {bitSet(preset4,1);}
   if(loopState3 == 1) {bitSet(preset4,2);}
   if(loopState4 == 1) {bitSet(preset4,3);}
    
    Serial.print("preset4 = ");    
    Serial.println(preset4, BIN);   
    break;
  }
  while (digitalRead (save) == LOW);
  {
    delay(1);
  }

 
 
 */

Once I get this working I'm going to expand it to 8 momentary switches (the foot pedal types) to control 8 loops and 8 presets.

Thanks for any help you can give,
Brian

I'm mocking up a small version now that uses 4 momentary switches, 2 digital inputs that I'm using is as momentary switch inputs

4 switches on two pins? Or 6 switches on 6 pins?

  pinMode(mode, INPUT_PULLUP);
  pinMode(save, INPUT_PULLUP);

  pinMode(pb1, INPUT);
  pinMode(pb2, INPUT);
  pinMode(pb3, INPUT);
  pinMode(pb4, INPUT);

Why don't they all use the internal pullup resistors? Do the other 4 have external pullup or pulldown resistors?

int loopState1 = 0;
int loopState2 = 0;
int loopState3 = 0;
int loopState4 = 0;

Crappy names. You are not saving the state of a loop. Are you sure these shouldn't be longs? After all, you do need to store a value as high as 15 (to be 255) in them.

It's hard to understand what your code is supposed to be doing, given meaningless names like presetN and loopStateN.

You should be using arrays, not numbered variable names. Then, you could use a for loop to iterate over all of them, instead of cut and paste.

Where are you going to save these? If you are going to save them in EEPROM, bytes will be easier.

    while (digitalRead (pb2) == HIGH);
    {
      delay(1);
    }

While the switch state is HIGH, do nothing. When it goes LOW, delay for a millisecond. Why? Even removing the semicolon from the end, to make the delay(1) call the body of while loop doesn't make sense. Why do you care how many times the while loop iterates? Once or a million times makes no difference.

Hi PaulS,

It's 4 physical pushbuttons switches with built in debounce and pull-down resistors. When pressed they swing high. Inputs 6 and 7 and in pull-up mode so I can use grounded wires to pull them down. So 6 individual switches to the arduino on 6 pins.

Crappy names. You are not saving the state of a loop. Are you sure these shouldn't be longs? After all, you do need to store a value as high as 15 (to be 255) in them.

What's wrong with the names? How would you be naming them? They are meaningful enough to me.
I'll look into long format, do you think changing applies now (when 15 is the max value) or only when I go up to 8 or 16 loops?

It's hard to understand what your code is supposed to be doing, given meaningless names like presetN and loopStateN.

Again, I'm not really getting what's wrong about the names. I have 4 presets to save/write and 4 loops with outputs to toggle and save. If you're saying that NO name (using an array) is better than ANY name in this application then thanks for the coaching and I'll pursue that. If you're saying that THESE names should be replaced with BETTER names can you give me an idea of how a more experienced user might select them?

You should be using arrays, not numbered variable names. Then, you could use a for loop to iterate over all of them, instead of cut and paste.

OK, I'll look into arrays. Never done those before.

Where are you going to save these? If you are going to save them in EEPROM, bytes will be easier.

I was planning to write them to EEPROM during the save function. When you say bytes to do mean as an alternative to EEPROM or (what I think you mean) a better variable type for the data prior to saving?

While the switch state is HIGH, do nothing. When it goes LOW, delay for a millisecond. Why? Even removing the semicolon from the end, to make the delay(1) call the body of while loop doesn't make sense. Why do you care how many times the while loop iterates? Once or a million times makes no difference.

The idea here is that because the buttons will be arranged on the floor I wanted to hold the program while my foot is on one. The while loop ends when the button is released and the arduino starts to scan again. Correct, I don't care how many times it delays for 1 ms, I just want it to stop there. It might not be necessary because my foot will take way longer to get to another button and my other foot will be keeping me vertical, but I thought it might be a good practice. Another concern was to halt the function after an EEPROM write so I I din't accidentally write and over write an EEPROM address a couple hundred times when pressing the button. Hit the button > do a thing > after the thing is done wait until that button isn't pressed anymore. Now that you know what I'm looking to do, maybe there is a better way?

Thanks for the insight. Maybe you can take a few minutes and push me a little closer?

Brian

Does anyone else have any input, maybe?

OK, well I think I've made some progress. I haven't dug into arrays just yet and I'm sure this is some very redundant and bloated code for what it does… but it works now.

The problem with the strange "preset4 = 11111111111111111111111111111010" stuff was because I was using the ~ operator when toggling loopStates. I thought I was toggling the loopState variables form 1 to 0 and 0 to 1; but in actuality the ~ toggles all bits in the variable so I was going from 0 to 11111111 and vice versa. I replaced it with some if/else statements. I also change the variable to unsigned.

So now I need to work out saving the presets to EEPROM so they will survive power cycling.

#include <EEPROM.h>

//mode and save pins
const int mode = 6; 
const int save = 7;

//4 push buttons for toggling the 4 relays and switching the 4 presets
const int pb0 = 11;
const int pb1 = 10;
const int pb2 =  9;
const int pb3 =  8;

//the 4 relay outputs (perhaps redundant)
const int rl1 =  2;
const int rl2 =  3;
const int rl3 =  4;
const int rl4 =  5;

//statrtup on preset 1
int preset = 1;

//4 variables for the state of the current state of each relay loop
unsigned int loopState1 = 0;
unsigned int loopState2 = 0;
unsigned int loopState3 = 0;
unsigned int loopState4 = 0;

//4 bytes to store relay states, currently wiped to 0 at startup
byte preset1 = 0;
byte preset2 = 0;
byte preset3 = 0;
byte preset4 = 0;

void setup() {
  // put your setup code here, to run once:

  Serial.begin(57600);

  delay(500);

  pinMode(mode, INPUT_PULLUP);
  pinMode(save, INPUT_PULLUP);

  pinMode(pb0, INPUT);
  pinMode(pb1, INPUT);
  pinMode(pb2, INPUT);
  pinMode(pb3, INPUT);

  pinMode(rl1, OUTPUT);
  pinMode(rl2, OUTPUT);
  pinMode(rl3, OUTPUT);
  pinMode(rl4, OUTPUT);

//all relays off at startup
  digitalWrite(rl1, LOW);
  digitalWrite(rl2, LOW);
  digitalWrite(rl3, LOW);
  digitalWrite(rl4, LOW);

  //preset = 
  //loadLoopState ();

}

void loop() {

//select between toggle and preste mode or initiate a save of the current loop states
  if (digitalRead (mode) == HIGH)
  {
    presetMode();
    Serial.print("PRESET MODE   ");
    Serial.print("Preset = ");
    Serial.println(preset);
  }
  else
  {
    toggleMode();
    Serial.print("TOGGLE MODE   ");
    Serial.print(loopState1,BIN);
    Serial.print(loopState2,BIN);
    Serial.print(loopState3,BIN);
    Serial.println(loopState4,BIN);
  }

  if (digitalRead (save) == LOW)
  {
    saveLoopState ();
  }
}

//*************************************************

void presetMode ()
{
  if (digitalRead (pb0) == HIGH)
  {
    preset = 1;
    Serial.print("Preset 1 = ");
    Serial.println(preset1,BIN);
    loadLoopState ();
    writeLoopState ();
    while (digitalRead (pb0) == HIGH);
  }
  else if (digitalRead (pb1) == HIGH)
  {
    preset = 2;
    Serial.print("Preset 2 = ");
    Serial.println(preset2,BIN);
    loadLoopState ();
    writeLoopState ();
    while (digitalRead (pb1) == HIGH);
  }
  else if (digitalRead (pb2) == HIGH)
  {
    preset = 3;
    Serial.print("Preset 3 = ");
    Serial.println(preset3,BIN);
    loadLoopState ();
    writeLoopState ();
    while (digitalRead (pb2) == HIGH);
  }
  else if (digitalRead (pb3) == HIGH)
  {
    preset = 4;
    Serial.print("Preset 4 = ");
    Serial.println(preset4,BIN);
    loadLoopState ();
    writeLoopState ();
    while (digitalRead (pb3) == HIGH);
  }
}

void toggleMode ()
{
  if (digitalRead (pb0) == HIGH)
  {
    if (loopState1 == 0)
    {
      loopState1 = 1;
    }
    else
    {
      loopState1 = 0;
    }
    writeLoopState ();
    while (digitalRead (pb0) == HIGH);
  } 
  else if (digitalRead (pb1) == HIGH)
  {
    if (loopState2 == 0)
    {
      loopState2 = 1;
    }
    else
    {
      loopState2 = 0;
    }
    writeLoopState ();
    while (digitalRead (pb1) == HIGH);
  } 
  else if (digitalRead (pb2) == HIGH)
  {
    if (loopState3 == 0)
    {
      loopState3 = 1;
    }
    else
    {
      loopState3 = 0;
    }
    writeLoopState ();
    while (digitalRead (pb2) == HIGH);
  } 
  else if (digitalRead (pb3) == HIGH)
  {
    if (loopState4 == 0)
    {
      loopState4 = 1;
    }
    else
    {
      loopState4 = 0;
    }
    writeLoopState ();
    while (digitalRead (pb3) == HIGH);
  }
}

void saveLoopState ()
{
  switch (preset)
  {
  case 1:
    preset1 = 0;
    preset1 = ((0 << 7) + (0 << 6) + (0 << 5) + (0 << 4) + (loopState4 << 3) + (loopState3 << 2) + (loopState2 << 1) + loopState1 << 0);
    Serial.print("preset1 = ");    
    Serial.println(preset1, BIN);     
    break;
  case 2:
    preset2 = ((0 << 7) + (0 << 6) + (0 << 5) + (0 << 4) + (loopState4 << 3) + (loopState3 << 2) + (loopState2 << 1) + loopState1 << 0);
    Serial.print("preset2 = ");    
    Serial.println(preset2, BIN);   
    break;
  case 3:
    preset3 = ((0 << 7) + (0 << 6) + (0 << 5) + (0 << 4) + (loopState4 << 3) + (loopState3 << 2) + (loopState2 << 1) + loopState1 << 0);
    Serial.print("preset3 = ");    
    Serial.println(preset3, BIN);   
    break;
  case 4:
    preset4 = ((0 << 7) + (0 << 6) + (0 << 5) + (0 << 4) + (loopState4 << 3) + (loopState3 << 2) + (loopState2 << 1) + loopState1 << 0);
    Serial.print("preset4 = ");    
    Serial.println(preset4, BIN);   
    break;
  }
  while (digitalRead (save) == LOW);
}


void loadLoopState()
{
  switch (preset)
  {
  case 1:
    loopState1 = bitRead(preset1,0);
    loopState2 = bitRead(preset1,1);
    loopState3 = bitRead(preset1,2);
    loopState4 = bitRead(preset1,3);
    break;
  case 2:  
    loopState1 = bitRead(preset2,0);
    loopState2 = bitRead(preset2,1);
    loopState3 = bitRead(preset2,2);
    loopState4 = bitRead(preset2,3);
    break;
  case 3:
    loopState1 = bitRead(preset3,0);
    loopState2 = bitRead(preset3,1);
    loopState3 = bitRead(preset3,2);
    loopState4 = bitRead(preset3,3);
    break;
  case 4:
    loopState1 = bitRead(preset4,0);
    loopState2 = bitRead(preset4,1);
    loopState3 = bitRead(preset4,2);
    loopState4 = bitRead(preset4,3);
    break;

    Serial.print(loopState1);
    Serial.print(loopState2);
    Serial.print(loopState3);
    Serial.print(loopState4);
  }
}

void writeLoopState ()
{
  digitalWrite(rl1, loopState1);
  digitalWrite(rl2, loopState2);
  digitalWrite(rl3, loopState3);
  digitalWrite(rl4, loopState4);
}