Rotary Encoder outputting garbage to LCD?

I'm just dipping my toe into the whole Arduino stuff. I'm not a programmer by trade, but have poked around in it here and there. I'm not great, but I comprehend the basics.

I got a kit that included a bunch of widgets, inputs and outputs. I've got a 16x2 LCD screen hooked up and working using code I've found in a couple of tutorials (forgive me, I don't even know which one I'm using at this point).

I've also gotten a rotary encoder hooked up and working using a couple of more tutorials.

So, I tried the next step, of combining the two. I've got the rotary encoder position counter working, and outputting to the LCD screen. When I rotate right, the number goes up, and when I rotate left, the number goes down.

But if I twist the encoder quickly in either direction, the LCD turns to garbage, and doesn't return.

I've looked around and have seen some stuff about rotary encoders skipping numbers (which also happens), but I haven't seen much about it outputting garbage. I should note that the serial monitor also shows garbage data sometimes, but not the same stuff the LCD is showing.

Here's a video:

And here's my current code:

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

#define clkPin 0
#define dtPin 1
#define swPin 2 //Click Button

int encoderVal = 0;
int encoderOldVal = 1;
static int oldA = HIGH;
static int oldB = HIGH;

void setup() {
  
  pinMode(clkPin, INPUT);
  pinMode(dtPin, INPUT);
  pinMode(swPin, INPUT);
  digitalWrite(swPin, HIGH);
  Serial.begin(9600);
  Serial.println("Arduino Running. . . ");

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Position:");
}

void loop() {
  
  int change = getEncoderTurn();
  encoderOldVal = encoderVal;
  encoderVal = encoderVal + change;
  if(digitalRead(swPin) == LOW)
  {
    encoderVal = 0;
  }

  if(encoderVal != encoderOldVal) {
      // set the cursor to column 0, line 1
      // (note: line 1 is the second row, since counting begins with 0):
      lcd.setCursor(0, 1);
      lcd.print("     ");
      lcd.setCursor(0, 1);
      // print the number of seconds since reset:
      lcd.print(encoderVal);
  }
}

int getEncoderTurn(void)
{
  int result = 0;
  int newA = digitalRead(clkPin);
  int newB = digitalRead(dtPin);
  if (newA != oldA || newB != oldB)
  {
    // something changed
    if (oldA == HIGH && newA == LOW)
    {
      result = (oldB * 2 - 1);
    }
  }
  oldA = newA;
  oldB = newB;
  return result;

}

The more 'modern' way to express this

  pinMode(swPin, INPUT);
  digitalWrite(swPin, HIGH);

is

pinMode(swPin, INPUT_PULLUP);

I guess the examples you are using are quite old.

This comment does not seem to be appropriate for the code that follows it?

      // print the number of seconds since reset:

And, while I am at it :slight_smile: the encoder inputs are normally called A and B, not CLK and DATA.

Just a nudge to make sure you pick up good habits. Remember that others reading your code do so for the first time and so make sure that everything is consistent, especially that the comments and variable names reflect what the code is doing.

OK.

So how are you powering this (USB, external power?) and how is the rotary encoder wired up? A well focused photo of the detail would be useful.
Does it actually zero when you press the switch?

Thanks for the reply. I am a super novice to this stuff, so yeah, I'm sure some of what I'm finding is ancient by today's standards.

I started with A and B but kept getting confused about where they were going on the actual encoder, so I switched for my own sake. The comments are hit and miss because they came with whatever code I was copying, I didn't comment myself. I'll try to endeavor to do that in the future. I know it isn't good form. Sorry for offending your delicate sensibilities. :stuck_out_tongue:

The arduino has external power, and is plugged into a usb slot on my computer.

The position # does zero when I press the encoder in, though once it's been corrupted, it doesn't fix anything.

Here's a shot of the encoder:

Left to right:
Black - Ground
Red - 5v
Green - Pin 2 (push button)
Black - Pin 1 (B)
White - Pin 0 (A)

Nothing screams at me that this is wrong.

In the code

    if (oldA == HIGH && newA == LOW)
    {
      result = (oldB * 2 - 1);
    }

oldB is either HIGH or LOW and respresents a digital. What is the intention using it in the calculation?

Is your LCD connected via a 'backpack' through I2C or SPI, a shield or through wires into a breadboard?

