Encoder button state

Hello,
i can’t figure it how can control 2 different variables:
fist one on 1st push of the encoder switch frqA = constrain(val2,0,1000)*4.096;
and the
second one on the 2nd push of the encoder. frqB = constrain(val2,0,1000);

and come back to 1

I did manage something to see the two states on the push of the encoder switch ont the 13D led but i don’t know what i have to add or combine to do the separate routines asked above for the variables.

I am using a teensy 3.2 or 3.6 btw

#include <Encoder.h>


Encoder myEnc(3, 4);
//const int Button = 5;

const int Button = 5;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

unsigned int buttonState      = 0;     // current state of the button
unsigned int lastButtonState  = 0;     // previous state of the button
unsigned int ledState         = 0;         // variable for reading the pushbutton status

unsigned int frqB;
unsigned int frqA;
int val2;


void setup() {
  pinMode(Button, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}


void loop() {
   buttonState = digitalRead(Button);

  val2 = myEnc.read(); //freqB of Wavetable **0 -> 2^32
    if(val2 <= 0) { // constrain for below 0
    myEnc.write(0); // constrain the encoder object
    }
    else if(val2 >= 1000){
    myEnc.write(1000); 
    }
    
      if (buttonState != lastButtonState) { //cond
        if (buttonState == 1) {
          if(ledState==1){                                   //1st push

                ledState =0; 
                frqA = constrain(val2,0,1000)*4.096;
      }
          else if(ledState==0){                            //2nd push

                ledState =1;  
                frqB = constrain(val2,0,1000);
      }
    }           
     lastButtonState = buttonState;

  }
  digitalWrite(ledPin, ledState);
  
   Serial.print("Status ");
   Serial.print(ledState);
   Serial.print(" Enc ");
   Serial.print(val2);
   Serial.print(" Encoder1: ");
   Serial.print(frqA);
   Serial.print(" Encoder2: ");
   Serial.println(frqB);
   
    delay(20);

}

Any advice?

Any advice?

Yes. The code does something. You forgot to tell us what it actually does.

You expect the cod to do something. Presumably, if what it actually does is what you expect, you would not post here claiming to have a problem. So, it is safe to assume that what it actually does is not what you want.

But, what DO you want it to do?

Yes, more details that i forgot :slight_smile:

I need it to control 2 different frequencies of two oscillators made by the teensy audio tool via a DAC.
so i aspect on the fist push to change only the frqA;
on the second push to change only the frqB;
and back again

so i aspect on the fist push to change only the ... on the second push to change only the

So, you are counting switch presses in a variable called ledState. How the hell does that name relate to what the value it contains represents?

What does the code ACTUALLY do?

I was doing it
This is supposed to do

  • ledState it's called as it will change the led 13 on and off to see if it's working
  • the encoder Encoder myEnc(3, 4); has the role to change the values of the val2 in the region of 0-1000;
  • Button (encoder switch) has the role to change between two cases 0 and 1 of the buttonState ;
  • After pressing the encoder, switching to 0 case has the role now to change the FrqA with the values form the encoder and is constrain the values
  • After pressing the encoder 2nd time, is switching to 1 case change FrqB with the values form the encoder is and constrain the final value

Now the code is not changing the values UNTIL i push down the encoder and it does for the frqA then frqB one after another without remembering the previous value of the frqA and then frqB. IF i change A its affects B and if i change B its affects A when i push the encoder to switch the case.

Now

I want to change the values of frqA ONLY in the 0 case (1st push) and 1 case (2nd push) for frqB
When i am back in case 0 i need the value that was there for the frqA left before 2nd push and the same for case 1, the value that was before 1st push (case 0) of the encoder.

Your code indentation is piss-poor. It is very hard to read your code. Use Tools + Auto Format so your code doesn't look like it was typed by a drunken monkey.

Put more Serial.print() statements in your code. Make certain that you are reading the switch correctly, and that the state changes ONLY when you actually push the switch.

Use names that make sense. Regardless of what you plan to do later, the ledState variable has a piss-poor name. It is NOT currently being used to hold the state of an LED.

Envision two modes. First mode uses encoder to move between A and B. This could be extended from A to n. When freq x (A or B) is selected, pressing the encoder switch toggles you out of moving from A and B and instead uses the encoder to adjust the frequency for whichever x is currently selected. Another press on the encoder switch toggles back to A-B (menu navigation) mode.

any example would be awesome :slight_smile:

vincentiu:
any example would be awesome :slight_smile:

Well, I don't have one in my back pocket just now but,

dougp:
Envision two modes. First mode uses encoder to move between A and B. This could be extended from A to n. When freq x (A or B) is selected, pressing the encoder switch toggles you out of moving from A and B and instead uses the encoder to adjust the frequency for whichever x is currently selected. Another press on the encoder switch toggles back to A-B (menu navigation) mode.

Using debouncing and state change detection (see examples in the IDE) create a boolean which toggles on and off as you press the switch. Say false is navigation mode, true is adjustment mode.

If you're in nav mode then encoder pulses inc/decrement a variable which selects the active parameter.

When the mode switch is pressed you enter adjustment mode and the encoder pulses now, instead inc/decrement another variable associated with the active parameter.

Once the parameter is set, switch back to nav mode and the parameter is held at its last value. At this point you could even save the value(s) to EEPROM for restoration at next power up.

If mode == 0 and encoder pulse, select next parameter

If (mode == 1 and encoder pulse and active parameter == 1) adjust parameter value no. 1

If (mode == 1 and encoder pulse and active parameter == 2) adjust parameter value no. 2

etc.

If you aren't into diving deep you could check out some libraries at the playground.

I have this version made which is working without keeping the values of the parameters as i switch between mode 1 and 0.

#include <Encoder.h>

Encoder myEnc(3, 4);
//const int Button = 5;

unsigned int frqB;
unsigned int frqA;
int val2;
int val3;


// this constant won't change:
const int  buttonPin = 5;    // the pin that the pushbutton is attached to
//const int ledPin = 13;       // the pin that the LED is attached to


// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
bool buttonState = false;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
 // initialize the button pin as a input:
 pinMode(buttonPin, INPUT_PULLUP);
 // initialize the LED as an output:
 //pinMode(ledPin, OUTPUT);
 // initialize serial communication:
 Serial.begin(9600);
}


