Rotary Encoder with LCD Function

Hi,

I am currently trying to get my rotary encoder and lcd to work together. For now the aim is to have the LCD display the rotary count as i turn the rotary and when i push the button switch on LED on 13 for 1 second, and return the counter to 0.
When i upload the code below this is what happens:

1/ The "Index" shows up on the LCD but flickering very fast
2/ When I turn the rotary i can see the counter working but again flickering very fast
3/ When I press the rotary button "Index" stops flickering but the count is not shown, Led 13 lights up but does not go off after 1 second.

I would be grateful if anybody could guide where i am going wrong.

Thanks.

#include <LiquidCrystal.h>
LiquidCrystal lcd (12, 11, 8, 9, 6, 7);

enum PinAssignments {
  encoderPinA = 3,   // right (labeled DT on our decoder, yellow wire)
  encoderPinB = 2,   // left (labeled CLK on our decoder, green wire)
  clearButton = A0    // switch (labeled SW on our decoder, orange wire)
                
};

volatile int encoderPos = 0;  // a counter for the dial
int lastReportedPos = 1;   // change management
static boolean rotating = false;    // debounce management
int UIstate = 0;                            //User state management


// interrupt service routine vars
boolean A_set = false;
boolean B_set = false;

void setup() {

  pinMode(encoderPinA, INPUT_PULLUP); // new method of enabling pullups
  pinMode(encoderPinB, INPUT_PULLUP);
  pinMode(clearButton, INPUT_PULLUP);


 // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderA, CHANGE);
  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, doEncoderB, CHANGE);
  lcd.begin(16, 2);

//  Serial.begin(9600);  // output
}


void loop() 
{
  UserInterface();
  navigateMenu();
}

void navigateMenu()
{
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Index:");
  
  switch (UIstate)
  {
    case 1:
    digitalWrite(13, HIGH);        //ENTER PART using LED on 13 for testing purposes
    delay(1000);
    digitalWrite (13, LOW);
    break;
    
    case 2:
    lcd.print(encoderPos, DEC);    //CW ROTATION print counter
    break;
    
    case 3:
    lcd.print(encoderPos, DEC);    //CCW ROTATION print counter
    break;
  }
}

void UserInterface()
{
  rotating = true;  // reset the debouncer
  if (lastReportedPos != encoderPos)
  {
    lastReportedPos = encoderPos;
  }
  if (digitalRead(clearButton) == HIGH )
  {
    delay(20);
    UIstate = 1;
    encoderPos = 0;        //When button is pressed reset counter to 0
  }
}

void doEncoderA()
{
  if ( rotating ) delay (1);                                //Wait a little until the bouncing is done
  if ( digitalRead(encoderPinA) != A_set )
  {
    A_set = !A_set;
    if (A_set && !B_set && encoderPos != 10)
    {
      encoderPos += 1;                         
      UIstate = 2;                                            //Increment by 1 clockwise
    }
    if ( A_set && !B_set && encoderPos == 10)
    {
      encoderPos = 10;
    }
    rotating = false;                                        //No more debouncing until loop() hits again
  }
}

void doEncoderB()
{
  if ( rotating ) delay (1);                              //Wait a little until the bouncing is done
  if ( digitalRead(encoderPinB) != B_set  )
  {
    B_set = !B_set;
    if ( !A_set && B_set && encoderPos != 0)
    {
      encoderPos -= 1;
     UIstate = 3;
    }
    if (!A_set && B_set && encoderPos == 0)
    {
      encoderPos = 0; 
    }
    rotating = false;
  }
}

Proietti:
1/ The "Index" shows up on the LCD but flickering very fast
2/ When I turn the rotary i can see the counter working but again flickering very fast
3/ When I press the rotary button "Index" stops flickering but the count is not shown, Led 13 lights up but does not go off after 1 second.

The "loop" part of your code calls "navigateMenu()" over and over again, and navigateMenu has as it's first statement "lcd.clear()". So, as fast as the loop runs you are printing and clearing and printing and erasing etc... your LCD display, which is why it flickers.

Don't clear it every time... only when you need to.

And, instead of using clear, you can avoid all flicker by "erasing" lines with spaces. For example:

lcd.setCursor (0, 0); // first line
lcd.print ("                "); // print a blank line of 16 characters
lcd.setCursor (0, 0); // reset to first line
lcd.print ("Your data here"); // print whatever

This is a bit more complicated than "lcd.clear()", but it produces a nice "clean" display with no flicker.

Hope this helps.

Brilliant thanks. That has stopped the flickering. The LED on 13 still does not go off after 1 second but stays on until I rotate the encoder again.

I don't see why the led doesn't turn off.. But the screen is cleared because you print nothing when the last action is a button push.

So go for

if(UIstate == 1){
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
}
lcd.print(encoderPos, DEC);
UIstate = 0;
[/quote]

But I find the whole structure of the program a bit weird. Why do you need a encoderPos and a lastReportedPos? The only thing you do is if they are not the same you make them the same...

And ALL interrupt variables should be volatile, so A_set and B_set should be volatile.
if(UIstate == 1){
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
}
lcd.print(encoderPos, DEC);
UIstate = 0;
[/quote]

But I find the whole structure of the program a bit weird. Why do you need a encoderPos and a lastReportedPos? The only thing you do is if they are not the same you make them the same...

And ALL interrupt variables should be volatile, so A_set and B_set should be volatile.

Ok, so how would i improve it. What i want to get to is this:
i want the encoder to display a counter which I set eg. 0-10 & 10-0. When press the button the LED lights up then shuts off. This is going to later expand into my bigger project where the rotation of the encoder will rotate through menus, and when i press the button it takes me to submenus, then rotate encoder through submenus and when i press the button i go to subsubmenus ect..