Showing Encoder Value on LCD

Dear Forum Arduino members,

I am using Arduino Mega, Ramps 1.6 (or 1.4) and 128*64 LCD. I want to show the encoder value on the LCD screen with the following code. I am getting some values of the encoder but it is not working properly.
I can print text on the LCD. I can also read the encoder value on the serial print without any problems. However, when I join these two projects, I see that the encoder is skipping some values.
I need your help in this direction.

//Arduino Mega
//RepRap Ramps 1.6
//RepRapDiscount Full Graphic Smart Controller
//https://forum.arduino.cc/t/showing-encoder-value-on-lcd/1130690

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

//LCD Encoder Pins - https://reprap.org/wiki/RepRapDiscount_Full_Graphic_Smart_Controller
#define CLK 31 //Enc Btn 2
#define DT 33 //Enc Btn 1
#define SW 35 //Enc Btn

//LCD Screen Pins - https://reprap.org/wiki/RepRapDiscount_Full_Graphic_Smart_Controller
#define SCK 23 //LCD Data Bus 4bit Mode
#define MOSI 17 //LCD RS/CS (Enable Trigger)
#define CS 16 //LCD SID//RW Control

U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0,SCK,MOSI,CS,U8X8_PIN_NONE);

int enc_counter = 0;
int enc_state;
int enc_laststate;
String enc_text;

void u8g2_prepare(void) {
  u8g2.setFont(u8g2_font_7x14_tf);
  u8g2.setFontRefHeightExtendedText();
  u8g2.setDrawColor(1);
  u8g2.setFontPosTop();
  u8g2.setFontDirection(0);
}

void setup() {

  pinMode(10,OUTPUT);
  pinMode(9,OUTPUT);
  digitalWrite(10,0);
  digitalWrite(9,0);

  u8g2.begin();

  pinMode(CLK,INPUT_PULLUP);
  pinMode(DT,INPUT_PULLUP);
  pinMode(SW,INPUT_PULLUP);
  enc_laststate = digitalRead(CLK);

}

void loop() {

  enc_state = digitalRead(CLK);
  if(enc_state != enc_laststate)
  {
    if(digitalRead(DT) != enc_state)
    {
      enc_counter++;
    }
    else
    {
      enc_counter--;
    }
  }
  if((digitalRead(SW) != 1) && (enc_counter != 0))
  {
    enc_counter=0;
  }
  enc_laststate=enc_state;

  enc_text="Encoder: "+String(enc_counter);
  u8g2.firstPage();  
  do {
    u8g2.setFont(u8g2_font_7x14_tf);
    u8g2.drawStr(5,15,enc_text.c_str());
  } while( u8g2.nextPage() );

}

In the future, I want to create a simple menu for my custom project and run my stepper motors depending on the values selected on the screen menu.

Thank you.
bkarpuz

Won't that slow things down?

It must be slowing down for sure but even when I rotate the encoder slowly, it usually does not update its value.
On the other hand, when I upload the Marlin Firmware, I see that the encoder does not skip any menu items and works properly.
This makes me think there is something wrong.

Thank you.
bkarpuz

I can recommend the Encoder library. That library uses interrupts so will read faster since you don't need to poll the inputs. The Encoder library needs 1 or 2 of the hardware interrupts (Mega has 6).

Mega hardware serial pins:
Arduino Mega 2, 3, 18, 19, 20, 21

3 Likes

won't this get in the way of updating enc_counter?

1 Like

As far as I understand, I should not use do-while loop and just use

    u8g2.setFont(u8g2_font_7x14_tf);
    u8g2.drawStr(5,15,enc_text.c_str());

and It would be better if I use it righ here

  if(enc_state != enc_laststate)
  {
    if(digitalRead(DT) != enc_state)
    {
      enc_counter++;
    }
    else
    {
      enc_counter--;
    }
  //Update screen when enc_counter changes.
  }

Do you think it would be useful? I wil ltry this as soon as I go back to home from work.

Thank you.
bkarpuz

why not

void loop ()
{
    enc_state = digitalRead (CLK);
    if (enc_state != enc_laststate) {
        enc_laststate = enc_state;

        if (digitalRead (DT) != enc_state) {
            enc_counter++;
        }
        else {
            enc_counter--;
        }
    }

    enc_text="Encoder: "+String (enc_counter);

    u8g2.firstPage ();
    u8g2.drawStr (5, 15, enc_text.c_str ());
}

