LCD Scroll Menu, with Encoder

I'm trying my best to communicate with you this best I can.

This is cursor Select, each layer is the the different lines on the LCD screen.

example:
cursorLayer = 1; // This one is to mover the cursor to line 2 one the LCD (With is 1, because it starts with 0)

void cursorSelect(){
  switch (currentSelect){
          case 1:
            cursorLayer = 0;
            break;
          case 2:
            cursorLayer = 1;
            break;
          case 3:
            cursorLayer = 2;
            break;
          case 4:
            cursorLayer = 3;
            break;

This is something i was trying to see if would work.

void cursorSelect(){
  cursorLayer = currentSelect - 1;
}

So far in the code I have got not where, I have never done a Menu/scroll before.

The Problem in the code I'm having is getting the value of the encode to change to get the Cursor to move.

Example:

if(newPosition > oldPosition){           //if the encoder is turned CW, the Cursor Moves down a roll
 lcd.setCursor (0,newPosition);  
        writeCursor();
}
if(newPosition < oldPosition){ 
 lcd.setCursor (0,newPosition - 1);   //if the encoder is turned CCW, the Cursor Moves up a roll
        writeCursor();

}

And this code doesn't do that? What does it do that is different?

You've done a great job at explaining what you want it to do. But if you can't describe also the problem with it then you are going to be stuck.

Maybe let me dumb it down a little more for you.

Fill in the blanks:

I want this code to _________ but it doesn't. Instead it ___________ and that's not what I want.

I think the first blank you've covered pretty well. It's that second blank that you've got to fill in.

I want this code to _1 but it doesn't. Instead it _2 and that's not what I want.

  1. I want the cursor to move up and down on the left side of the 20x4 LCD screen.

  2. It will not move the cursor down or back up, I can't get the values of the encode to to change with the cursor to move it. The cursor is staying in (0,0) plan.

Nicole1998:
I want this code to _1 but it doesn't. Instead it _2 and that's not what I want.

  1. I want the cursor to move up and down on the left side of the 20x4 LCD screen.

  2. It will not move the cursor down or back up, I can't get the values of the encode to to change with the cursor to move it. The cursor is staying in (0,0) plan.

I would suggest that you look at the examples for the Arduino Explora.
The Explora is basically an Arduino Leonardo with a joystick, 4 buttons and a small LCD display.
The Etch-A-Sketch example may be worth looking at.

It is 0242 here so I will look up some more examples in the morning when I am wide awake.

Welcome to the world of Arduino.
A new adventure everyday.

Re #9. Now we're getting somewhere. So what encoder library are you using. Look carefully at the documentation for it. What specifically does the read method in that class return? Does it returns running count or does it return the movement since the last read?

Have you played with any of the examples from that library? Do they seem to work as advertised?

#include <Encoder.h> /// Arduino encoder.

This is the One I'm using, I have try out some of the library and they seem to work great.

As far as read method, in the serial port, the value(on Base Example) Starts at 0 and goes up and down as I turn the encode(prints one Line as I turn). if I stop turning it, it stops at the line with that value.

Nicole1998:
#include <Encoder.h> /// Arduino encoder.

No, that's the line where you included it. But there are lots of libraries out there and many have the same name. When I ask which one you have, I mean specifically. Like where did you get it?

Nicole1998:
This is the One I'm using, I have try out some of the library and they seem to work great.

You mean you've tried some of the examples? Have you looked at the code in them? Can you pick apart how they work?

Nicole1998:
As far as read method, in the serial port, the value(on Base Example) Starts at 0 and goes up and down as I turn the encode(prints one Line as I turn). if I stop turning it, it stops at the line with that value.

No, that's what some whole complete program does. The read method on that encoder class surely doesn't print anything to the serial monitor. What does that method return? Have you looked at the documentation for it? Have you looked at the code for it?

I really appreciate your time, But I have tried everything to understand how to make this, I've seem a lot of code for menu and all of them have a sub screen which I don't need, I have spend several hours in front of the computer trying different thing to make any of the code i get work and trying to understand how they work I'm just not understand it. I'm trying my best to give you what I know so you can help me.

I think it be easier for both of us to start over, You need to know the encoder I'm using and I'm not for sure with one, I know I download it from the library, But if you know of one off the top of your head we can work with lets try that so we are on the same page.

I do apologize for not know how to do, I never done encoder or menu on LCD screen before. Mostly all i have done is use them to display message of machine.

As you know I have a Encode and 20x4 LCD display with the IC2 backpack. I need a menu that I can scroll through and pick what I want the machine to.

Display exmaple:

LED1
LED2
LED3
LED4
Etc.

After scrolling though and finding the LED I want to use. I will then click the encode(singleClick). It will turn the LED that I pick to true.

Example: Scroll down to >LED8
Click the Encoder.
LED8 = true.
After it done runnning the code.
LED8 = false.
return the Menu back to LED.

I'm asking for you help in Pretty much everything in Writing this code because I haven't got anywhere.
I haven't learned anything.

I really hope you can help me because I have worked so hard in the project and this is the last thing I need for it to be done.

If you like to Private message me I can give you my email.

Nicole1998:
I really appreciate your time, But I have tried everything to understand how to make this, I've seem a lot of code for menu and all of them have a sub screen which I don't need, I have spend several hours in front of the computer trying different thing to make any of the code i get work and trying to understand how they work I'm just not understand it. I'm trying my best to give you what I know so you can help me.

I think it be easier for both of us to start over, You need to know the encoder I'm using and I'm not for sure with one, I know I download it from the library, But if you know of one off the top of your head we can work with lets try that so we are on the same page.

I do apologize for not know how to do, I never done encoder or menu on LCD screen before. Mostly all i have done is use them to display message of machine.

As you know I have a Encode and 20x4 LCD display with the IC2 backpack. I need a menu that I can scroll through and pick what I want the machine to.

Display exmaple:

LED1
LED2
LED3
LED4
Etc.

After scrolling though and finding the LED I want to use. I will then click the encode(singleClick). It will turn the LED that I pick to true.

Example: Scroll down to >LED8
Click the Encoder.
LED8 = true.
After it done runnning the code.
LED8 = false.
return the Menu back to LED.

I'm asking for you help in Pretty much everything in Writing this code because I haven't got anywhere.
I haven't learned anything.

I really hope you can help me because I have worked so hard in the project and this is the last thing I need for it to be done.

If you like to Private message me I can give you my email.

Allow me to help you.
Would you mind restating your problem/project?

I will try my best to provide you with a workable solution.
Being frustrated does no one any good.
It turns you (generic you) off programming and arduino.
I will read your posts in the morning and go through the background.

Nicole1998:
I really appreciate your time, But I have tried everything to understand how to make this, I've seem a lot of code for menu and all of them have a sub screen which I don't need, I have spend several hours in front of the computer trying different thing to make any of the code i get work and trying to understand how they work I'm just not understand it. I'm trying my best to give you what I know so you can help me.

The one I posted in reply #1 will work with any number of screens. It is probably a little more complex than what you are after, but really all you'd have to do is switch out the LCD library to the one you use and write all of the functions to light the light and return true.

Nicole1998:
I think it be easier for both of us to start over, You need to know the encoder I'm using and I'm not for sure with one, I know I download it from the library, But if you know of one off the top of your head we can work with lets try that so we are on the same page.

I don't use a library for an encoder. It's a really simple device. I find it easier to understand how it works than to hide the details behind some library. Give me a second and I'll post my normal type of encoder code.

Nicole1998:
I do apologize for not know how to do, I never done encoder or menu on LCD screen before. Mostly all i have done is use them to display message of machine.

Don't apologize. We all have things we don't know how to do. I bet you can do lots of things I can't.

Nicole1998:
As you know I have a Encode and 20x4 LCD display with the IC2 backpack. I need a menu that I can scroll through and pick what I want the machine to.

Display exmaple:

LED1
LED2
LED3
LED4
Etc.

After scrolling though and finding the LED I want to use. I will then click the encode(singleClick). It will turn the LED that I pick to true.

Example: Scroll down to >LED8
Click the Encoder.
LED8 = true.
After it done runnning the code.
LED8 = false.
return the Menu back to LED.

I'm asking for you help in Pretty much everything in Writing this code because I haven't got anywhere.
I haven't learned anything.

Haven't learned anything? That's troubling. Maybe you have just started off with something too complex. When you learn to swim, you don't do so by trying to swim across an ocean. You would just drown and get nowhere. Maybe it would help to put this aside for a bit and study up on the basics a little.

Nicole1998:
I really hope you can help me because I have worked so hard in the project and this is the last thing I need for it to be done.

If you like to Private message me I can give you my email.

Help on the forum is free. Private help means you have to hire me and I am VERY VERY expensive. We should probably keep this on the forum. I only really come on here when I'm out on the road stuck in some hotel room bored out of my mind. When I get home or have some work to do I will just disappear and you might not hear from me for some time. But out here on the forum someone else can jump in and continue helping you out.

Expect another post in a few minutes with some encoder code.

Alright So I have a machine that has 10 different thing it can do. All the thing are set to false in the program until I Press a button, I would like to change the buttons so I don't need 10 of them.

I need the button on the encoder and the LCD display to change (int) to true. After it runs through the code, at the end I have it setting the (int) back to false so i can run something else.

I buy a encoder, and a 20x4 LCD display to take place of the buttons.

I would like to have a scroll menu with a cursor that scroll down the left side of the LCD screen till I get to the function I would like to run.

I have no code for it, I have try multiple menu codes and all of them are using different layers and changing values.

All I need is a menu(1 Layer). and as I scroll the Encode I need the cursor to move down the LCD display until I get to what I want to run.

If i press down on the encoder(single Click). The menu will go away and the LCD Display will print what the machine is doing until it is done. After its done it will return to the Menu to start over. (NO Values to change, no Sub menu inside menus, just ONE layer).

I have searched and couldn't find anyone that has done anything like this, I though it was going to be a little easier then what i have been though to get this to work.

If you look at the gray code that an encoder puts out, you can see an easy way to tell which way it is turning. Start by looking only at one pin. When its state changes, if the other pin is in the same state then the encoder is going one way and if the other pin is in the opposite state then the encoder is going the other way. If you are looking at state changes on the second pin then the same holds true but the directions are reversed. If that doesn't make sense yet then google "encoder gray code" and see if you can learn how the waveform works.

Here's a picture:

encoderOutput.gif

Now one more thing about encoders. As you spin them that waveform keeps moving, so you really need to check the state of the other line at the very instant that you notice the state change on one pin. So it is common to use an interrupt for that. If you don't know about those, stop here and google "Arduino Hardware Interrupt" and do some reading to learn what those are. The important thing is that on an UNO those are on pins 2 and 3 so we MUST use those pins.

So here is some code that illustrates the point well, but won't work for a reason I'll explain afterwards.

// Code compiles but is untested
// In reality it would be too slow
// But it is easier to understand the 
// concept here with digitalRead than
// it is with diret port reads
// I have used the same code written
// with port reads many times to read
// encoders.  It works.  

// If your encoder gives four increments per "click"
// and you only want one, then remove one interrupt
// entirely and set the other to RISING or FALLING
// instead of CHANGE.  

// The two pins from the encoder
const byte epinA = 2;
const byte epinB = 3;

int printInterval = 500;

volatile int encoderCount = 0;

void setup(){

  Serial.begin(115200);

  attachInterrupt(digitalPinToInterrupt(epinA), eintA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(epinB), eintB, CHANGE);
  
}

void loop(){

  static unsigned long pt = millis();
  unsigned long ct = millis();
  
  int encoderRead = 0;

  if(ct - pt >= printInterval){
    cli();
    encoderRead = encoderCount;
    sei();
    Serial.println(encoderRead);
  }
  
}
/*
  This is actually too slow for fast encoders.
  Should use direct port reads instead of 
  digitalRead.  But this illustrates the point.
  if your encoder ends up going backwards
  just switch the ++ and -- in both ISR's. 
*/ 

void eintA(){
  // if the pins read the same we're going one direction
  // else we're going the other direction.
  if(digitalRead(epinA) == digitalRead(epinB)){
    encoderCount++;
  }
  else {
    encoderCount--;
  }
}

void eintB(){
  // Same as above, except the directions are switched for
  // the other pin.  
  if(digitalRead(epinB) == digitalRead(epinA)){
    encoderCount--;
  }
  else {
    encoderCount++;
  }
}

The loop is just a regular Blink Without Delay style timing code that prints the encoder count to the screen once every so often. The important bit is the cli() and sei() which turn off and then back on the interrupts on either side of copying that reading to another variable. This is important because it takes more than one clock cycle to copy that value and we don't want the interrupt to trigger and change it in the middle of while we are reading it. (google "critical section" for more information on that)

Unfortunately that code will almost work. But I included it because what is about to happen is probably a little over your head and I want you to be able to see what is really going on in the next code. See, the problem is that digitalRead can be too slow to catch the state on an encoder that is moving very fast. We need a faster way to read a digital pin and this comes from direct port reads. Please take a little while to study that page. You don't really need to know all of it, you just need to get the basic idea that I am reading the hardware directly. This is what digitalRead does for you behind the scenes.

So now my code becomes this:

// The two pins from the encoder
const byte epinA = 2;
const byte epinB = 3;

int printInterval = 500;

volatile int encoderCount = 0;

void setup(){

  Serial.begin(115200);

  attachInterrupt(digitalPinToInterrupt(epinA), eintA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(epinB), eintB, CHANGE);
  
}

void loop(){

  static unsigned long pt = millis();
  unsigned long ct = millis();
  
  int encoderRead = 0;

  if(ct - pt >= printInterval){
    cli();
    encoderRead = encoderCount;
    sei();
    Serial.println(encoderRead);
  }
  
}
/*
  Port reads are way faster than digitalRead
  if your encoder ends up going backwards
  just switch the ++ and -- in both ISR's. 
*/ 

void eintA(){
  // if the pins read the same we're going one direction
  // else we're going the other direction.
  if(!!(PIND & 4) == !!(PIND & 8)){
    encoderCount++;
  }
  else {
    encoderCount--;
  }
}

void eintB(){
  // Same as above, except the directions are switched for
  // the other pin.  
  if(!!(PIND & 8) == !!(PIND & 4)){
    encoderCount--;
  }
  else {
    encoderCount++;
  }
}

The !! looks confusing, but all it is doing really is letting me treat a number as a boolean. !someNumber is true if the number is 0 and false if the number is not 0. An extra ! gets me back to true for numbers that aren't 0 and false for 0. Basically, it converts any number that isn't 0 into a 1. So my bitmath would result in 4 or 8 for the two pins which obviously isn't equal. But by using !! I can say !!8 == !!4. If that's still confusing then just take my word for it that it works.

So now I have a counter that will count up or down depending on which way I turn my encoder.

Look now, I gave you a lot of links here and things to google. That whole thing about you not learning anything is about to change. I expect this might take a while for you to study through, maybe even a day or two. If you will, then you will learn a lot more than just how to work an encoder. Take your time and when you get how this is working then we will put it together with your display to make a menu.

PLEASE, if you don't understand some part of this ask questions, but ask specific questions. I'm not going to like "I just don't get it". If that is the case then you need to keep at the things I told you to read or google until you do start to get it.

The one I posted in reply #1 will work with any number of screens. It is probably a little more complex than what you are after, but really all you'd have to do is switch out the LCD library to the one you use and write all of the functions to light the light and return true.

I have try download it but I can't find the library to? do you have a link?

This is another important page. You should really just read everything on it or linked from it.

Nicole1998:
I have try download it but I can't find the library to? do you have a link?

There is a link in the very first post on that second thread that I linked to in #1. Still, that one may be a bit complex for you. I don't know that it is a good fit. You'll have to learn about virtual classes and it might be easier to just learn how to read an encoder. You really don't need most of the things that code is capable of. I was just pointing out that it does work for a single layer. But it isn't going to be a drop in solution. You'll have to do some editing of it to switch it to work with the I2C LCD and you'll have to really understand the explanation of how to write the functions you want the menu to call. They must have a very specific function signature.

I have when back through everything, I when back to the Link you send to me using MenuClass, I got the libeary and I have try to use it and it throws Error fun1 is not in scope.
I think I understand a little bit more now and I might be about to get this code to work. But I'm not sure on the Error.
Any Ideas?

Nicole1998:
I got the libeary and I have try to use it and it throws Error fun1 is not in scope.

Did you make the modifications that it needs? Did you read the part where I said it probably wasn't what you needed?

I don't have a copy of the IDE with me right now so I can't try to compile it. Will try later. It worked last time I tried it, but it's been a long time since I've tried to use that example.

Did you make the modifications that it needs? Did you read the part where I said it probably wasn't what you needed?

I didn't know anything need to be changed just to get it upload? I known that i need to add the LCD screen but I was just going to see how it worked with the serial to get a understand?

I couldn't fine anywhere that need to change something?

Are you playing with the Simple menu (works with buttons) or REBL (works with encoders). REBL has the LCD pretty well integrated into it. It's going to be hard to run that on the serial monitor without serious modifications.

If you're using the Simple Serial Menu then you have to derive your own class from it. Like I said, it's not the kind of code you can just copy in and see it work. This is code for coders who know how to code and can look at it and pick it apart and make it work for them. I think you should probably just stick to what you were doing.

Have you been able to get an encoder to work yet? Forget the LCD and everything else. Can you get just an encoder working by itself to increase or decrease a variable?