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