Program and Save function using Keypad Library for Effects Switcher

Hi everyone! Now that I have a functional (if imperfect, but still!) relay switching setup for my guitar effects switcher, I've added LCD display and a bank button - both of which work great - but that leaves the programming function - e.g. choosing the effect loops for a preset, and then saving them to a preset. It's currently very clunky to me.

The code uses the keypad library/setup as the basis for reading and storing information. There are 3 columns of inputs - one to read the memory (e.g., use the thing), one to select effect loops for a preset, and one that saves those effect loops to memory.

Currently, this is done with either a 3 way rotary or 2 slide/foot switches. The 3 pins for the columns each read as "IN floating" in the simulator - all of the preset buttons link together and then connect to these pins. The manual switches effectively make it so only one input can be active at a time.

I had a thought to use relays instead of manual switches and control those with a button, but I still feel like that's overkill.

so I guess my question is: I know you can't "turn off" an input - but is there a way to sort of say "on button press, use this input only"? I'm not sure if you can set a pin as OUTPUT, LOW within a function, but that's where my brain is going.

Here's my code:

#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include <Keypad.h>

LiquidCrystal lcd(19, 18, 17, 16, 15, 14);

const int bankButton = A15;
const int progButton = A13;
const int saveButton = A14;
const byte rows = 3;
const byte cols = 3;
char keys[rows][cols] = {
{'a','f','k'}, 
{'b','g','l'},
{'c','h','m'}
};
byte rowPins[rows] = {2,3,4}; /* buttons or momentary switches */
byte colPins[cols] = {5,6,7}; /* rotary switch - pin 7 is read/use, pin 5 is program/choose effects, pin 6 is save to a preset. */
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);
int OneRelayPin[3] = {8,9,10}; /* pin 1 on relay - reset/default has pin 1 at 0v - RED */
int TenRelayPin[3] = {11,12,13}; /* pin 10 on relay - reset/default has pin 10 at 5v - BLUE */
int presetLEDPin[3] = {A0,A1,A2}; /* shows which preset is engaged - GREEN */
int effectLEDPin[3] = {A3,A4,A5}; /* shows which effects are engaged - YELLOW */
const int progRelay = 29;
const int saveRelay = 31;

byte midiChannel = 0;

int numberOfPedal = 3;

int bankVariable = 9;
int numberOfBanks = 9;
int bank = 0; //Starting Bank Number
boolean lastBankButton = LOW;
boolean currentBankButton = LOW;
boolean lastProgButton = LOW;
boolean currentProgButton = LOW;
boolean lastSaveButton = LOW;
boolean currentSaveButton = LOW;

/******************************************************/
void setup()
{
  lcd.begin (16, 2);
  lcd.print("You are a fat");
  lcd.setCursor(0, 1);
  lcd.print("sausage bitch!");

  for(int cc=0; cc<numberOfPedal; cc++) /* setup device */
  {
    pinMode(OneRelayPin[cc], OUTPUT);
    pinMode(TenRelayPin[cc], OUTPUT);
    pinMode(presetLEDPin[cc], OUTPUT);
    pinMode(effectLEDPin[cc], OUTPUT);
    digitalWrite(OneRelayPin[cc], LOW);
    digitalWrite(TenRelayPin[cc], LOW);
    digitalWrite(presetLEDPin[cc], LOW);
    digitalWrite(effectLEDPin[cc], LOW);
    delay(100);
  }
  delay(100);
  for(int dd=0; dd<numberOfPedal; dd++) 
  {
    digitalWrite(OneRelayPin[dd], HIGH);
    delay(100);  
  }
  delay(100);
  for(int ee=0; ee<numberOfPedal; ee++)
  {
    digitalWrite(TenRelayPin[ee], HIGH);
    digitalWrite(presetLEDPin[ee], HIGH);
    digitalWrite(effectLEDPin[ee], HIGH);
    delay(100);
  }
  delay(1000);

  //readPreset((bank * bankVariable), 1, 0); /* pulls first saved preset in memory */
  Serial.begin(31250); /* for midi communication - pin 1 TX */
  /*for (int i = 0; i < 10; i++) // erase eeprom (optional)
   // EEPROM.write(i, 0); */
   
}
/* Bank Button Debounce */

boolean bankdebounce(boolean last) {
  boolean current = digitalRead(bankButton);
  if (last != current) {
    delay(5);
    current = digitalRead(bankButton);
  }
  return current;
}
/* Program and Save Button Debounce */

boolean progdebounce(boolean last) {
  boolean current = digitalRead(progButton);
  if (last != current) {
    delay(5);
    current = digitalRead(progButton);
  }
  return current;
}

