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.
Description
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.
Components
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.
Wiring
The wiring for the LCD is almost the same you can find in the “Hello World!” example on the Arduino website, so I’m not going to spend much words on it.
The only difference is with the 4 data pins: in the original example 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.
Sketch
For this tutorial I decided to split the sketch in 3 blocks of code:
- constants and globals
- initialization
- 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.
In the first block there’s all the code used to declare and initialize global and constant data.
#include <LiquidCrystal.h> // === CONSTANTS AND GLOBALS === // -- 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 www.nudatech.com"; const int TEXT_LEN = (sizeof(TEXT) / sizeof(char)) - 1; const int LCD_LIMIT = TEXT_LEN - LCD_COLS; // === CONSTANTS AND GLOBALS END ===
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).
// === INITIALIZATION ===
void setup()
{
// -- SET DIGITAL PINS --
pinMode(PIN_BUTTON1, INPUT);
pinMode(PIN_BUTTON2, INPUT);
pinMode(PIN_ERR_LED, OUTPUT);
// -- SET UP LCD --
lcd.begin(16,2);
lcd.noDisplay();
digitalWrite(PIN_LCD_LED, state_lcd);
// ERROR LED is off when starting
digitalWrite(PIN_ERR_LED, state_led);
}
// === INITIALIZATION END ===
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);
lcd.display();
state_lcd = HIGH;
delay(250);
}
}
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)
{
lcd_start--;
state_led = LOW;
digitalWrite(PIN_ERR_LED, state_led);
delay(200);
}
else
{
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)
{
lcd_start++;
state_led = LOW;
digitalWrite(PIN_ERR_LED, state_led);
delay(200);
}
else
{
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
delay(50);
}
// === 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:
Download YouTube Video | YouTube Converter
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.



Please don’t use Yoda-conditions.
(e.g. ‘if blue = sky then ..’)
Why not?
They avoid errors like the one in your example code
I don’t see how they can help to avoid errors.
What’s wrong w/ my pseudo-code?
= is an assignment operator
== is a comparison operator
if(var == value) and if(value == var) are exactly the same thing, but the latter gives you safer code. i.e.:
if(var = value) // hard to find error
if(value = var) // error raised at compile time
Hey, thanks a lot for sharing this project, it’s helpful.
If i understood well, the string “lcd_start++” is to scroll right and “lcd_start–” it’s to scroll left.
I have a question: If we would like to scroll up and down instead of right and left, displaying different parameters ( exemple: T1, T2 -> scroll down -> T2, humidity1 -> scroll down -> humidity1, humidity2 -> …) what should I put in the code?
I am at the beginning with arduino, i hope you can help me. It would be great if you had some references i could eventually have.
Michael daldini