Oled + Rotary Encoder

I want to Combine a Oled-Display with a rotary encoder.

I have 1 Value i want to Change with the Rotary Encoder and i want the Value beeing displayed on the oled. I Ran into problems. The Value is glitching and it is not clearly changing. I narrowed it down do "display.display();". As soon as i remove this line it works. When i add it it is glitching again. Any ideas?

//SCreen
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

//Rotary Encoder

// Rotary Encoder Inputs
#define inputCLK 4
#define inputDT 5

int counter = 0;
int currentStateCLK;
int previousStateCLK;

String encdir = "";  //String to be populated with either ClockWise or CounterClockWise

//Variables
int Length = 20;

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();

  //RotaryEncoder
  // Set encoder pins as inputs
  pinMode(inputCLK, INPUT);
  pinMode(inputDT, INPUT);

  // Read the initial state of inputCLK
  // Assign to previousStateCLK variable
  previousStateCLK = digitalRead(inputCLK);
}

void loop() {
  //Rotary Encoder
  
   // Read the current state of inputCLK
   currentStateCLK = digitalRead(inputCLK);
    
   // If the previous and the current state of the inputCLK are different then a pulse has occured
   if (currentStateCLK != previousStateCLK){ 
       
     // If the inputDT state is different than the inputCLK state then 
     // the encoder is rotating counterclockwise
     if (digitalRead(inputDT) != currentStateCLK) { 
       counter --;
       Length --;
       encdir ="CCW";

      
       
     } else {
       // Encoder is rotating clockwise
       counter ++;
       encdir ="CW";
       Length ++;

       
     }
     
     if (Length <= 0){
      Length = 0;}

     Serial.print("Direction: ");
     Serial.println(encdir);
     Serial.print(" -- Value: ");
     Serial.println(counter);
    Serial.print(" Length ");
     Serial.println(Length);
  }
  // Update previousStateCLK with the current state
  previousStateCLK = currentStateCLK;
  
  
  
  //Oled
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  //Timer
  display.setCursor(0, 10);
  display.print("Timer - ");
  display.print(Length);
  display.println(" Minutes");
  display.display();
}

Your sketch is running fast, and the display.display() is refreshing the data placed in its buffer. For an experiment, just after display.display(); put a delay to slow the refresh:

   delay(200); // 200 ms delay

If this delay helps resolve the "flicker"... consider replacing the delay(); with a timing loop using the millis() function to only refresh your display at your preferred interval. An example of how to use it is blink without delay

Yes, like @xfpd points out you are updating the display at loop speed..
try only updating display when Length has changed..

Uno Encoder Oled

have fun.. ~q

A Delay is not Solving the issue. It just...well...delays it. Like i said. It is not a problem of the display. I have the Values printed out in the Serial.Monitor. It is allready glitching in the Monitor. But Thx

It works in the simulation but not on my setup. Sorry. It simply displays "Length 20" in Serial.Monitor.

had to move clock to pin 2..

uno can only use either pins 2 or 3 for interrupt..

~q

Thx! That solved it. I think this is a bit to advanced for me. I should spend some more time with the basics.

using the interrupt makes sure you won't miss any encoder movements..
took it from my Uno Pong..

have fun.. ~q

1 Like

this is insane. how do get to that level? do you do this stuff for a living?

Iv'e lived, eat and breathed code for the last 4 decades..
that being said, i don't know anything.. :slight_smile:

have fun.. ~q

2 Likes

This is very true. The moment you "know" something, it becomes out-dated. Eat/sleep/breathe code keeps the newest information readily available.

2 Likes

You got a very good solution from @qubits-us already using an interrupt pin!

The main problems of your sketch has already been mentioned above, redrawing the display all the time delays loop() so that it cannot read the encoder pins in due time.

Just as an example here (almost) your code but with a few changes:

https://wokwi.com/projects/377762218537644033

Sketch
/*
  Forum: https://forum.arduino.cc/t/oled-rotary-encoder/1175366
  Wokwi: https://wokwi.com/projects/377762218537644033
*/

//Screen
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

//Rotary Encoder

// Rotary Encoder Inputs
#define inputCLK 4
#define inputDT 5

String encdir = "";  //String to be populated with either ClockWise or CounterClockWise

//Variables
int Length    = 20;
int oldLength = 0;

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();

  //RotaryEncoder
  // Set encoder pins as inputs
  pinMode(inputCLK, INPUT);
  pinMode(inputDT, INPUT);

}

void loop() {
  readEncoder();
  printToDisplay();
}

void readEncoder() {
  static int previousStateCLK = HIGH;  // Store the previous state for the next call of readEncoder()
  //Rotary Encoder
  // Read the current state of inputCLK
  int currentStateCLK = digitalRead(inputCLK);
  // If the previous and the current state of the inputCLK are different then a pulse has occured
  if (currentStateCLK != previousStateCLK) {
    int dtValue = digitalRead(inputDT);
    if (currentStateCLK == LOW && dtValue == HIGH) {
      // Encoder is rotating clockwise
      Length++;
    }
    if (currentStateCLK == LOW && dtValue == LOW) {
      // Encoder is rotating counterclockwise
      Length--;
      if (Length < 0) {
        Length = 0;
      }
    };
  }
  // Update previousStateCLK with the current state
  previousStateCLK = currentStateCLK;
}

void printToDisplay() {
  if (Length != oldLength) {
    //Oled
    oldLength = Length;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    //Timer
    display.setCursor(0, 10);
    display.print("Timer - ");
    display.print(Length);
    display.println(" Minutes");
    display.display();
  }
}
  • The encoder part in your sketch did not work correctly ... so it had to be changed.
    (See here for a nice explanation: https://docs.wokwi.com/parts/wokwi-ky-040
  • The display is only rewritten if the data have changed.

So in case you come into a situation where you cannot effort to "sacrifice" one of the two interrupt pins of your UNO you might use an Encoder also without that.

But the main goal is to show you that if you can avoid delaying functions microcontrollers may handle things with an amazing speed ...

Have fun and good luck!

1 Like

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