Creating a Cycling List on a LCD Screen

Hello everyone,

I don't know if this is the right section to ask this but I have been trying to create a list of items on a 20x4 LCD screen and when I press a button, the first item goes to the bottom of the list and everything shifts up.

For example:

"ITEM 1"
"ITEM 2"
"ITEM 3"

button is pressed

"ITEM 2"
"ITEM 3"
"ITEM 1"

I haven't seen anything around that is similar to this so any help will be greatly appreciated!!

I have been trying

Please post what you have tried

Please follow the advice on posting code given in Read this before posting a programming question in order to make your sketch easy to read, copy and test

In particular note the advice to Auto format code in the IDE and to use code tags when posting code here as it prevents some combinations of characters in code being interpreted as HTML commands such as italics, bold or a smiley character, all of which render the code useless

If the code exceeds the 9000 character inline limit then attach it to a post

sneezy_anus:
Hello everyone,

I don't know if this is the right section to ask this but I have been trying to create a list of items on a 20x4 LCD screen and when I press a button, the first item goes to the bottom of the list and everything shifts up.

For example:

"ITEM 1"
"ITEM 2"
"ITEM 3"

button is pressed

"ITEM 2"
"ITEM 3"
"ITEM 1"

I haven't seen anything around that is similar to this so any help will be greatly appreciated!!

Put the list of items in an array.

Create a variable used as an index to that array and initialize it to the first element (e.g. zero).

Update LCD with the contents of the array starting where the index is pointing.

When your button is pressed, bump the index pointer by 1. You can then update the display with the same logic as was used to initialize the display: print the first line with the contents of the array pointed to by the index. Print the remaining elements, making sure to circle back to element zero when the end of the array is hit.

You can try this (which prints to the serial monitor) but gives the basic idea.

/*
 * Sketch...:   sketch_mar27a.ino
 * Target...:   Uno
 * 
 * Notes....:
 */

//includes

//defines
#define NUM_ITEMS       3

//constants
const char *grzMenuItems[NUM_ITEMS] = 
{
    "Item 1",
    "Item 2",
    "Item 3"
};

const uint8_t pinButton = 2;

//variables
uint8_t
    lastButton,
    index;
uint32_t
    timeButton,
    timeNow;

void setup( void )
{
    Serial.begin(115200);
    pinMode( pinButton, INPUT_PULLUP );
    lastButton = digitalRead( pinButton );

    //set index to start of array
    index = 0;
    //initialize the display
    UpdateDisplay();
        
}//setup

void loop( void )
{
    //read the switch every 50mS
    timeNow = millis();
    if( (timeNow - timeButton) > 50ul )
    {
        timeButton = timeNow;
        uint8_t nowButton = digitalRead( pinButton );
        if( nowButton != lastButton )
        {
            //if not the same as last time button was pressed or released
            lastButton = nowButton;
            //if it's now LOW, button was depressed
            if( nowButton == LOW )
            {
                //bump our array index and limit it to the size of the array of items
                index++;
                if( index == NUM_ITEMS )
                    index = 0;

                //then update the display
                UpdateDisplay();
                
            }//if
            
        }//if
        
    }//if
        
}//loop

void UpdateDisplay( void )
{
    //make a working copy of the index
    uint8_t
        copyIndex = index;

    //print all items of the array
    for( uint8_t i=0; i<NUM_ITEMS; i++ )
    {
        Serial.println( grzMenuItems[copyIndex] );
        //bump the working copy and limit it to the size of the array of items
        copyIndex++;
        if( copyIndex == NUM_ITEMS )
            copyIndex = 0;
            
    }//for

    //for clarity on the serial monitor print a blank line between each update
    Serial.println();
    
}//UpdateDisplay

Okay, I had an idea this morning on how I could make this work and also understand what is happening.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,20,4);

const int buttonPin = 2;

int buttonState = 0;
int old_buttonState = 0;
int buttonCounter = 0 ;

String string1 = "PC 1";
String string2 = "PC 2";
String string3 = "MONSTER";

void setup() {
  lcd.init();
  lcd.backlight();
  pinMode(buttonPin, INPUT);
}

void loop() {
    buttonState = digitalRead(buttonPin);

  if ((buttonState == HIGH) && (old_buttonState == LOW)){
    buttonCounter++;
  }
  if (buttonCounter == 0){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(string1);
    lcd.setCursor(0,1);
    lcd.print(string2);
    lcd.setCursor(0,2);
    lcd.print(string3);
    delay(100);
    return;
  }
  if (buttonCounter == 1){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(string2);
    lcd.setCursor(0,1);
    lcd.print(string3);
    lcd.setCursor(0,2);
    lcd.print(string1);
    delay(100);
    return;
  }
  else if (buttonCounter == 2){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(string3);
    lcd.setCursor(0,1);
    lcd.print(string1);
    lcd.setCursor(0,2);
    lcd.print(string2);
    delay(100);
    return;
  }
  else if (buttonCounter == 3){
    buttonCounter == 0;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(string1);
    lcd.setCursor(0,1);
    lcd.print(string2);
    lcd.setCursor(0,2);
    lcd.print(string3);
    delay(100);
    return;
  }
  old_buttonState = buttonState;
}

This works almost perfectly. Just when it gets back into the original state of the list, everything freezes and I can't continue to loop the list. So firstly and most importantly, how can I solve this new issue? And secondly, is there anything in my code that is redundant/not needed/could be simplified?

One obvious problem is that old_buttonstate is not updated because the code returns before that statement is reached

You need to get rid of all those 'return' statements and let loop() finish. Your flow is all a bunch of if/else statements so only one path with get executed each time through. You can also stop your display from flickering since you always do a lcd.clear() each time through the loop and just move that into the if() statement when a button is pressed

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,20,4);

const int buttonPin = 2;

int buttonState = 0;
int old_buttonState = 0;
int buttonCounter = 0 ;

String string1 = "PC 1";
String string2 = "PC 2";
String string3 = "MONSTER";

void setup() {
  lcd.init();
  lcd.backlight();
  pinMode(buttonPin, INPUT);
}

void loop() {
    buttonState = digitalRead(buttonPin);

  if ((buttonState == HIGH) && (old_buttonState == LOW)){
    buttonCounter++;
    delay(100);
    lcd.clear();
  }
  if (buttonCounter == 0){
    lcd.setCursor(0,0);
    lcd.print(string1);
    lcd.setCursor(0,1);
    lcd.print(string2);
    lcd.setCursor(0,2);
    lcd.print(string3);
  }
  if (buttonCounter == 1){
    lcd.setCursor(0,0);
    lcd.print(string2);
    lcd.setCursor(0,1);
    lcd.print(string3);
    lcd.setCursor(0,2);
    lcd.print(string1);
  }
  else if (buttonCounter == 2){
    lcd.setCursor(0,0);
    lcd.print(string3);
    lcd.setCursor(0,1);
    lcd.print(string1);
    lcd.setCursor(0,2);
    lcd.print(string2);
  }
  else if (buttonCounter == 3){
    buttonCounter == 0;
    lcd.setCursor(0,0);
    lcd.print(string1);
    lcd.setCursor(0,1);
    lcd.print(string2);
    lcd.setCursor(0,2);
    lcd.print(string3);
  }
  old_buttonState = buttonState;
}

The next step would be to learn about arrays so you don't have string1, string2, string 3 and then if will get reduced to one for() loop rather than a lot of if/else statements.

You could use something like this

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