Rotary encoder menu system

Thanks for the help! That does indeed seem to get the button press registering only once.

I now have another issue. In each menu case I want the serial monitor to be updated when I move the rotary encoder. So I added 'updateDisplay' inside each if statement - a void I wrote at the bottom of the code. See line 92 and line 97 for example.

This works okay, until I add the same to case 2 and case 3. This way regardless of which case I am in, it posts to the serial monitor as many times as I have cases. I thought only code within the active case is run?

This code only prints once, but when I change case I then get no serial monitor output.

// Rotary encoder variables
const byte inputCLK = 3; // Arduino pin the rotary encoder CLK pin is connected to.
const byte inputDT = 2; // Arduino pin the rotary encoder DT pin is connected to.
int currentStateCLK; // Current state of rotary encoder pin CLK. Used to identify rotation.
int previousStateCLK; // Current state of rotary encoder pin CLK. Used to identify rotation.
boolean encCCW; // Rotary encoder flag to denote counter-clockwise rotatation by one pulse.
boolean encCW; // Rotary encoder flag to denote clockwise rotatation by one pulse.

// Push button variables
const byte buttonPin = 4; // Arduino pin the push button is connected to.
byte previousButtonState = HIGH;  // Assume switch open because of pull-up resistor.
byte currentButtonState; // Will be populated by reading button pin satae.
const unsigned long debounceTime = 5;  // Milliseconds of debounce.
unsigned long buttonPressTime;  // Time since button last changed state. Used to differentialte button bounce vs. intentional press.
boolean buttonPressed = 0; // A flag variable to identify button presses. Returned from button debounce code. 

// Menu mode change variables
int mode = 1;  // Mode variable used to run switch case. 1 = volume, 2 = audio input, 3 = tone control.
int currentInputNumber = 1; // Audio input the system is currently set to.
int newInputNumber = 1; // Audio input user is in the process of choosing by rotary control.
int currentToneValue = 5; // Current tone control setting.
int newToneValue = 5; // Tone control setting the user is in the process of choosing by rotary control.

// Gain variables 
float volume; // Volume level in dB.
float linGain; // Volume level as a linear gain value between 0 (no level) and 1 (full level).
uint32_t vol32; // Linear gain as a 32 bit word to populate hex array.
byte volArray[4]; // 4 byte array to hold volume hex values ready to send over I2C to the audio processor.

void setup() { 
    
 volume = -45; // Set default volume level to -45dB.
    
 // Set encoder and push button pins as inputs.  
 pinMode (inputCLK,INPUT);
 pinMode (inputDT,INPUT);
 pinMode (buttonPin, INPUT_PULLUP);
 encCCW = 0; // Initial state for rotation flag not rotated.
 encCW = 0; // Initial state for rotation flag not rotated.
 previousStateCLK = digitalRead(inputCLK); // Read initial state of rotary encoder CLK pin. Assign to previousStateCLK so we can check for state changes.
 
 // Setup Serial Monitor
 Serial.begin (9600);
} 

