Scrolling text on 16×2 LCD controlled by pushbuttons

In this project I’m going to use an Arduino Uno to scroll some text on a 16×2 character LCD which is controlled with a pair of pushbuttons. Even if there’s nothing very fancy or original here I think I came out with some features that could be of interest for many beginners and the project can easily be extended to do more. You can consider it as an “advanced Hello World!” example.


In this project the 16×2 LCD (16 cols and 2 rows) is showing a scrollable text on a single line and the user can control the scrolling using two pushbuttons (left and right scrolling). A red LED is used to signal the user when it reaches the end (or the beginning) of the text and no more scrolling is possible. The brightness of the screen is controlled via code and the contrast of the text is controlled with a 10k potentiometer.

When connecting Arduino to a power source the LCD remains off (no backlight and no text showed) and the user needs to push the two pushbuttons simultaneously to turn it on. This is done implementing a very basic state machine (with only two states: OFF and ON) in the main loop.


This is what I used for this project:

  • 1x Arduino Uno
  • 1x large 700 tie-points breadboard
  • 1x 16×2 LCD
  • 1x 10K potentiometer
  • 2x pushbuttons
  • 1x 3mm red LED
  • 2x 10kΩ resistors
  • 2x 220Ω resistors
  • 24x jumper wires (male-male)

Considering the number of wires and the components used I recommend to use a bigger breadboard, possibly with two distribution strips per side. Obviously it’s not a big deal if you don’t have one.


The wiring for the LCD is pretty standard, the same you can find in any project using an LC compatible with the Hitachi HD44780 driver.

The only difference with most of the projects I’ve seen so far  is with the 4 data pins: usually the four LCD data pins (D4-D7) are connected to Arduino pins 5, 4, 3, 2 so in inverted order, instead I decided to keep a straight order, i.e.: D4 is connected to P2, D5 to P3, etc…

Obviously you can decide to use the order you want for the data pins, but you’ll need to remember that when initializing the LCD object in code, as you’re going to see shortly.

Nothing special about the wiring for the pushbuttons and the LED so let’s move to the sketch code.


For this tutorial I decided to split the sketch in 3 blocks of code:

  1. constants and globals
  2. initialization
  3. main loop

That’s just for clarity, so if you want to use this code in your project you’ll need to copy and paste the three blocks in a single file or you can download it from our website.

In the first block there’s all the code used to declare and initialize global and constant data.

#include <LiquidCrystal.h>

// -- PINS --
const int PIN_LCD_LED = 6;  // analog

const int PIN_ERR_LED = 7;  // digital
const int PIN_BUTTON1 = 8;  // digital
const int PIN_BUTTON2 = 9;  // digital

// -- LCD --
// PIN 12   -> RS
// PIN 11   -> Enable
// PINS 2-5 -> D4-7
LiquidCrystal lcd(12, 11, 2, 3, 4, 5);
// number of columns in the LCD
const int LCD_COLS = 16;
// LCD brightness [0, 255]
const int LCD_BRIGHTNESS = 128;
// LCD ON or OFF
int state_lcd = LOW;
// start position for text
int lcd_start = 0;

// -- LED --
// LOW -> LED is OFF - HIGH -> LED is ON
int state_led = LOW;
// stores time when turned LED on
unsigned long t0_led;
// timeout to turn the LED off
const int LED_TIMEOUT = 500;

// -- text to print --
// ASSUMPTION: text always longer than LCD_COLS, if not add a check in loop
const char TEXT[] = "This is a long text brought to you by";
const int TEXT_LEN = (sizeof(TEXT) / sizeof(char)) - 1;

Comments and names used for variables and constants should be enough to understand what’s going on there, so let’s move to the second block.

The setup() function is used to initialize the Arduino Uno and it’s divided in 3 parts:
in the first one (lines 5-8) digital pins are declared according to their usage (INPUT or OUTPUT), in the second one (lines 11-13) the LCD is initialized and turned off, finally the last part (line 16) is used to send a digital signal to the LED (to be sure it’s off).

void setup()
  pinMode(PIN_BUTTON1, INPUT);
  pinMode(PIN_BUTTON2, INPUT);


  // -- SET UP LCD --
  digitalWrite(PIN_LCD_LED, state_lcd);

  // ERROR LED is off when starting
  digitalWrite(PIN_ERR_LED, state_led);

The main loop() uses two states for the LCD: ON and OFF.

When running the loop for the first time after the initialization the LCD is in the first state (OFF) and the code (lines 9-22) is just checking if the user is pushing the two buttons simultaneously. When that happens the LCD is turned on and the device turns into the second state (ON).

// === MAIN LOOP ===
void loop()
  // -- read buttons --
  int state_button1 = digitalRead(PIN_BUTTON1);
  int state_button2 = digitalRead(PIN_BUTTON2);

  // == LCD STILL OFF ==
  if(LOW == state_lcd)
    // pushing both buttons -> turn LCD on
    if(HIGH == state_button1 && HIGH == state_button2)
      analogWrite(PIN_LCD_LED, LCD_BRIGHTNESS);


      state_lcd = HIGH;

  else  // == LCD ON ==
    // pushed button 1 -> try to scroll left or turn LED on if can't
    if(HIGH == state_button1)
      if(lcd_start > 0)

        state_led = LOW;
        digitalWrite(PIN_ERR_LED, state_led);

        state_led = HIGH;
        digitalWrite(PIN_ERR_LED, state_led);

        t0_led = millis();

    // pushed button 2 -> try to scroll right or turn LED on if can't
    if(HIGH == state_button2)
      if(lcd_start < LCD_LIMIT)

        state_led = LOW;
        digitalWrite(PIN_ERR_LED, state_led);

        state_led = HIGH;
        digitalWrite(PIN_ERR_LED, state_led);

        t0_led = millis();

    // -- print text on the LCD --
    for(int i = 0; i < LCD_COLS; i++)
      lcd.setCursor(i, 0);
      lcd.print(TEXT[lcd_start + i]);

    // ERROR LED is ON
    if(HIGH == state_led)
      unsigned long td = millis() - t0_led;

      // LED has been ON for more than LED_TIMEOUT ms. -> turn it OFF
      if(td > LED_TIMEOUT)
        state_led = LOW;
        digitalWrite(PIN_ERR_LED, state_led);

  // normally 20FPS
// === MAIN LOOP END ===

When running the loop in the second state the first part of the code (lines 26-65) is checking if any button is pressed to control the scrolling, the second part (lines 68-72) is printing the text on the LCD and the last one (lines 75-85) is managing the red LED used to signal the end of the text, a timeout is used to turn the red LED off after a short time.

As I tried to keep the sketch as simple as possible there’s no code to debounce the pushbuttons input, instead a simple debounce is achieved using delays, probably not the most elegant solution possible, but it’s simple and it works just fine for the project.

Project in action

Finally a short video to show you the project in action:


I hope you enjoyed this simple project and that everything was clear, but if you have any question don’t hesitate to leave a comment and I’ll be happy to answer.


Leave a Comment

Your email address will not be published. Required fields are marked *