doesn't this only need to be done once in setup()?

I have checked a Hello World! example, which applied that line in a loop. But you are right, it should be just in void setup only.

Oh, okay gcjr, you made my path much clear. Thank you very much.
bkarpuz

Thank you very much SemperIdem, groundFungus and gcjr for your guidance, I have analized the encoder values and came up with a working code. This time, I am just updating the screen only when it is necessary. It increases/decreases the counter upon rotation of the encoder, and resets the counter (also beeps) when the encoder button is pressed.

//Arduino Mega
//RepRap Ramps 1.6
//RepRapDiscount Full Graphic Smart Controller

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

//https://reprap.org/wiki/RepRapDiscount_Full_Graphic_Smart_Controller

//LCD Beeper Pins
#define BZR 37 //Beeper

//LCD Encoder Pins
#define CLK 31 //Enc Btn 2
#define DT 33 //Enc Btn 1
#define SW 35 //Enc Btn

//LCD Screen Pins
#define SCK 23 //LCD Data Bus 4bit Mode
#define MOSI 17 //LCD RS/CS (Enable Trigger)
#define CS 16 //LCD SID//RW Control

U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0,SCK,MOSI,CS,U8X8_PIN_NONE);

int enc_counter = 0;
String enc_text = "0";
int clk_state[4] = {1, 1, 1, 1};
int dt_state[4] = {1, 1, 1, 1};
int sw_state[2] = {1, 1};

int current_clk_state = 1;
int current_dt_state = 1;
int current_sw_state = 1;

void u8g2_prepare() {

  u8g2.begin();
  u8g2.setFont(u8g2_font_7x14_tf);
  u8g2.setFontRefHeightExtendedText();
  u8g2.setDrawColor(1);
  u8g2.setFontPosTop();
  u8g2.setFontDirection(0);

}

void u8g2_update() {

  u8g2.clearBuffer();
  u8g2.drawStr(5,11,"Encoder Value");
  enc_text = String(enc_counter);
  u8g2.drawStr(5,23,enc_text.c_str());
  u8g2.sendBuffer();


}

void beep() {

  digitalWrite(BZR,HIGH);
  delay(1);
  digitalWrite(BZR,LOW);

}

void setup() {

  pinMode(BZR,OUTPUT);

  pinMode(CLK,INPUT_PULLUP);
  pinMode(DT,INPUT_PULLUP);
  pinMode(SW,INPUT_PULLUP);

  u8g2_prepare();
  u8g2_update();

  Serial.begin(9600);
  Serial.println(enc_counter);

}

void loop() {

  current_clk_state = digitalRead(CLK);
  current_dt_state = digitalRead(DT);
  if((current_clk_state != clk_state[0]) || (current_dt_state != dt_state[0]))
  {
    //Update last 4 encoder values
    for (int i = 2; i >=0; i = i - 1) {
      clk_state[i+1] = clk_state[i];
      dt_state[i+1] = dt_state[i];
    }
    clk_state[0] = current_clk_state;
    dt_state[0] = current_dt_state;
    if ((clk_state[0] == 1) && (dt_state[0] == 1) && (clk_state[2] == 0) && (dt_state[2] == 0))
    {
      if ((clk_state[1] == 1) && (dt_state[1] == 0) && (clk_state[3] == 0) && (dt_state[3] == 1))
      {
        //Encoder has been rotated CW
        Serial.println("CW");
        enc_counter = enc_counter + 1;
        Serial.println(enc_counter);
        u8g2_update();
      }
      else if ((clk_state[1] == 0) && (dt_state[1] == 1) && (clk_state[3] == 1) && (dt_state[3] == 0))
      {
        //Encoder has been rotated CCW
        Serial.println("CCW");
        enc_counter = enc_counter - 1;
        Serial.println(enc_counter);
        u8g2_update();
      }
    }
  }

  current_sw_state = digitalRead(SW);
  if(current_sw_state != sw_state[0])
  {
    sw_state[1] = sw_state[0];
    sw_state[0] = current_sw_state;
    if ((sw_state[0] == 1) && (sw_state[1] == 0))
    {
      //Button has been released
      Serial.println("Up");
      enc_counter = 0;
      Serial.println(enc_counter);
      u8g2_update();
      beep();
    }
    else if ((sw_state[0] == 0) && (sw_state[1] == 1))
    {
      //Button has been pressed
      Serial.println("Down");
    }
  }

}

Note: In this update skipping of the encoder is fixed.

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