Constraining Rotary Encoder Values

I found this (I think) brilliant bit of code for a rotary encoder by John Main.

#define CLK_PIN  2
#define DATA_PIN 7
#define YLED A1

////////////////////////////////////////////////////
void setup() {
   pinMode(CLK_PIN,INPUT);
   pinMode(DATA_PIN,INPUT);
   pinMode(YLED,OUTPUT);

   Serial.begin(9600);
   Serial.println("Rotary Encoder KY-040");
}

////////////////////////////////////////////////////
void loop() {
static uint16_t state=0,counter=0;

    delayMicroseconds(100); // Simulate doing somehing else as well.

    state=(state<<1) | digitalRead(CLK_PIN) | 0xe000;

    if (state==0xf000){
       state=0x0000;
       if(digitalRead(DATA_PIN))
         counter++;
       else
         counter--;
       Serial.println(counter);
    }
}


I modified it a little for my use.

#define CLK_PIN 2
#define DATA_PIN 3
#define SWITCH_PIN 4
int rpm = 0;

//Setup
void setup() {
  pinMode(CLK_PIN, INPUT);
  pinMode(DATA_PIN, INPUT);
  pinMode(SWITCH_PIN, OUTPUT);

  Serial.begin(9600);
  Serial.println("READY");
}

//
void loop() {
  static uint16_t state = 0, counter = 0;

  delayMicroseconds(100);  // Simulate doing something else as well.

  state = (state << 1) | digitalRead(CLK_PIN) | 0xe000; //Digital Debounce Filter

  if (state == 0xf000) {                                //61440
    state = 0x0000;                                     //0
    if (digitalRead(DATA_PIN))
      counter++;
    else
      counter--;
    rpm = counter * 25;
    if (rpm > 6000)
      rpm = 0;
    if (rpm > 500)
      rpm = 500;
    Serial.println(rpm);
  }
}

Lines 31 - 34 are an attempt to constrain the value of 'rpm' to between 0 and 500.
It doesn't work. Well, it sort of works but I need better than 'sort of'.
If I dial it down to 0 and keep going, it does indeed stay on zero. But, it saves those zeros up so if I want to increase the value I have to dial out all of those zeros before the value starts increasing again. :grimacing:
At the top end, it does the same thing in the opposite direction.
Suggestions please. :slightly_smiling_face:

It dawned on me that constraining rpm will never work. I need to constrain counter to a value between 0 and 20.
So far, I've gotten nowhere with that. :confused:

Please post your code effort to constrain the counter.

 pinMode(CLK_PIN, INPUT);
 pinMode(DATA_PIN, INPUT);

Do you have external pullups or pull downs on these inputs? Are you certain they are not floating?

I don't keep code that fails so I really don't have anything to show.
There are no external pullups.
The code works excellent until I try to constrain it.

I think this will work if counter becomes a signed variable

static uint16_t state = 0; //counter = 0;
static  int8_t  counter = 0;

Then

if (digitalRead(DATA_PIN))
      counter++;
    else
      counter--;
if(counter > 20) counter = 20;
if (counter < 0) counter = 0;
1 Like

That helped for counter > 20. I'd been trying something similar but got slightly weird results. The rpm count would increase to 525 then go to 475 on the way down. Goofy but acceptable. Your code gives the proper numbers.

The bigger problem is at counter < 0. Counter never gets to < 0 it goes to 65535 (x0FFFF).
It seems this code just goes around in a big circle (no negative numbers) . I tried counter = 65535 but that just returns a string of zeros. :grimacing:
At this point, I'm looking for a library that appeals to me. :wink:

I stand corrected. Changing to a signed variable does now, indeed, give me negative numbers. I was misreading the output. I think a bit more coding and I'll be where I'd like to be. I'll keep you updated. :grin:

Perfect, thank you. :grinning:


```cpp
#define CLK_PIN 2
#define DATA_PIN 3
#define SWITCH_PIN 4
int rpm = 0;

//Setup
void setup() {
  pinMode(CLK_PIN, INPUT);
  pinMode(DATA_PIN, INPUT);
  pinMode(SWITCH_PIN, OUTPUT);

  Serial.begin(9600);
  Serial.println("READY");
}
static uint16_t state = 0;
static int8_t counter = 0;

//
void loop() {

  delayMicroseconds(100);  // Simulate doing something else as well.

  state = (state << 1) | digitalRead(CLK_PIN) | 0xe000;  //Digital Debounce Filter
  if (state == 0xf000) {
    state = 0x0000;
    if (digitalRead(DATA_PIN))
      counter++;
    else
      counter--;
    if (counter > 20) counter = 20;
    if (counter < 0) counter = 0;
    rpm = counter * 25;
    if (rpm != 0)
      Serial.println(rpm);
    else
      Serial.println("READY");
  }
}

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