void loop() {
 // read the pushbutton input pin:
 buttonState = digitalRead(buttonPin);

 // compare the buttonState to its previous state
 if (buttonState != lastButtonState) {
   // if the state has changed, increment the counter
   if (buttonState == true) {
     // if the current state is HIGH then the button
     // wend from off to on:
     buttonPushCounter++;
     if(buttonPushCounter>1)
     buttonPushCounter=0;
   } 
 }
 
 // save the current state as the last state, 
 //for next time through the loop
 lastButtonState = buttonState;

 
 // turns on the LED every four button pushes by 
 // checking the modulo of the button push counter.
 // the modulo function gives you the remainder of 
 // the division of two numbers:
 if (buttonPushCounter == 0) {
 
   val2 = myEnc.read(); //freqB of Wavetable **0 -> 2^32
   if(val2 <= 0) { // constrain for below 0
   myEnc.write(0); // constrain the encoder object
   }
   else if(val2 >= 1000){
   myEnc.write(1000); 
   }
   frqA = constrain(val2,0,1000)*4.096;

   
//   digitalWrite(ledPin, HIGH);
   
 } else if (buttonPushCounter == 1) {

   val3 = myEnc.read(); //freqB of Wavetable **0 -> 2^32
   if(val3 <= 0) { // constrain for below 0
   myEnc.write(0); // constrain the encoder object
   }
   else if(val3 >= 1000){
   myEnc.write(1000); 
   }
   frqB = constrain(val3,0,1000);
   
//   digitalWrite(ledPin, LOW);
 }
 
 Serial.print("Status ");
  Serial.print(buttonPushCounter);
  Serial.print(" Enc ");
  Serial.print(val2);
  Serial.print(" Enc2: ");
  Serial.print(val3);
  Serial.print(" FrqA: ");
  Serial.print(frqA);
  Serial.print(" FrqB: ");
  Serial.println(frqB);
 
}

I don’t know how to separate them somehow from the encoder physical position detent , any idea?

The encoder library you’re using emits four pulses for every detent. And you write to it. This messes with my head so I modified the encoder section to only produce a 1 (CCW) or a 2 (CW).

Try modifying the sketch using this approach. Hint: all the rest of the myEnc.xxx will go away.

/*
new variables:
byte encRot;

#define CCW 1
#define CW 2
*/
  //
  // detect encoder rotation and direction
  //
  encRot = 0; // reset any previous encoder signal

  // modulo operation allows response to only every
  // 4th encoder signal change (one physical detent)
  // encRot will = either CW or CCW for one program scan
  
  if (lastEncRead > myEnc.read()) {
    if (lastEncRead % 4 == 0) {
      encRot = CW;
    }
  }
  else if (lastEncRead < myEnc.read()) {
    if ( lastEncRead % 4 == 0) {
      encRot = CCW;
    }
  }
  lastEncRead = myEnc.read();