void loop() {

  // Rotary encoder code.
  currentStateCLK = digitalRead(inputCLK); // Read the current state of inputCLK pin.

  if (currentStateCLK != previousStateCLK) { // If the previous and the current state of inputCLK are different, then the encoder and been rotated.
    if (currentStateCLK != digitalRead(inputDT)) { // If the inputCLK state is different than the inputDT state then the rotation is counterclockwise.
      encCCW = 1; // Set rotation flag counter-clockwise.
    }
    else { // If inputCLK and inputDT are the same then encoder is not rotating CCW.
      encCW = 1; // Set rotation flag clockwise.
    }
  }

  // Button press code with debounce.
  currentButtonState = digitalRead (buttonPin); 
  if (currentButtonState != previousButtonState){
    if (millis () - buttonPressTime >= debounceTime){ // debounce
      buttonPressTime = millis ();  // when we closed the switch 
      previousButtonState = currentButtonState;  // remember for next time 
      if (currentButtonState == LOW){ // When debounce criteria are met and button is still pressed.
        buttonPressed = 1; // Set button flag to 1.
      }
    }
  }

  // Limit Mode (menu page) and loop back to main menu.
  if (mode >= 4){
   mode = 1; 
  }
 
  // Convert dB volume level to hex array for sending by I2C to the audio processor.
  linGain = pow(10, volume/20); // Convert dB level to linear gain value.
  vol32 = linGain * 16777216; // Convert linear gain value stored as a float variable to a 32 bit integer.
  volArray[0] = (vol32 >> 24) & 0xFF; // Populate first byte of array with most significant 8 bits of the 32 bit volume word, by shifting word right by 24 bits. Adding 0xFF denotes it as a hex value.
  volArray[1] = (vol32 >> 16) & 0xFF; // Populate second byte of array with next most significant 8 bits of the 32 bit volume word, by shifting word right by 16 bits. Adding 0xFF denotes it as a hex value.
  volArray[2] = (vol32 >> 8) & 0xFF; // Populate third byte of array with next most significant 8 bits of the 32 bit volume word, by shifting word right by 8 bits. Adding 0xFF denotes it as a hex value.
  volArray[3] = vol32 & 0xFF; // Populate fourth byte of array with least significant 8 bits of the 32 bit volume word, naturally the first 8 bits of the word. Adding 0xFF denotes it as a hex value.
        

  switch (mode) { // Each menu page is a case operated by the 'mode' variable.
   
    case 1: // Main menu page, volume control.
     
      if (encCCW == 1) { // If the rotary encoder has been rotated counter-clockwise.
       volume --; // Decrement volume level by one. 
       updateDisplay(); 
      }

      if (encCW == 1) { // If the rotary encoder has been rotated clockwise.
        volume ++; // Increment volume level by one.   
        updateDisplay(); 
      }

      if (buttonPressed == 1) {
        mode = mode + 1 ; // If the button is pressed while on the main volume page (case 1), the menu progresses to the next page (case 2).
      }

  buttonPressed = 0;
   
    // End of case 1.
      
    case 2:
     
      if (encCCW == 1) { // If the rotary encoder has been rotated counter-clockwise.
        newInputNumber -= 1; // subtract 1 from input number.
      }

      if (encCW == 1) { // If the rotary encoder has been rotated clockwise.
        newInputNumber += 1; // Add 1 to the input number. 
      }

      if (newInputNumber >= 6){ // If input number is more than 5 then loop back to 1.
         newInputNumber = 1;
      }

      if (newInputNumber <= 0){ // If input number is less than 1 then loop back to 5.
        newInputNumber = 5;
      }   

      if (buttonPressed == 1) {
        if(newInputNumber == currentInputNumber){ // If the button is pressed without changing input selection.
         mode = mode + 1 ; // Increment mode by 1 to progress to the next menu page.
        }

        else{ // A new audio input is being selected.
         currentInputNumber = newInputNumber; // Set the current audio input to the new selection.
         mode = 1; // Go back to the main menu page (case 1)

        }
      }

  buttonPressed = 0;
    // End of case 2.
    
    case 3:
     
      if (encCCW == 1) { // If the rotary encoder has been rotated counter-clockwise.
        newToneValue -= 1; // subtract 1 from tone value.
      }

      if (encCW == 1) { // If the rotary encoder has been rotated clockwise.
        newToneValue += 1; // Add 1 to the tone value. 
      }

      if (newToneValue >= 10){ // If tone value is more than 9.
        newToneValue = 9; // Limit tone value to 9.
      }

      if (newToneValue <= 0){ // If tone value is less than 1.
        newToneValue = 1; // Limit tone value to 1.
      }   

      if (buttonPressed == 1) {
        if(newToneValue == currentToneValue){ // If the button is pressed without changing input selection.
         mode = 1 ; // Go back to the main menu page, because this is the last menu.
        }

        else{ // A new tone value has been selected.
         currentToneValue = newToneValue; // Set the current tone value to the new tone value.
         mode = 1; // Go back to the main menu page (case 1).
        }
      }
  buttonPressed = 0;
    // End of case 3.

  } // End of switch.

  // Rotary encoder reset for next loop around.  
  previousStateCLK = currentStateCLK; // Update previousStateCLK with the current state of inputCLK.
  encCCW = 0; // Reset encoder counter-clockwise flag.
  encCW = 0; // Reset encoder clockwise flag.

} // end of loop.

void updateDisplay(){ // Display the menu mode, volume level and current audio input.
  Serial.print("Mode:");
  Serial.println(mode);
  Serial.print("Volume: ");
  Serial.print(volume);
  Serial.println("dB");
  Serial.print("Current Input Number:");
  Serial.println(currentInputNumber);
  Serial.print("New Input Number:");
  Serial.println(newInputNumber);
  Serial.print("Current Tone Control Value:");
  Serial.println(currentToneValue);
  Serial.print("New Tone Control Value:");
  Serial.println(newToneValue);
  Serial.println();
}