boolean savedebounce(boolean last) {
  boolean current = digitalRead(saveButton);
  if (last != current) {
    delay(5);
    current = digitalRead(saveButton);
  }
  return current;
}
/*********************************************************/
void midiProg(byte status, int data) 
 {
  Serial.write(status);
  Serial.write(data);
 }
 /*********************************************************/
void memory(int addr, int led)
{
  for(int ff=0; ff<numberOfPedal; ff++)
  {
    EEPROM.write((addr) + ff, digitalRead(effectLEDPin[ff]));
    digitalWrite(presetLEDPin[ff], HIGH); // turns off all preset LEDs
  }
  lcd.clear();
  lcd.print("Program saved to");
  lcd.setCursor(0, 1);
  lcd.print("Bank ");
  lcd.print(bank);
  lcd.print(" Preset ");
  lcd.print(led + 1);
  /* Preset LED will flash when saving effects loops */
  delay(100); 
  digitalWrite(presetLEDPin[led], LOW);
  delay(100); 
  digitalWrite(presetLEDPin[led], HIGH);
  delay(100);
  digitalWrite(presetLEDPin[led], LOW);
  delay(100); 
  digitalWrite(presetLEDPin[led], HIGH);
  delay(100);
  digitalWrite(presetLEDPin[led], LOW);
  delay(100); 
  digitalWrite(presetLEDPin[led], HIGH);
  delay(100);
  digitalWrite(presetLEDPin[led], LOW);
  delay(100);
  digitalWrite(presetLEDPin[led], HIGH);
}

/*********************************************************/
void resetAllRelays()
{
  for(int gg=0; gg<numberOfPedal; gg++)
  {
    digitalWrite(OneRelayPin[gg], HIGH);
    digitalWrite(TenRelayPin[gg], LOW);
  }
  delay(100);
  for(int hh=0; hh<numberOfPedal; hh++)
  {
    digitalWrite(TenRelayPin[hh], HIGH);
  }
}
/*********************************************************/
void resetAllLeds()
{
  for(int ii=0; ii<numberOfPedal; ii++)
  {
    digitalWrite(presetLEDPin[ii], HIGH);
  }
}
/*********************************************************/
void writeOut(int relay)
{
  resetAllLeds();
  digitalWrite(effectLEDPin[relay], !digitalRead(effectLEDPin[relay]));
  /*digitalWrite(ledPin[relay], !digitalRead(relayPin[relay]));
  /* thanks to  anton.efremoff.1 for this tip */
  lcd.clear();
  lcd.print("Current Bank: ");
  lcd.print(bank);
  lcd.setCursor(0, 1);
  lcd.print("Choose Loops: ");
  lcd.print(relay + 1);
}
/*********************************************************/
void readPreset(int addr, int pcNum, int led)
{
  for(int jj=0; jj<numberOfPedal; jj++)
  {
    digitalWrite(effectLEDPin[jj], EEPROM.read((addr)+jj));
    digitalWrite(presetLEDPin[jj], HIGH);
    digitalWrite(presetLEDPin[led], LOW);
    if (EEPROM.read((addr)+jj)) {  
      digitalWrite(OneRelayPin[jj], HIGH);
      digitalWrite(TenRelayPin[jj], LOW);
    }
    else {  
      digitalWrite(OneRelayPin[jj], LOW);
      digitalWrite(TenRelayPin[jj], HIGH);
    }
  }
  lcd.clear();
  lcd.print("             B-");
  lcd.print(bank);
  lcd.setCursor(0, 1);
  lcd.print("Preset ");
  lcd.print(led + 1);
  delay(100);
  for(int kk=0; kk<numberOfPedal; kk++)
  {
    digitalWrite(OneRelayPin[kk], HIGH);
    digitalWrite(TenRelayPin[kk], HIGH);
  }
}
  