dougp:
The encoder library you’re using emits four pulses for every detent. And you write to it. This messes with my head so I modified the encoder section to only produce a 1 (CCW) or a 2 (CW).

Try modifying the sketch using this approach. Hint: all the rest of the myEnc.xxx will go away.

/*

new variables:
byte encRot;

#define CCW 1
#define CW 2
*/
  //
  // detect encoder rotation and direction
  //
  encRot = 0; // reset any previous encoder signal

// modulo operation allows response to only every
  // 4th encoder signal change (one physical detent)
  // encRot will = either CW or CCW for one program scan
 
  if (lastEncRead > myEnc.read()) {
    if (lastEncRead % 4 == 0) {
      encRot = CW;
    }
  }
  else if (lastEncRead < myEnc.read()) {
    if ( lastEncRead % 4 == 0) {
      encRot = CCW;
    }
  }
  lastEncRead = myEnc.read();

I did check it, but it’s suitable for me to keep the the code like that. I can divide the val3 number by 4 and i will have 1 number at on detent move. I did check the Encoder.h but it’s to complex to figure it out

Anyway… if you can guid me how to modify the code from above to keeping the values of the parameters as i switch between mode 0 and 1

vincentiu:
how to modify the code from above

There's a lot of above to choose from. Specify a particular post.

dougp:
There’s a lot of above to choose from. Specify a particular post.

Sure, for this

#include <Encoder.h>

Encoder myEnc(3, 4);
//const int Button = 5;

unsigned int frqB;
unsigned int frqA;
int val2;
int val3;


// this constant won't change:
const int  buttonPin = 5;    // the pin that the pushbutton is attached to
//const int ledPin = 13;       // the pin that the LED is attached to


// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
bool buttonState = false;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {

 pinMode(buttonPin, INPUT_PULLUP);
 
 Serial.begin(9600);
}


void loop() {
 // read the pushbutton input pin:
 buttonState = digitalRead(buttonPin);

 // compare the buttonState to its previous state
 if (buttonState != lastButtonState) {
   // if the state has changed, increment the counter
   if (buttonState == true) {
     // if the current state is HIGH then the button
     // wend from off to on:
     buttonPushCounter++;
     if(buttonPushCounter>1)
     buttonPushCounter=0;
   } 
 }
 
 // save the current state as the last state, 
 //for next time through the loop
 lastButtonState = buttonState;

////////// mode 0 - frqA parameter and mode 1 - frqB parameter ////////

 if (buttonPushCounter == 0) {
 
   val2 = myEnc.read(); //freqB of Wavetable **0 -> 2^32
   if(val2 <= 0) { // constrain for below 0
   myEnc.write(0); // constrain the encoder object
   }
   else if(val2 >= 1000){
   myEnc.write(1000); 
   }

   frqA = constrain(val2,0,1000)*4.096;

 } else if (buttonPushCounter == 1) {

   val3 = myEnc.read(); //freqB of Wavetable **0 -> 2^32
   if(val3 <= 0) { // constrain for below 0
   myEnc.write(0); // constrain the encoder object
   }
   else if(val3 >= 1000){
   myEnc.write(1000); 
   }

   frqB = constrain(val3,0,1000);
   
 }
 
 Serial.print("Status ");
  Serial.print(buttonPushCounter);
  Serial.print(" Enc ");
  Serial.print(val2);
  Serial.print(" Enc2: ");
  Serial.print(val3);
  Serial.print(" FrqA: ");
  Serial.print(frqA);
  Serial.print(" FrqB: ");
  Serial.println(frqB);
}

see the sequence after “////////// mode 0 - frqA parameter and mode 1 - frqB parameter ////////” comment

Your problem is due to the behavior of encoder.h . Namely, it retains its value through changes between buttonPushCounter = 0/1. So, as you have observed, val1 will assume the value of val2 and vice versa because - the first thing done in the adjustment code is to read the encoder.

To overcome this create a boolean one-shot. This is a bool value which will be true for only one program scan whenever the button is pressed. Refer to this modified bit extracted from your code.

  // read the pushbutton input pin:
  buttonOS = false;
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == true) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      buttonOS = true;