The reason for asking is that often breadboards can cause weird effects like this. Maybe try moving the cables around (in, out, jiggle, etc) and see if it improves the situation. It is also worth testing that you are actually getting the right voltages at the LCD and encoder (with a voltmeter/multimeter).

The LCD has 16 pins sticking out of the back of it. I have it pressed into the breadboard, and then those jumped to the Arduino.

I think my original title/premise may be confusing things a bit though.

Even if I remove the LCD entirely from the picture, the Rotary Encoder still outputs garbage to the serial monitor. It does seem to keep track of turns though (at least, sort of), even with the garbage, unlike the LCD.

Hi,

#define clkPin 0
#define dtPin 1
#define swPin 2 //Click Button

Not a good move, pins 0 and 1 are used for programming the Arduino.

I think your code will run better if you do not use pins 0 and 1 for your encoder inputs.

Tom.... :slight_smile:

Sure enough, pin 2 & 3 seem to be working much better.

Thanks for the newb lesson.

Ok, so I've got things nearly working as intended.

The rotary encoder is sending it's signals properly, not spitting out garbage. the LCD is updating as it should. I also added a little buzzer to the mix just for a little better feedback. And the encoder's center button resets the count.

Only issue is that the encoder is counting twice per step. It wouldn't be hard to work around that, but I'm curious how/where that's happening?

Here's my current code. Hopefully a little more correct and legible than previously.

// include the library code:
#include <LiquidCrystal.h>

// initialize the LCD library with the numbers of the interface pins
LiquidCrystal lcd( 8, 9, 10, 11, 12, 13);

//Setting our encoder Pin numbers:
#define outputA 5 //Rotary Output 1
#define outputB 6 //Rotary Output 2
#define outputC 7 //Click Button

//Initializing Variables
int count = 0;
int countOld = 1;
int newA;
int newB;
int encC;
int buzzer = 4;//the pin of the active buzzer
static int oldA;
static int oldB;
static int oldC;

void setup() {
  
  //Setting Pins to be Inputs
  pinMode(outputA, INPUT);
  pinMode(outputB, INPUT);
  pinMode(outputC, INPUT);
  pinMode(buzzer, OUTPUT);
  digitalWrite(outputC, HIGH);
  //Outputting to the serial monitor, and making an initial statement
  Serial.begin(9600);
  Serial.println("Arduino Running. . . ");
  lcd.begin(16, 2);                 // set up the LCD's number of columns and rows:
  lcd.print("Position:");           // Print a message to the LCD.
}

void loop() {
  
  newA = digitalRead(outputA);      //Reads the current state of outputA
  newB = digitalRead(outputB);      //Reads the current state of outputB
  encC = digitalRead(outputC);      //Reads the current state of outputC
  countOld = count;                 //store the old value of the encoder
  if (newA != oldA)
  {
    if (newA != newB)               //if A changed . . .
    {
      count ++;                     //increase the count
      tone(buzzer, 1000, 3);        //output to buzzer
    } else {                        //otherwise. . . 
      count --;                     //decrease the count
      tone(buzzer, 1500, 3);        //output to buzzer
    }
  }
  if (encC == LOW)                  //if the button is pushed . . .
  {
    count = 0;                      //Reset the counter
    tone(buzzer, 3000, 3);          //output to buzzer
  }
  if (count != countOld)            //if the old count isn't the same as the new count . . . 
  {
    lcd.setCursor(0, 1);          //set LCD posiiont
    lcd.print("     ");           //clear LCD at that spot
    lcd.setCursor(0, 1);          //reset LCD position
    lcd.print(count);             //print the count to LCD
    Serial.println(count);        //print the count to the serial monitor.
  }
  oldA = newA;                    //store A for comparison
  oldB = newB;                    //store B for comparison
}

A Rotary Encoder requires Interrupts

My code for a rotary encoder works very well.

For security reasons I never ever use URLs (links).
Use Google and search for "rotary encoder arduinoaleman".

A Rotary Encoder requires Interrupts

This is not the case. As long as you poll a rotary encoder often enough you will get the changes. If you are implementing a mission critical counter (for example, measuring speed of a mechanically rotating shaft) then using interrupts will be far more reliable. For a user input device like this polling can work just as well.