Code for rotary encoder not working as expected, any solutions?

Hi there,

I'm writing code for a pair of glasses that use an ultrasonic sensor to beep if an object is nearby in a particular range. In the glasses, the range can be set with a rotary encoder.
Here's the problem: the rotary encoder values are increasing even when I turn it the other way. I checked, and the rotary encoder is not the problem because I tried with the code provided on the general electronics website and the encoder works as it should. It's only not working with this code of mine. I even checked by isolating the function I wrote to handle the encoder (getRotValues) and that function is not the problem as in a new code base it works just fine. I would appreciate any help.
Here is the code:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 12 
Adafruit_SSD1306 display(OLED_RESET);

// battery indicator definition
#define battery A3   
//Ultrasonic sensor definition
#define trig 11
#define echo 10
//buzzer difinition
#define Buzz 4
//colour definitions
#define red 6
#define blue 7
#define green 8
//Encoder definitions
#define CLK 3
#define DT 2
#define mute 5
//A4 and A5 are SDA and SCL


float dist=0;
int Time=0;
int maxDist=275; // in Centimeters
int counter=0;
int cCLK;
int pCLK;
int potLim=0;
int potVal=0;
int buzzVal;
bool isMute;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
pinMode(trig,OUTPUT);
pinMode(echo,INPUT);
pinMode(Buzz,OUTPUT);
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(mute,INPUT);
pinMode(red,OUTPUT);
pinMode(blue,OUTPUT);
pinMode(green,OUTPUT);
pinMode(battery,INPUT);
pCLK=digitalRead(CLK);

  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(0.5);
  display.setTextColor(WHITE);
SendRecieve();
Intro();
delay(1000);
}
void batteryCheck() {
  int censorValue=analogRead(battery);
  float voltage=censorValue * (4.2/1023.0);
  float limit=4.2-2.4;
  float percentage=((4.2-limit)/2.4)*100;
  if((100-percentage)>=75) {
    digitalWrite(red,1);
    digitalWrite(blue,1);
    digitalWrite(green,0);
  }
  else if((100-percentage)>=50) {
digitalWrite(red,1);
digitalWrite(blue,0);
digitalWrite(green,1);
  }
  else if((100-percentage)>=25) {
    digitalWrite(red,0);
    digitalWrite(blue,1);
    digitalWrite(green,0);

  }
  else {
    digitalWrite(red,1);
    digitalWrite(blue,1);
    digitalWrite(green,0);
  }
}

void Intro(){
  display.setTextSize(1);
  display.setCursor(15,12);
  display.print("LGBTQ+ CHASHME!!");
  display.display();
  delay(2000);
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(0,0);
  display.print("By");
  display.setTextSize(2);
  display.setCursor(0,16);
  display.print("PhoenoPav");
  display.setTextSize(1);

  display.display();
  delay(2000);
for (int i=0; i<100; i++) {
  digitalWrite(Buzz,1);
  delay(10);
  digitalWrite(Buzz,0);
}
    }
void SendRecieve(){
  digitalWrite(trig,0);
  delay(3);
  digitalWrite(trig,1);
  delay(3);
  digitalWrite(trig,0);
  Time=pulseIn(echo,HIGH);
  dist=(Time*0.0344)/2;// for cm
//if (dist<0) {
//dist*=-1;
//}
  Serial.print("Distance: "); Serial.print(dist); Serial.print(" ");

}
void Beep(){
  buzzVal=map(dist,0,maxDist,0,100);
  for(int i=0;i<10;i++){
    digitalWrite(Buzz,1);
    delay(buzzVal);
    digitalWrite(Buzz,0);
    delay(buzzVal);
  }
}
void getRotValues() {
  cCLK=digitalRead(CLK);
  if(pCLK!=cCLK) {
    if(digitalRead(DT)!=cCLK) {
      counter--;
      if(counter<=0) {
        counter=0;
      }
    }
    else {
      counter++;
      if(counter>=maxDist) {
        counter=maxDist;
      }
    }
  }
potLim=counter;
pCLK=cCLK;
}

void Print(){
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("Max Distance: "); display.print(maxDist);
  display.setCursor(0,10);
if(dist>maxDist) {
  display.print("    Out of bounds");
}
else {
  display.print("Distance: "); display.print(dist);
}
  display.setCursor(0,20);
  display.print("Limit: "); display.print(potLim);
  display.display();
}

void toggleMute() {
  if(digitalRead(mute) == 1) {
    isMute=!isMute;
  }
}

void loop() {
  batteryCheck();
  // put your main code here, to run repeatedly:
toggleMute();
getRotValues();
Print(); 
display.setCursor(0,0);
display.print("Max Distance: "); display.println (maxDist);
   if((dist<potLim)&&(!mute)) {
    Beep();
   }
}

It is difficult to make an encoder work smoothly and not miss movements if you don't use interrupts. It can be done, but only if you remove all blocking code from your sketch. Examples of blocking code include delay(), pulseIn(), Serial.println() and functions which use i2c or update displays.

Using interrupts is not beginner-friendly. Why not use an encoder library?

Hi @blindiephoenix,

welcome to the arduino-Forum.
Well done posting code as a code-section in your first posting.
You should provide more information.

What microcontroller do you use?
As user @PaulRB already mentioned reading encoders without interrupts does not work reliably. Using interrupts with programming your own interrupt-service-routine is not beginner-friendly

There are several libraries that care about all the details.
As you want to use two rotary encoders;
An Ardunio Uno / Nano has only two interrupt-capable IO-pins. This means you would need a different library than for other microcontrollers.

This is the reason why you should post the microcontroller-type that you are using.

best regards Stefan

Only one, I think.

Hey there,

Thanks for your reply. I am using an arduino nano. I am also only using one encoder.
The issue that I face is this:
When I turn the encoder clockwise, the values increment as expected. However, when I turn the encoder anticlockwise, the values, instead of decrementing as expected, continue incrementing.

So if you are using only one encoder you can use the NewEncoder-library from gfvavlo

If you install this library you will find a subfolder "examples" which has multiple examples

If you use this library you must connect the encoder-channels A and B to IOnpins 2 and 3, because IO-pins 2 and 3 are the only interrupt-capable pins.

Interrupt means you code can execute any part of your program if an "interrupt" occurs the pulse gets counted "in the background"

Here is the the single encoder example

best regards Stefan

Does your encoder have its own pullup resistors?

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