Button Up/Down has a quirk... Quick fix?

Hi everyone! I have another question about this dang switcher... but it's working pretty well at this stage!

The last real quirk revolves around the BANK button. I have setup 9 banks for storaging 9 presets each. Originally I had just one bank button, and it only went up - this worked well: when I pressed the button, the bank number went up.

Once I added a bank DOWN button, it's got some... quirks. First, if I immediately hit "down" it will go to Bank 0 - I'd like it to just go to bank 9 (I have no issue cycling through banks up or down). Second, if I immediate hit "up" it will just stay at bank 1 and won't go up until I hit the button a second time.

I've tried multiple configurations of if/then, etc., and nothing is QUITE fixing the issue.

Here's my project in simulator: https://wokwi.com/projects/386665695414235137

Here's my code for the buttons themselves:

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;

  currentDownButton = downdebounce(lastDownButton);
  if (lastDownButton == LOW && currentDownButton == 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 <= 1) {
      bank = numberOfBanks + 1;
    }
  }
  lastDownButton = currentDownButton;

And here's my FULL code:

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


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

# define rHot  LOW
# define rGnd HIGH

// WTF
void setupRelays();
void switchRelay(int, int);

const int bankButton = A15; //blue button
const int downButton = A12; //red button
int progButton = A14; //program button (green) - matches LED
int saveButton = A13; //save button (yellow) - matches LED
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 - grey colors */
//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. */
byte colPins[cols] = {46,48,44}; /* Green and Yellow Buttons - pin 44 is read/use, pin 46 is program/choose effects, pin 48 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 LED */
int TenRelayPin[3] = {11,12,13}; /* pin 10 on relay - reset/default has pin 10 at 5v - BLUE LED */
int presetLEDPin[3] = {A0,A1,A2}; /* shows which preset is engaged - GREEN LED */
int effectLEDPin[3] = {A3,A4,A5}; /* shows which effects are engaged - YELLOW LED */
int progRelay = 53;
int saveRelay = 51;

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 lastDownButton = LOW;
boolean currentDownButton = LOW;

boolean lastProgButton = LOW;
boolean currentProgButton = LOW;
boolean progOn = true;

boolean lastSaveButton = LOW;
boolean currentSaveButton = LOW;
boolean saveOn = true;


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

  setupRelays();  // pins and initial state

  for(int cc=0; cc<numberOfPedal; cc++) /* setup device */
  {
    pinMode(presetLEDPin[cc], OUTPUT);
    pinMode(effectLEDPin[cc], OUTPUT);
    digitalWrite(presetLEDPin[cc], LOW);
    digitalWrite(effectLEDPin[cc], LOW);
    delay(100);
  }
  delay(100);
  for(int ee=0; ee<numberOfPedal; ee++)
  {
    digitalWrite(presetLEDPin[ee], HIGH);
    digitalWrite(effectLEDPin[ee], HIGH);
    delay(100);
  }
  pinMode(progRelay,OUTPUT);
  pinMode(saveRelay,OUTPUT);
  digitalWrite(progRelay,LOW);
  digitalWrite(saveRelay,LOW);
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); */
   // initialize serial communication:
  Serial.begin(9600);
}
/* Bank Button Debounce */

boolean bankdebounce(boolean last) {
  boolean current = digitalRead(bankButton);
  if (last != current) {
    delay(5);
    current = digitalRead(bankButton);
  }
  return current;
}
boolean downdebounce(boolean last) {
  boolean current = digitalRead(downButton);
  if (last != current) {
    delay(5);
    current = digitalRead(downButton);
  }
  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);
  saveOn = !saveOn;
  delay(2000);
  lcd.clear();
  lcd.print("To Exit, Hit PRG");
  lcd.setCursor(0, 1);
  lcd.print("Or Choose Loops");
}

/*********************************************************/
void resetAllRelays()
{
  for (int ii = 0; ii < numberOfPedal; ii++)
    switchRelay(ii, LOW);     //... whatever the reset state is
}
/*********************************************************/
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);
    int kPreset = EEPROM.read((addr) + jj);
    switchRelay(jj, kPreset ? HIGH : LOW);
  }
    digitalWrite(presetLEDPin[led], LOW);
  
  lcd.clear();
  lcd.print("             B-");
  lcd.print(bank);
  lcd.setCursor(0, 1);
  lcd.print("Preset ");
  lcd.print(led + 1);
  delay(100);
}

/*********************************************************/
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;

  currentDownButton = downdebounce(lastDownButton);
  if (lastDownButton == LOW && currentDownButton == 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 <= 1) {
      bank = numberOfBanks + 1;
    }
  }
  lastDownButton = currentDownButton;

  currentProgButton = progdebounce(lastProgButton);
  if (lastProgButton == LOW && currentProgButton == HIGH) {
    progOn = !progOn;
    if (progOn == HIGH){
    lcd.clear();
    lcd.print("Program Mode:");
    lcd.setCursor(0, 1);
    lcd.print("Select Loops");
    } else {
    lcd.clear();
    lcd.print("             B-");
    lcd.print(bank);
    lcd.setCursor(0, 1);
    lcd.print("Press Any Preset");
    if (bank >= numberOfBanks) {
      bank = 0;
    }
    }
  }
  lastProgButton = currentProgButton;
  digitalWrite(progRelay, progOn);
  

  currentSaveButton = savedebounce(lastSaveButton);
  if (lastSaveButton == LOW && currentSaveButton == HIGH) {
    saveOn = !saveOn;
    if (saveOn == HIGH){
    lcd.clear();
    lcd.print("Save Mode:");
    lcd.setCursor(0, 1);
    lcd.print("Select Preset");
    } 
  }
  lastSaveButton = currentSaveButton;
  digitalWrite(saveRelay, saveOn);
   

  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;   
      }
   }
}