This code outputs serial monitor in each case, but it does it 3 times regardless of which case is running!

// Rotary encoder variables
const byte inputCLK = 3; // Arduino pin the rotary encoder CLK pin is connected to.
const byte inputDT = 2; // Arduino pin the rotary encoder DT pin is connected to.
int currentStateCLK; // Current state of rotary encoder pin CLK. Used to identify rotation.
int previousStateCLK; // Current state of rotary encoder pin CLK. Used to identify rotation.
boolean encCCW; // Rotary encoder flag to denote counter-clockwise rotatation by one pulse.
boolean encCW; // Rotary encoder flag to denote clockwise rotatation by one pulse.

// Push button variables
const byte buttonPin = 4; // Arduino pin the push button is connected to.
byte previousButtonState = HIGH;  // Assume switch open because of pull-up resistor.
byte currentButtonState; // Will be populated by reading button pin satae.
const unsigned long debounceTime = 5;  // Milliseconds of debounce.
unsigned long buttonPressTime;  // Time since button last changed state. Used to differentialte button bounce vs. intentional press.
boolean buttonPressed = 0; // A flag variable to identify button presses. Returned from button debounce code. 

// Menu mode change variables
int mode = 1;  // Mode variable used to run switch case. 1 = volume, 2 = audio input, 3 = tone control.
int currentInputNumber = 1; // Audio input the system is currently set to.
int newInputNumber = 1; // Audio input user is in the process of choosing by rotary control.
int currentToneValue = 5; // Current tone control setting.
int newToneValue = 5; // Tone control setting the user is in the process of choosing by rotary control.

// Gain variables 
float volume; // Volume level in dB.
float linGain; // Volume level as a linear gain value between 0 (no level) and 1 (full level).
uint32_t vol32; // Linear gain as a 32 bit word to populate hex array.
byte volArray[4]; // 4 byte array to hold volume hex values ready to send over I2C to the audio processor.

void setup() { 
    
 volume = -45; // Set default volume level to -45dB.
    
 // Set encoder and push button pins as inputs.  
 pinMode (inputCLK,INPUT);
 pinMode (inputDT,INPUT);
 pinMode (buttonPin, INPUT_PULLUP);
 encCCW = 0; // Initial state for rotation flag not rotated.
 encCW = 0; // Initial state for rotation flag not rotated.
 previousStateCLK = digitalRead(inputCLK); // Read initial state of rotary encoder CLK pin. Assign to previousStateCLK so we can check for state changes.
 
 // Setup Serial Monitor
 Serial.begin (9600);
} 

