Counting button presses within a switch/case state.

Hi all,

Forgive the poor explanation of my problem but I'm really bad at programming.

I'm building a MIDI controller, based on a DUE. Even though it has plenty of pins, I managed to use almost all of them, and had to resort to this little trick:

Basically using an analog input and enough resistors in order to have as many push buttons as I need.

In one of these button arrays, say the one assigned to pin A1, I want to create a submenu, by that I mean the following:

The switch has 6 cases, or 6 buttons. Each one sends a MIDI note and prints a different menu on the lcd. In 2 cases, I would like to be able to have an additional submenu, and change the note/lcd every time the same button is pressed. I guess I'm looking for a state change scenario, but I have no idea how to implement it. Any help will be greatly appreciated.

Here's the code, stripped down to the bare minimum:

#include <MIDI_controller.h>

#include <MIDIUSB.h>

#include <LiquidCrystal.h>


#define VELOCITY          0b01111111  
#define LATCHTIME         100         

#define SPEED_MULTIPLY    1          
#define PULSES_PER_STEP   4           

#define ANALOG_AVERAGE    8           




const int buttonPin1 = A1;     


const int BUTTON1 = 1;
const int BUTTON2 = 2;
const int BUTTON3 = 3;
const int BUTTON4 = 4;
const int BUTTON5 = 5;
const int BUTTON6 = 6;

const int BUTTON1LOW = 970;
const int BUTTON1HIGH = 1024;
const int BUTTON2LOW = 750;
const int BUTTON2HIGH = 800;
const int BUTTON3LOW = 600;
const int BUTTON3HIGH = 660;
const int BUTTON4LOW = 400;
const int BUTTON4HIGH = 450;
const int BUTTON5LOW = 270;
const int BUTTON5HIGH = 320;
const int BUTTON6LOW = 50;
const int BUTTON6HIGH = 100;


// Variables will change:
int buttonState1;             // the current reading from the input pin
int lastButtonState1 = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime1 = 0;  // the last time the output pin was toggled
long debounceDelay1 = 50;    // the debounce time; increase if the output flickers


// initialize the library with the numbers of the interface pins for LCD
LiquidCrystal lcd(22, 24, 23, 25, 27, 29);

void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOff);
}


//_____________________________________________________________________________________________________________________________________________________________________________________________

void setup()
{

  //Serial.begin(9600);

  pinMode(buttonPin1, INPUT);


  // set up the LCD's number of columns and rows:
  lcd.begin(20, 2);
  // Print a message to the LCD.
  lcd.setCursor(0, 0); //position cursor
  lcd.print(" Cont   Pivot   Sat ");
  lcd.setCursor(0, 1); //position cursor
  lcd.print(" Hue   Lum Mix      ");



  USBMidiController.setDelay(15);  // wait 15 ms after each message not to flood the connection

  delay(1000);         // Wait a second...

}

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  MidiUSB.sendMIDI(event);

}