void setupRelays()
{
  for (int ii = 0; ii < numberOfPedal; ii++) {
    //digitalWrite(OneRelayPin[ii], LOW);
    //digitalWrite(TenRelayPin[ii], LOW);   // they will be, but here explicitly so no one wonders

    pinMode(OneRelayPin[ii], OUTPUT);
    pinMode(TenRelayPin[ii], OUTPUT);

    initRelay(ii, LOW); // HIGH or LOW as desired
  }
}

void setupRelays(); 

// this driver
// gives him a little jolt left to right, or right to left. careful how you fix things, think it out
void switchRelay(int relayNumber, int onOff)
{
  if (onOff) {  // close the contacts current flows 1 to 10
    digitalWrite(OneRelayPin[relayNumber], rHot);
    digitalWrite(TenRelayPin[relayNumber], rGnd);
  }
  else {  // open the contacts
    digitalWrite(TenRelayPin[relayNumber], rHot);
    digitalWrite(OneRelayPin[relayNumber], rGnd);
  }

  // if we have additional tell-tale lamps for the relays
  //    digitalWrite(tellTale[relayNumber], onOff ? HIGH : LOW);

//  delay(7);    // give peace a chance. implement the "stab" function

  //delay(75);    // let us see the pulse for now

  digitalWrite(OneRelayPin[relayNumber], rGnd);
  digitalWrite(TenRelayPin[relayNumber], rGnd);      // always return to
}

void initRelay(int relayNumber, int onOff)
{
  if (onOff) {  // close the contacts current flows 1 to 10
    digitalWrite(OneRelayPin[relayNumber], rHot);
    digitalWrite(TenRelayPin[relayNumber], rGnd);
  }
  else {  // open the contacts
    digitalWrite(TenRelayPin[relayNumber], rHot);
    digitalWrite(OneRelayPin[relayNumber], rGnd);
  }
    delay (50);

  // if we have additional tell-tale lamps for the relays
  //    digitalWrite(tellTale[relayNumber], onOff ? HIGH : LOW);

//  delay(7);    // give peace a chance. implement the "stab" function

  //delay(500);    // let us see the pulse for now

  digitalWrite(OneRelayPin[relayNumber], rGnd);
  //delay(100);
  digitalWrite(TenRelayPin[relayNumber], rGnd);      // always return to
  //delay(100);    // let us see the pulse for now
}

Any thoughts? Thank you in advance!

not sure what this is doing. shouldn't last be set to current, but then isn't last being used in all your debounce routines?

buttons are typically connected between the pin and ground, the pin configured as INPUT_PULLUP to use the internal pullup resistor which pulls the pin HIGH and when pressed, the button pulls the pin LOW.

a button press can be recognized by detecting a change in state and becoming LOW

look this over

// check multiple buttons and toggle LEDs

enum { Off = HIGH, On = LOW };

byte pinsLed [] = { 10, 11, 12 };
byte pinsBut [] = { A1, A2, A3 };
#define N_BUT   sizeof(pinsBut)

byte butState [N_BUT];

// -----------------------------------------------------------------------------
int
chkButtons ()
{
    for (unsigned n = 0; n < sizeof(pinsBut); n++)  {
        byte but = digitalRead (pinsBut [n]);

        if (butState [n] != but)  {
            butState [n] = but;

            delay (10);     // debounce

            if (On == but)
                return n;
        }
    }
    return -1;
}

// -----------------------------------------------------------------------------
void
loop ()
{
    switch (chkButtons ())  {
    case 2:
        digitalWrite (pinsLed [2], ! digitalRead (pinsLed [2]));
        break;

    case 1:
        digitalWrite (pinsLed [1], ! digitalRead (pinsLed [1]));
        break;

    case 0:
        digitalWrite (pinsLed [0], ! digitalRead (pinsLed [0]));
        break;
    }
}

// -----------------------------------------------------------------------------
void
setup ()
{
    Serial.begin (9600);

    for (unsigned n = 0; n < sizeof(pinsBut); n++)  {
        pinMode (pinsBut [n], INPUT_PULLUP);
        butState [n] = digitalRead (pinsBut [n]);
    }

    for (unsigned n = 0; n < sizeof(pinsLed); n++)  {
        digitalWrite (pinsLed [n], Off);
        pinMode      (pinsLed [n], OUTPUT);
    }
}

Read the code.

This

  currentDownButton = downdebounce(lastDownButton);

is how the debounce family of functions is called. Yes, a bit unconventional.

@greysun the simulation you linked doesn't seem to malfuntcion and it doesn't use downdebounce() at all.

Can you set it up so we don't have to figure out how to see it not work as you are seeing it not work?

And since it does work with all that stuff commented out, why are you messing with it at this time? Just curious - there are lotsa reasons to change the sketch around how it does all the buttons there are.

a7

  • it reads the button twice,
  • it calls a delay if changed
  • and uses the same last for all buttons

and in the function calling it there another check if the state has changed using lastDownButton

what's the "thinking" behind this and is it really doing what's intended

Hi everyone! Thank you @gcjr and @alto777 - but after looking at my physical stomp box that I laid out many years back, I miscounted the number of switches I have available - I only have one button for a bank, so I'm doing away with the down button altogether.

Thanks for the help, but it's moot, so I'll shut this thread down. :slight_smile:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.