void loop() {

  // Rotary encoder code.
  currentStateCLK = digitalRead(inputCLK); // Read the current state of inputCLK pin.

  if (currentStateCLK != previousStateCLK) { // If the previous and the current state of inputCLK are different, then the encoder and been rotated.
    if (currentStateCLK != digitalRead(inputDT)) { // If the inputCLK state is different than the inputDT state then the rotation is counterclockwise.
      encCCW = 1; // Set rotation flag counter-clockwise.
    }
    else { // If inputCLK and inputDT are the same then encoder is not rotating CCW.
      encCW = 1; // Set rotation flag clockwise.
    }
  }

  // Button press code with debounce.
  currentButtonState = digitalRead (buttonPin); 
  if (currentButtonState != previousButtonState){
    if (millis () - buttonPressTime >= debounceTime){ // debounce
      buttonPressTime = millis ();  // when we closed the switch 
      previousButtonState = currentButtonState;  // remember for next time 
      if (currentButtonState == LOW){ // When debounce criteria are met and button is still pressed.
        buttonPressed = 1; // Set button flag to 1.
      }
    }
  }

  // Limit Mode (menu page) and loop back to main menu.
  if (mode >= 4){
   mode = 1; 
  }
 
  // Convert dB volume level to hex array for sending by I2C to the audio processor.
  linGain = pow(10, volume/20); // Convert dB level to linear gain value.
  vol32 = linGain * 16777216; // Convert linear gain value stored as a float variable to a 32 bit integer.
  volArray[0] = (vol32 >> 24) & 0xFF; // Populate first byte of array with most significant 8 bits of the 32 bit volume word, by shifting word right by 24 bits. Adding 0xFF denotes it as a hex value.
  volArray[1] = (vol32 >> 16) & 0xFF; // Populate second byte of array with next most significant 8 bits of the 32 bit volume word, by shifting word right by 16 bits. Adding 0xFF denotes it as a hex value.
  volArray[2] = (vol32 >> 8) & 0xFF; // Populate third byte of array with next most significant 8 bits of the 32 bit volume word, by shifting word right by 8 bits. Adding 0xFF denotes it as a hex value.
  volArray[3] = vol32 & 0xFF; // Populate fourth byte of array with least significant 8 bits of the 32 bit volume word, naturally the first 8 bits of the word. Adding 0xFF denotes it as a hex value.
        

  switch (mode) { // Each menu page is a case operated by the 'mode' variable.
   
    case 1: // Main menu page, volume control.
     
      if (encCCW == 1) { // If the rotary encoder has been rotated counter-clockwise.
       volume --; // Decrement volume level by one. 
       updateDisplay(); 
      }

      if (encCW == 1) { // If the rotary encoder has been rotated clockwise.
        volume ++; // Increment volume level by one.   
        updateDisplay(); 
      }

      if (buttonPressed == 1) {
        mode = mode + 1 ; // If the button is pressed while on the main volume page (case 1), the menu progresses to the next page (case 2).
      }

  buttonPressed = 0;
   
    // End of case 1.
      
    case 2:
     
      if (encCCW == 1) { // If the rotary encoder has been rotated counter-clockwise.
        newInputNumber -= 1; // subtract 1 from input number.
        updateDisplay();
      }

      if (encCW == 1) { // If the rotary encoder has been rotated clockwise.
        newInputNumber += 1; // Add 1 to the input number. 
       updateDisplay();
      }

      if (newInputNumber >= 6){ // If input number is more than 5 then loop back to 1.
         newInputNumber = 1;
      }

      if (newInputNumber <= 0){ // If input number is less than 1 then loop back to 5.
        newInputNumber = 5;
      }   

      if (buttonPressed == 1) {
        if(newInputNumber == currentInputNumber){ // If the button is pressed without changing input selection.
         mode = mode + 1 ; // Increment mode by 1 to progress to the next menu page.
        }

        else{ // A new audio input is being selected.
         currentInputNumber = newInputNumber; // Set the current audio input to the new selection.
         mode = 1; // Go back to the main menu page (case 1)

        }
      }

  buttonPressed = 0;
    // End of case 2.
    
    case 3:
     
      if (encCCW == 1) { // If the rotary encoder has been rotated counter-clockwise.
        newToneValue -= 1; // subtract 1 from tone value.
        updateDisplay();
      }

      if (encCW == 1) { // If the rotary encoder has been rotated clockwise.
        newToneValue += 1; // Add 1 to the tone value. 
        updateDisplay();
      }

      if (newToneValue >= 10){ // If tone value is more than 9.
        newToneValue = 9; // Limit tone value to 9.
      }

      if (newToneValue <= 0){ // If tone value is less than 1.
        newToneValue = 1; // Limit tone value to 1.
      }   

      if (buttonPressed == 1) {
        if(newToneValue == currentToneValue){ // If the button is pressed without changing input selection.
         mode = 1 ; // Go back to the main menu page, because this is the last menu.
        }

        else{ // A new tone value has been selected.
         currentToneValue = newToneValue; // Set the current tone value to the new tone value.
         mode = 1; // Go back to the main menu page (case 1).
        }
      }
  buttonPressed = 0;
    // End of case 3.

  } // End of switch.

  // Rotary encoder reset for next loop around.  
  previousStateCLK = currentStateCLK; // Update previousStateCLK with the current state of inputCLK.
  encCCW = 0; // Reset encoder counter-clockwise flag.
  encCW = 0; // Reset encoder clockwise flag.

} // end of loop.

void updateDisplay(){ // Display the menu mode, volume level and current audio input.
  Serial.print("Mode:");
  Serial.println(mode);
  Serial.print("Volume: ");
  Serial.print(volume);
  Serial.println("dB");
  Serial.print("Current Input Number:");
  Serial.println(currentInputNumber);
  Serial.print("New Input Number:");
  Serial.println(newInputNumber);
  Serial.print("Current Tone Control Value:");
  Serial.println(currentToneValue);
  Serial.print("New Tone Control Value:");
  Serial.println(newToneValue);
  Serial.println();
}