void loop() // Refresh all inputs
{

  // read the state of the switch into a local variable:
  int reading1 = analogRead(buttonPin1);
  //Serial.println(reading1);



  int tmpButtonState1 = LOW;             // the current reading from the input pin

  if (reading1 > BUTTON6LOW && reading1 < BUTTON6HIGH) {
    //Read switch 6
    tmpButtonState1 = BUTTON6;
  } else if (reading1 > BUTTON5LOW && reading1 < BUTTON5HIGH) {
    //Read switch 5
    tmpButtonState1 = BUTTON5;
  } else if (reading1 > BUTTON4LOW && reading1 < BUTTON4HIGH) {
    //Read switch 4
    tmpButtonState1 = BUTTON4;
  } else if (reading1 > BUTTON3LOW && reading1 < BUTTON3HIGH) {
    //Read switch 3
    tmpButtonState1 = BUTTON3;
  } else if (reading1 > BUTTON2LOW && reading1 < BUTTON2HIGH) {
    //Read switch 2
    tmpButtonState1 = BUTTON2;
  } else if (reading1 > BUTTON1LOW && reading1 < BUTTON1HIGH) {
    //Read switch 1
    tmpButtonState1 = BUTTON1;
  } else {
    //No button is pressed;
    tmpButtonState1 = LOW;
  }

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to a buttonState),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (tmpButtonState1 != lastButtonState1) {
    // reset the debouncing timer
    lastDebounceTime1 = millis();
  }

  if ((millis() - lastDebounceTime1) > debounceDelay1) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState1 = tmpButtonState1;
    // Serial.println(buttonState);
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState1 = tmpButtonState1;

  // set the LED using the state of the button for testing:
  switch (buttonState1) {

    case BUTTON1:
      lcd.setCursor(0, 0); //position cursor
      lcd.print(" Cont   Pivot   Sat ");
      lcd.setCursor(0, 1); //position cursor
      lcd.print(" Hue   Lum Mix      ");

      noteOn(0, 53, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 52, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 48, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 49, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 50, 64);
      MidiUSB.flush();
      delay(50);

      noteOff(0, 86, 64);  // B-S-M Submenu off
      MidiUSB.flush();
      delay(50);
      noteOff(0, 87, 64);   // Curves Submenu Off
      MidiUSB.flush();
      break;

    case BUTTON2:
      lcd.setCursor(0, 0); //position cursor
      lcd.print("Temp     Tint     MD");
      lcd.setCursor(0, 1); //position cursor
      lcd.print("Col Bst  Shad     HL");

      noteOn(0, 48, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 53, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 52, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 49, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 50, 64);
      MidiUSB.flush();
      delay(50);

      noteOff(0, 86, 64);  // B-S-M Submenu off
      MidiUSB.flush();
      delay(50);
      noteOff(0, 87, 64);   // Curves Submenu Off
      MidiUSB.flush();
      break;

    case BUTTON3:
      lcd.setCursor(0, 0); //position cursor
      lcd.print("Low      High       ");
      lcd.setCursor(0, 1); //position cursor
      lcd.print("L.S.     H.S.       ");

      noteOn(0, 87, 64);   // Curves Submenu On
      MidiUSB.flush();
      delay(20);
      noteOff(0, 87, 64);   // Curves Submenu Off
      MidiUSB.flush();
      delay(20);
      noteOff(0, 53, 64);
      MidiUSB.flush();
      delay(20);
      noteOff(0, 48, 64);
      MidiUSB.flush();
      delay(20);
      noteOff(0, 52, 64);
      MidiUSB.flush();
      delay(20);
      noteOff(0, 50, 64);
      MidiUSB.flush();
      delay(20);

      noteOff(0, 86, 64);  // B-S-M Submenu off
      MidiUSB.flush();
      break;

    case BUTTON4:
      lcd.setCursor(0, 0); //position cursor
      lcd.print("Size    Pan   Rotate");
      lcd.setCursor(0, 1); //position cursor
      lcd.print("Aspect Tilt  Opacity");

      noteOn(0, 50, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 53, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 48, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 52, 64);
      MidiUSB.flush();
      delay(50);

      noteOff(0, 86, 64);  // B-S-M Submenu off
      MidiUSB.flush();
      delay(50);
      noteOff(0, 87, 64);   // Curves Submenu Off
      MidiUSB.flush();
      break;

    case BUTTON5:
      lcd.setCursor(0, 0); //position cursor
      lcd.print("Radius H/V Rat  Scal");
      lcd.setCursor(0, 1); //position cursor
      lcd.print("Cor S   Level   Mix ");

      noteOn(0, 86, 64);   // B-S-M Submenu on
      MidiUSB.flush();
      delay(20);
      noteOff(0, 53, 64);
      MidiUSB.flush();
      delay(20);
      noteOff(0, 86, 64);  // B-S-M Submenu off
      MidiUSB.flush();
      delay(20);
      noteOff(0, 48, 64);
      MidiUSB.flush();
      delay(20);
      noteOff(0, 50, 64);
      MidiUSB.flush();
      delay(20);
      noteOff(0, 52, 64);
      MidiUSB.flush();
      delay(20);

      noteOff(0, 87, 64);   // Curves Submenu Off
      MidiUSB.flush();
      break;

    case BUTTON6:
      lcd.setCursor(0, 0); //position cursor
      lcd.print(" Pan    Tilt    Zoom");
      lcd.setCursor(0, 1); //position cursor
      lcd.print("Rotate  Width Height");

      noteOn(0, 52, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 53, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 48, 64);
      MidiUSB.flush();
      delay(50);
      noteOff(0, 50, 64);
      MidiUSB.flush();
      delay(50);

      noteOff(0, 86, 64);  // B-S-M Submenu off
      MidiUSB.flush();
      delay(50);
      noteOff(0, 87, 64);   // Curves Submenu Off
      MidiUSB.flush();
      break;
  }



}

In one of these button arrays, say the one assigned to pin A1

You can't assign an array to a pin, so, why don't you say something else?

const int BUTTON1 = 1;
const int BUTTON2 = 2;
const int BUTTON3 = 3;
const int BUTTON4 = 4;
const int BUTTON5 = 5;
const int BUTTON6 = 6;

When you starting adding numeric suffixes to variable names, it is a sure sign that you need an array.

  int tmpButtonState1 = LOW;             // the current reading from the input pin

That comment is nonsense. That is not at all what the code is doing.

The value that you then assign to the variable is a switch NUMBER, NOT a switch STATE.

buttonState1 does not contain a state, either.

With such meaningless names, it is impossible to figure out what your code is supposed to be doing. I gave up.

The whole switch/case part is pretty much copy/paste(comments included) from the instructable link I provided and seems to be doing its job fine.

I'll also copy/paste the first sentence of my post since you seemed to miss it: Forgive the poor explanation of my problem but I'm really bad at programming. Better said, I don't know how to code, only understand a few basic things.

If you're having a bad day I suggest you refrain from posting cause you come off as quite hostile(unless my understanding of English is not that good) and obviously not helpful at all.

I'll post the question in the instructable page, maybe it makes more sense.