/*********************************************************/
void loop()
{
  currentBankButton = bankdebounce(lastBankButton);
  if (lastBankButton == LOW && currentBankButton == HIGH) {
    bank ++;
    for (int zz = 0; zz < numberOfPedal; zz++) {
      digitalWrite(presetLEDPin[zz], HIGH); //turn OFF all preset LEDs
      digitalWrite(effectLEDPin[zz], HIGH);
    }
    lcd.clear();
    lcd.print("             B-");
    lcd.print(bank);
    lcd.setCursor(0, 1);
    lcd.print("Press Any Preset");
    if (bank >= numberOfBanks) {
      bank = 0;
    }
  }
  lastBankButton = currentBankButton;

/*
  currentProgButton = progdebounce(lastProgButton);
  if (lastProgButton == LOW && currentProgButton == HIGH) {
    if (progRelay == HIGH) {
      digitalWrite(progRelay, LOW);
      digitalWrite(progRelay, HIGH);
      lcd.clear();
      lcd.print("Bank ");
      lcd.print(bank);
      lcd.setCursor(0, 1);
      lcd.print("Press Any Preset");
    } else if (progRelay == LOW) {
      digitalWrite(progRelay, HIGH);
      digitalWrite(progRelay, HIGH);
      for (int m = 0; m < numberOfPedal; m++) {
        digitalWrite(presetLEDPin[m], HIGH);
        digitalWrite(effectLEDPin[m], HIGH);
      }
      lcd.clear();
      lcd.print("Current Bank: ");
      lcd.print(bank);
      lcd.setCursor(0, 1);
      lcd.print("Choose Loops: ");
//      lcd.print(relay + 1);
    }
  }
  lastProgButton = currentProgButton;

  currentSaveButton = savedebounce(lastSaveButton);
  if (lastSaveButton == LOW && currentSaveButton == HIGH) {
    if (saveRelay == HIGH) {
      digitalWrite(saveRelay, LOW);
      lcd.clear();
      lcd.print("Current Bank: ");
      lcd.print(bank);
      lcd.setCursor(0, 1);
      lcd.print("Select Preset");
    } else if (saveRelay == LOW) {
      digitalWrite(saveRelay, HIGH);
      for (int n = 0; n < numberOfPedal; n++) {
        digitalWrite(ledPin[n], HIGH);
        digitalWrite(presetLed[n], HIGH);
      }
      lcd.clear();
      lcd.print("Current Bank: ");
      lcd.print(bank);
      lcd.setCursor(0, 1);
      lcd.print("Choose Loops: ");
//      lcd.print(relay + 1);
    }
  }
  lastSaveButton = currentSaveButton;

*/

  char key = keypad.getKey();
  if(key)  // Check for a valid key.
  {
   switch (key)
      { 
    case 'a': writeOut(0); // relay
      break; 
    case 'b': writeOut(1);
      break;
    case 'c': writeOut(2);
      break;
    case 'd': writeOut(3);
      break;
    case 'e': writeOut(4);
      break;  
    /****************************** STORE PRESET MODE */       
//. case 'q': storePreset((bank * bankVariable), 0);
    case 'f': memory((bank * bankVariable), 0);  //addr, led
      break; 
    case 'g': memory(100 + (bank * bankVariable), 1);
      break;
    case 'h': memory(200 + (bank * bankVariable), 2);
      break;
    case 'i': memory(300 + (bank * bankVariable), 3);
      break;
    case 'j': memory(400 + (bank * bankVariable), 4);
      break;
    /****************************** READ PRESET MODE */      
    case 'k': readPreset((bank * bankVariable), 1, 0); // addr, pcNum, relay
      break; 
    case 'l': readPreset(100 + (bank * bankVariable), 2, 1);
      break;   
    case 'm': readPreset(200 + (bank * bankVariable), 3, 2);
      break;
    case 'n': readPreset(300 + (bank * bankVariable), 4, 3);
      break;
    case 'o': readPreset(400 + (bank * bankVariable), 5, 4);
      break;   
      }
   }
}

and here's a link to a working version of what I'm thinking: 3-loops-LCD - Wokwi ESP32, STM32, Arduino Simulator (you'll notice I put in the buttons and extra relays, but figured to ask before I went down that path)

You'll see that pins 5, 6 and 7 are the ones that accept information. Any guidance?

Do you need to turn the input off, ? Why not don't read it or just ignore it when it would not be appropriate to act on it

Hi there - and thanks for the reply!

The way it's working now is that the buttons all connect to each other and the common on the rotary switch. Then the 3 switch positions go to the inputs on the Arduino. So there's only data going into ONE input at a time because the physical rotary switch prevents the other pins from receiving data.

Since the same buttons are used for read, set and save, something is needed that tells which input to use (example, if it's read, then set/save should be off - if it's set, then read/save should be off, etc.)

So I could rephrase it as: I have 3 inputs, and I need 2 of them to NOT receive data at any given time, with the ability to switch which ones receive data or otherwise.

Does that clarify a bit?

That bit is easy. Just ignore or don't read the 2 inactive inputs. The problem is in selecting the active input

Keypad lib is good for a keypad where keys are in matrix. 3 buttons are not a matrix.
the reason of using of EEPROM is for me a mystery.
if i need feedback from my device i choose LED, if it is too much info to show then i choose LCD instead, not both.