Now, when buttonOS is true write the previous value of val2/3, as the case may be, to the encoder. This will preset it to the value of interest.

i’ve tried it in different ways but i didn’t catch it.
I have to get rid of the counter part?
Maybe you can add the missing part, or if you have an analog potentiometer as an example it would be nice.

//#include <Encoder.h>

//Encoder myEnc(3, 4);
//const int Button = 5;

unsigned int Par1;
unsigned int Par2;
int val2;
int val3;
float volin;
float volin2;
const int  buttonPin = 5;    // the pin that the pushbutton is attached to
//const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
bool buttonState = false;         // current state of the button
int lastButtonState = 0;     // previous state of the button

float f;

void setup() {
//analogReadResolution(12);
pinMode(buttonPin, INPUT_PULLUP);
// pinMode(volin, A0);
 Serial.begin(9600);
}
bool buttonOS = false;

void loop() {
 // read the pushbutton input pin:
 buttonState = digitalRead(buttonPin);

 // compare the buttonState to its previous state
 if (buttonState != lastButtonState) {
   // if the state has changed, increment the counter
   if (buttonState == true) {
     // if the current state is HIGH then the button
     // wend from off to on:
     buttonPushCounter++;
     if(buttonPushCounter>1)
     buttonPushCounter=0;
      buttonOS = true;
   } 
 }
 

////////// mode 0 - frqA parameter and mode 1 - frqB parameter ////////

 if (buttonPushCounter == 0) {

int volin1 = analogRead(A0);

   Par1 = constrain(volin1,0,1000)*4.096;

 } else if (buttonPushCounter == 1) {

int volin2 = analogRead(A0);

   Par2 = constrain(volin2,0,1000);
   
 }
 
 Serial.print("Status ");
  Serial.print(buttonPushCounter);
 Serial.print(" Enc ");
  Serial.print(val2);
  Serial.print(" Enc2: ");
  Serial.print(val3);
  Serial.print(" FrqA: ");
  Serial.print(Par1);
  Serial.print(" FrqB: ");
  Serial.println(Par2);
}

vincentiu:
I have to get rid of the counter part?

No, the counter remains - it's your mechanism to select which value to change. Remember, you have two variables that have to share one encoder. What the one-shot does is reload the previous val2/3 *only once *when a new mode is selected. This becomes the current value of the encoder.

    if (buttonPushCounter == 0) {
      if (buttonOS) { // first time through since switch state change
        myEnc.write(val2);  // xfr previous value to encoder
      }
// other code to read encoder, constrain, etc.

OK! now it's working for mode 1, it's keeping the value from mode 1 as i change between modes, but it's changing the value from mode 0 when i press the switch.
For mode (buttonPushCounter == 1) is the same as above?

vincentiu:
For mode (buttonPushCounter == 1) is the same as above?

Yep.

here is how it works for mode 1 (buttonPushCounter == 1),
If i add the lines as i asked above it will stop working.

(buttonPushCounter == 1) {
     // if (buttonOS) { // first time through since switch state change
     // myEnc.write(val2);  // xfr previous value to encoder
    // }

all part

 if (buttonPushCounter == 0) {
      if (buttonOS) { // first time through since switch state change
        myEnc.write(val3);  // xfr previous value to encoder
      }
   val2 = myEnc.read(); //freqB of Wavetable **0 -> 2^32
   if(val2 <= 0) { // constrain for below 0
   myEnc.write(0); // constrain the encoder object
   }
   else if(val2 >= 1000){
   myEnc.write(1000); 
   }

   frqA = constrain(val2,0,1000)*4.096;

 } else if (buttonPushCounter == 1) {

     // if (buttonOS) { // first time through since switch state change
     // myEnc.write(val2);  // xfr previous value to encoder
    // }


   val3 = myEnc.read(); //freqB of Wavetable **0 -> 2^32
   if(val3 <= 0) { // constrain for below 0
   myEnc.write(0); // constrain the encoder object
   }
   else if(val3 >= 1000){
   myEnc.write(1000); 
   }
   frqB = constrain(val3,0,1000);
 }

the button it’s:

 buttonState = digitalRead(buttonPin);

 // compare the buttonState to its previous state
 if (buttonState != lastButtonState) {
   // if the state has changed, increment the counter
   if (buttonState == true) {
     // if the current state is HIGH then the button
     // wend from off to on:
     buttonPushCounter++;
       buttonOS = true;
     if(buttonPushCounter>1)
     buttonPushCounter=0;
   } 
 }