In case someone here understands what I mean, here's the switch/case code straight from the instructable.

 /* 
  Debounce
  
  Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
  press), the output pin is toggled from LOW to HIGH or HIGH to LOW.  There's
  a minimum delay between toggles to debounce the circuit (i.e. to ignore
  noise).  
  
  created 28 October 2009
  by Riaan Cornelius
  
  
  */

 // constants won't change. They're used here to 
 // set pin numbers:
 const int buttonPin = 0;     // the number of the pushbutton pin
 const int ledPin =  13;      // the number of the LED pin for testing
 
 const int BUTTON1 = 1;
 const int BUTTON2 = 2;
 const int BUTTON3 = 3;
 const int BUTTON4 = 4;
 const int BUTTON5 = 5;
 
 const int BUTTON1LOW = 970;
 const int BUTTON1HIGH = 1024;
 const int BUTTON2LOW = 850;
 const int BUTTON2HIGH = 950;
 const int BUTTON3LOW = 700;
 const int BUTTON3HIGH = 800;
 const int BUTTON4LOW = 400;
 const int BUTTON4HIGH = 650;
 const int BUTTON5LOW = 250;
 const int BUTTON5HIGH = 350;
 
 // Variables will change:
 int ledState = HIGH;         // the current state of the output pin
 int buttonState;             // the current reading from the input pin
 int lastButtonState = LOW;   // the previous reading from the input pin

 // the following variables are long's because the time, measured in miliseconds,
 // will quickly become a bigger number than can be stored in an int.
 long lastDebounceTime = 0;  // the last time the output pin was toggled
 long debounceDelay = 50;    // the debounce time; increase if the output flickers

 void setup() {
   pinMode(buttonPin, INPUT);
   pinMode(ledPin, OUTPUT);
   Serial.begin(9600);
 }

 void loop() {
   // read the state of the switch into a local variable:
   int reading = analogRead(buttonPin);   
   int tmpButtonState = LOW;             // the current reading from the input pin
   
   if(reading>BUTTON5LOW && reading<BUTTON5HIGH){
     //Read switch 5
     tmpButtonState = BUTTON5;
   }else if(reading>BUTTON4LOW && reading<BUTTON4HIGH){
     //Read switch 4
     tmpButtonState = BUTTON4;
   }else if(reading>BUTTON3LOW && reading<BUTTON3HIGH){
     //Read switch 3
     tmpButtonState = BUTTON3;
   }else if(reading>BUTTON2LOW && reading<BUTTON2HIGH){
     //Read switch 2
     tmpButtonState = BUTTON2;
   }else if(reading>BUTTON1LOW && reading<BUTTON1HIGH){
     //Read switch 1
     tmpButtonState = BUTTON1;
   }else{
     //No button is pressed;
     tmpButtonState = LOW;
   }

   // check to see if you just pressed the button 
   // (i.e. the input went from LOW to a buttonState),  and you've waited 
   // long enough since the last press to ignore any noise:  

   // If the switch changed, due to noise or pressing:
   if (tmpButtonState != lastButtonState) {
     // reset the debouncing timer
     lastDebounceTime = millis();
   } 

   if ((millis() - lastDebounceTime) > debounceDelay) {
     // whatever the reading is at, it's been there for longer
     // than the debounce delay, so take it as the actual current state:
     buttonState = tmpButtonState;
     Serial.println(buttonState);
   }

   // save the reading.  Next time through the loop,
   // it'll be the lastButtonState:
   lastButtonState = tmpButtonState;
   
   // set the LED using the state of the button for testing:
   switch(buttonState){
     case BUTTON1:
     digitalWrite(ledPin, buttonState>0);
     break;
     case BUTTON2:
     digitalWrite(ledPin, buttonState>0);
     break;
     case BUTTON3:
     digitalWrite(ledPin, buttonState>0);
     break;
     case BUTTON4:
     digitalWrite(ledPin, buttonState>0);
     break;
     case BUTTON5:
     digitalWrite(ledPin, buttonState>0);
     break;
   }
 }

I'll give it a second try at explaining: Is there a way to have a couple of different if scenarios within, say BUTTON1?
eg. If BUTTON1 is pressed once, do this. If BUTTON1 is pressed twice, do that.

Thanks again.

I don't know how to code, only understand a few basic things.

Apparently, you are not interested in getting better, either.

If you're having a bad day I suggest you refrain from posting cause you come off as quite hostile

You haven't seen me anywhere NEAR hostile. Keep it up, and you will.

PaulS:
Apparently, you are not interested in getting better, either.

I never asked for someone to provide the code, only to show me the way to go since I clearly have no clue, I guess you didn't see that. Anyway, I got help elsewhere and I think I know how to approach the issue.

Thanks for the good times, you warm fuzzy creature, you.

petros00:
The switch has 6 cases, or 6 buttons. Each one sends a MIDI note and prints a different menu on the lcd. In 2 cases, I would like to be able to have an additional submenu,

You create a sub-menu the same way you made the first one. with another state machine.