Connecting an LCD display to your Raspberry Pi is sure to take any project up a notch. They’re great for displaying sensor readings, songs or internet radio stations, and stuff from the web like tweets and stock quotes. Whatever you choose to display, LCDs are a simple and inexpensive way to do it.

In this tutorial, I’ll show you two different ways to connect an LCD to the Raspberry Pi with the GPIO pins. The first way I’ll show you is in 8 bit mode, which uses 10 GPIO pins. Then I’ll show you how to connect it in 4 bit mode, and that uses only 6 pins. After we get the LCD hooked up I’ll show you how to program it with C, using Gordon Henderson’s WiringPi LCD library.

I’ll show you how to print text to the display, clear the screen, position the text, and control the cursor. You’ll also see how to scroll text, create custom characters, print data from a sensor, and print the date, time and IP address of your Pi.

BONUS: I made a quick start guide for this tutorial that you can download and go back to later if you can’t set this up right now. It covers all of the steps, diagrams, and code you need to get started.

I’ll be using a 16X2 LCD display here, but the examples below will work with any LCD that uses the Hitachi HD44780 driver.

If your project uses Python, we have another article that will show you how to program the LCD in Python.

There’s another way to connect your LCD that uses only two wires, called I2C. To see how to do that, check out our tutorial How to Set Up an I2C LCD on the Raspberry Pi.

Here’s a video you can watch for a quick demonstration of the set up and example programs:

Connecting the LCD

Most people probably want to connect their LCD in 4 bit mode since it uses less wires. But in case you’re interested, I’ll show you how to connect it in 8 bit mode as well.

Wiring the LCD in 8 Bit Mode

In 8 bit mode, each command or character is sent to the LCD as a single byte (8 bits) of data. The byte travels in parallel over 8 data wires, with each bit travelling through it’s own wire. 8 bit mode has twice the bandwidth as 4 bit mode, which in theory translates to higher data transfer speed. The main downside to 8 bit mode is that it uses up a lot of GPIO pins.

Connecting the LCD in 8 bit mode requires 10 GPIO pins:

Raspberry Pi LCD 8 Bit Mode Connection Diagram

The brightness and contrast potentiometers are 10K Ohm, but you can also use 1K to 3K Ohm resistors here.

Wiring the LCD in 4 Bit Mode

In 4 bit mode, each byte of data is sent to the LCD in two sets of 4 bits, one after the other, in what are known as the upper bits and lower bits. Although 8 bit mode transfers data about twice as fast as 4 bit mode, it takes a longer time for the LCD driver to process each byte than it takes to transmit the byte. So in reality, there isn’t really a noticeable difference in speed between 4 bit mode and 8 bit mode.

4 bit mode takes up only 6 GPIO pins for input/output, which makes it a popular choice for many projects:

Raspberry Pi LCD 4 bit mode

The brightness and contrast potentiometers are 10K Ohm, but 1K to 3K Ohm resistors will work as well.

Programming the LCD With C

If you’ve never worked with C programs on the Raspberry Pi, you may want to read our article How to Write and Run a C Program on the Raspberry Pi first. It will explain how to write, compile, and run C programs.

Install WiringPi

WiringPi is a C module that makes it easy to program the LCD. If you already have WiringPi installed on your Pi, you can skip this section. If not, follow the steps below to install it:

1. We can download WiringPi using Git. Your Pi may have Git already installed (if so skip this step), but if not, enter this at the command prompt:

sudo apt-get install git-core

  • Note: If you get an error installing Git, run sudo apt-get update and try it again.

2. Now download WiringPi by entering this at the command prompt:

git clone git://git.drogon.net/wiringPi

3. Enter this to change directories:

cd wiringPi

4. Run the installation script with:

./build

5. Test the installation by entering:

gpio -v

Followed by:

gpio readall

Now we’re ready to start programming the LCD!

Examples

All of the examples below are stand-alone C programs, which will need to be complied by entering this at the command prompt:

gcc -o example example.c -lwiringPi -lwiringPiDev

Change example and example.c to the file name you want to use.

After the program is compiled, it can be executed by entering this at the command prompt:

sudo ./example

WiringPi has it’s own pin numbering system that’s different from the Broadcom (BCM) and RPi physical (BOARD) pin numbering systems. All of the programs below use the WiringPi pin numbers.

Write to the LCD in 8 Bit Mode

This program is the minimum code needed to initialize the LCD and print “Hello, world!” to it:

#include <wiringPi.h>
#include <lcd.h>

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D0  29               //Data pin D0
#define LCD_D1  28               //Data pin D1
#define LCD_D2  27               //Data pin D2
#define LCD_D3  26               //Data pin D3
#define LCD_D4  23               //Data pin D4
#define LCD_D5  22               //Data pin D5
#define LCD_D6  21               //Data pin D6
#define LCD_D7  14               //Data pin D7
 
int main()
{
    int lcd;
    wiringPiSetup();
    lcd = lcdInit (2, 16, 8, LCD_RS, LCD_E, LCD_D0, LCD_D1, LCD_D2, LCD_D3, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

    lcdPuts(lcd, "Hello, world!");
}

To use different pins to connect the LCD, change the pin numbers defined in lines 5 to 14. You’ll need to convert the WiringPi pin numbers to the physical pin numbers of the Raspberry Pi. See here for a diagram you can use to convert between the different numbering systems.

The function in line 20 is used to initialize the LCD:

lcd = lcdInit (ROWS, COLUMNS, BIT MODE, LCD_RS, LCD_E, LCD_D0, LCD_D1, LCD_D2, LCD_D3, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

The function lcdPuts(lcd, "Hello, world!") prints “Hello, world!” to the screen.

Write to the LCD in 4 Bit Mode

To use the LCD in 4 bit mode, we need to set the bit mode number to 4 in the initialization function (line 20 below). The following code prints “Hello, world!” to the screen in 4 bit mode:

#include <wiringPi.h>          
#include <lcd.h>               
 
//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7
 
int main()
{
    int lcd;               
    wiringPiSetup();        
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);
               
    lcdPuts(lcd, "Hello, world!");   
}

Position the Text

By default, text is printed to the screen at the top row, second column. To change the position, use lcdPosition(lcd, COLUMN, ROW). On a 16×2 LCD, the rows are numbered from 0 to 1, and the columns are numbered from 0 to 15.

The following code prints “Hello, world!” to the bottom row, fourth column:

#include <wiringPi.h>           
#include <lcd.h>                
 
//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7
 
int main()
{
    int lcd;               
    wiringPiSetup();        
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);
    
    lcdPosition(lcd, 3, 1); 
    lcdPuts(lcd, "Hello, world!");   
}

Clear the Screen

The function lcdClear(lcd) clears the screen and sets the cursor position at the top row, first column. This program prints “This is how you” for two seconds, clears the screen, then prints “clear the screen” for another two seconds:

#include <wiringPi.h>          
#include <lcd.h>               
 
//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7
 
int main()
{
    int lcd;               
    wiringPiSetup();        
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);
               
    lcdPuts(lcd, "This is how you"); 
    sleep(2);
    lcdClear(lcd);  

    lcdPuts(lcd, "clear the screen"); 
    sleep(2);
    lcdClear(lcd);
}

Notice how the first string is printed to the top row, second column (the default position). Then after clearing the screen, the second string is printed to the top row, first column.

Blinking Text

Using a while loop with lcdclear() and lcdputs() creates a blinking text effect:

#include <wiringPi.h>
#include <lcd.h>

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7

int main()
{
    int lcd;
    wiringPiSetup();
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);

    while(1){
        lcdPosition(lcd, 0, 0);
        lcdPuts(lcd, "Hello, world!");
        sleep(2);
        lcdClear(lcd);
        sleep(2);
        }
}

Press Ctrl-C to exit the program.

Turn the Cursor On and Off

The cursor is turned off by default, but you can get different styles of cursors using the following functions:

  • Underline non-blinking cursor: lcdCursor(lcd, 1)
  • Underline blinking cursor: lcdCursor(lcd, 1), followed by lcdCursorBlink(lcd, 1)
  • Blinking block style cursor: lcdCursorBlink(lcd, 1)
  • Cursor off : lcdCursor(lcd, 0)
#include <wiringPi.h>          
#include <lcd.h>               

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7

int main()
{
    int lcd;
    wiringPiSetup();
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);

    //lcdCursor(lcd, 0); //Cursor OFF
   
    lcdCursor(lcd, 1); //Cursor ON, underline, not blinking
    //lcdCursorBlink(lcd, 1); //Cursor ON, block, blinking    
    
    //Use both lines below to get a blinking underline/block cursor 
    //lcdCursor(lcd, 1);
    //lcdCursorBlink(lcd, 1);

    lcdPuts(lcd, "Hello, world!");
}

Print the Date and Time

This program will print the current date and time to the LCD:

#include <wiringPi.h>         
#include <lcd.h>               
#include <stdio.h>
#include <time.h>

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7

int main()
{
    int lcd;
    wiringPiSetup();
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);

    while(1){
        time_t timer;
        char buffer_date[26];
        char buffer_time[26];
        struct tm* tm_info;

        time(&timer);
        tm_info = localtime(&timer);

        strftime(buffer_date, 26, "Date: %m:%d:%Y", tm_info);
        strftime(buffer_time, 26, "Time: %H:%M:%S", tm_info);

        lcdPosition(lcd, 0, 0);
        lcdPuts(lcd, buffer_date);

        lcdPosition(lcd, 0, 1);
        lcdPuts(lcd, buffer_time);

        }
}

Print Your IP Address

This program prints the IP address of your ethernet connection (eth0). To get the IP of your WiFi connection, change eth0 to wlan0 in line 30:

#include <wiringPi.h>          
#include <lcd.h>                

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <arpa/inet.h>

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7

int main()
{
    int lcd;
    wiringPiSetup();
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);

    int n;
    struct ifreq ifr;
    char iface[] = "eth0"; //Change this to the network of your choice (eth0, wlan0, etc.)

    n = socket(AF_INET, SOCK_DGRAM, 0);
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name , iface , IFNAMSIZ - 1);
    ioctl(n, SIOCGIFADDR, &ifr);
    close(n);

    lcdPosition(lcd, 0, 0);
    lcdPrintf(lcd, "IP Address: ");

    lcdPosition(lcd, 0, 1);
    lcdPrintf(lcd, ("%s - %s\n" , iface , inet_ntoa(( (struct sockaddr_in *)&ifr.ifr_addr )->sin_addr)));
    return 0;
}

Custom Characters

Each LCD character is a 5×8 array of pixels. You can create any pattern you want and display it on the LCD as a custom character. Up to 8 custom characters can be stored in the LCD memory at a time. This website has a nice visual way to generate the bit array used to define custom characters.

Printing a Single Custom Character

To print a single custom character, first define the character. For an example of this see lines 12 to 19 below. Then use the function lcdCharDef(lcd, 2, omega) to store the character in the LCD’s memory. The number 2 in this example is one of the 8 locations in the LCD’s character memory. The 8 locations are numbered 0-7. Then, print the character to the display with lcdPutchar(lcd, 2), where the number 2 is the character stored in memory location 2.

This program prints the Greek letter omega to the LCD:

#include <wiringPi.h>           
#include <lcd.h>                

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7

char omega[8] = { 0b00000,
                  0b01110,
                  0b10001,
                  0b10001,
                  0b10001,
                  0b01010,
                  0b11011,
                  0b00000};

void customChar(void);
int lcd;

int main()
{
    int lcd;
    wiringPiSetup();
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);

    customChar();
}

void customChar(void)
{
        lcdCharDef(lcd, 2, omega);
        
        lcdClear(lcd);
        lcdPutchar(lcd, 2);
        sleep(3);
}

Printing Multiple Custom Characters

Here’s an example of using multiple custom characters that prints the Greek letters omega, pi, and mu, plus thermometer and water drop symbols for temperature and humidity:

#include <wiringPi.h>         
#include <lcd.h>                

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7

char omega[8] = { 0b00000,
                  0b01110,
                  0b10001,
                  0b10001,
                  0b10001,
                  0b01010,
                  0b11011,
                  0b00000};

char pi[8] = { 0b00000,
               0b00000,
               0b11111,
               0b01010,
               0b01010,
               0b01010,
               0b10011,
               0b00000};

char mu[8] = { 0b00000,
               0b10010,
               0b10010,
               0b10010,
               0b10010,
               0b11101,
               0b10000,
               0b10000};
               
char drop[8] = { 0b00100,
	             0b00100,
	             0b01010,
	             0b01010,
	             0b10001,
	             0b10001,
	             0b10001,
	             0b01110}; 
	       
char temp[8] = { 0b00100,
                 0b01010,
	             0b01010,
	             0b01110,
	             0b01110,
	             0b11111,
	             0b11111,
	             0b01110};

void customChar(void);
int lcd;

int main()
{
    int lcd;
    wiringPiSetup();
    lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);

    customChar();
}

void customChar(void)
{
        lcdCharDef(lcd, 10, omega); 
        lcdCharDef(lcd, 11, pi);
        lcdCharDef(lcd, 12, mu);
        lcdCharDef(lcd, 13, drop);
        lcdCharDef(lcd, 14, temp);

        lcdClear(lcd);

        lcdPutchar(lcd, 10);
        lcdPutchar(lcd, 11);
        lcdPutchar(lcd, 12);
        lcdPutchar(lcd, 13);
        lcdPutchar(lcd, 14);

        sleep(3);
}

Scrolling Text

Scroll Right to Left

This program will scroll text onto the display from right to left, then pause, clear the screen, and loop back to the beginning:

#include <stdio.h>
#include <wiringPi.h>
#include <lcd.h>
#include <string.h>

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7

void scrollText(void);
char message[] = "Hello, world!";
int count = 0;
int j = 0;
int lcd;

int main()
{
        wiringPiSetup();
        lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);
        while(1){
            scrollText();
            }
}

void  scrollText(void)
{
        int i, n;
        int h;
        int tempSpace = 0;
        char scrollPadding[] = "                ";
        int messageLength = strlen(scrollPadding) + strlen(message);
        for (n = 0; n < messageLength; n++){h = 16; usleep(300000); printf("\x1B[2J"); if (j > messageLength)
                        j = 0;

                for (i = 0; i < j ; i++){
                        scrollPadding[h - j] = message[i];
                h++;
                }
                lcdPosition(lcd, 0, 0);
                lcdClear(lcd);
                lcdPrintf(lcd, "%s", scrollPadding);
                j++;
        }
}

Scroll Left to Right

This program scrolls text in from left to right, then pauses, clears the screen, and loops back to the beginning:

#include <stdio.h>
#include <wiringPi.h>
#include <lcd.h>
#include <string.h>

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7

void scrollText(void);
char message[] = "Hello, world!";
int count = 0;
int j = 0;
int lcd;

int main()
{
        wiringPiSetup();
        lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);
        while(1){
            scrollText();
            }
}

void  scrollText(void)
{
        int i, n;
        int h;
        int tempSpace = 0;
        char scrollPadding[] = "                ";
        int messageLength = strlen(scrollPadding) + strlen(message);
        for (n = 0; n < messageLength; n++){h = 16; usleep(300000); printf("\x1B[2J"); if (j > messageLength)
                        j = 0;

                for (i = strlen(message); i >= 0; i--){
                        scrollPadding[j - h] = message[i];
                h++;
                }
                lcdPosition(lcd, 0, 0);
                lcdClear(lcd);
                lcdPrintf(lcd, "%s", scrollPadding);
                j++;
        }
}

Print Data From a Sensor

As an example to show you how to display readings from a sensor, this program prints temperature and humidity readings to the LCD using a DHT11 temperature and humidity sensor. To see how to set up the DHT11 on the Raspberry Pi, see our article How to Set Up the DHT11 Humidity Sensor on the Raspberry Pi.

The signal pin of the DHT11 is connected to physical pin 7 of the Raspberry Pi:

#include <wiringPi.h>
#include <lcd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

//USE WIRINGPI PIN NUMBERS
#define LCD_RS  25               //Register select pin
#define LCD_E   24               //Enable Pin
#define LCD_D4  23               //Data pin 4
#define LCD_D5  22               //Data pin 5
#define LCD_D6  21               //Data pin 6
#define LCD_D7  14               //Data pin 7
#define MAXTIMINGS 85
#define DHTPIN 7

int lcd;
int dht11_dat[5] = {0, 0, 0, 0, 0};

void read_dht11_dat()
{
        uint8_t laststate = HIGH;
        uint8_t counter = 0;
        uint8_t j = 0, i;
        float f; 

        dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;

        pinMode(DHTPIN, OUTPUT);
        digitalWrite(DHTPIN, LOW);
        delay(18);
        
        digitalWrite(DHTPIN, HIGH);
        delayMicroseconds(40);
        
        pinMode(DHTPIN, INPUT);

        for (i = 0; i < MAXTIMINGS; i++)
        {
                counter = 0;
                while (digitalRead(DHTPIN) == laststate)
                {
                        counter++;
                        delayMicroseconds(1);
                        if (counter == 255)
                        {
                                break;
                        }
                }
                laststate = digitalRead(DHTPIN);

                if (counter == 255)
                        break;

                if ((i >= 4) && (i % 2 == 0))
                {
                        dht11_dat[j / 8] <<= 1;
                        if (counter > 16)
                                dht11_dat[j / 8] |= 1;
                        j++;
                }
         }

        if ((j >= 40) && (dht11_dat[4] == ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF)))
        {
                f = dht11_dat[2] * 9. / 5. + 32;

                lcdPosition(lcd, 0, 0);
                lcdPrintf(lcd, "Humidity: %d.%d %%\n", dht11_dat[0], dht11_dat[1]);

                lcdPosition(lcd, 0, 1);
                //lcdPrintf(lcd, "Temp: %d.0 C", dht11_dat[2]); //Uncomment for Celsius
                lcdPrintf(lcd, "Temp: %.1f F", f); //Comment out for Celsius
        }
}

int main(void)
{
        int lcd;
        wiringPiSetup();
        lcd = lcdInit (2, 16, 4, LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 0, 0, 0, 0);
        
        while (1)
        {
                read_dht11_dat();
                delay(1000); 
        }

        return(0);
}

For temperature in Celsius, un-comment line 72, then comment out line 73.

Hopefully this helped you get your LCD up and running on your Raspberry Pi. The programs above are just basic examples, so try combining them to create interesting effects and animations.

If you have any problems or questions about installing the LCD or programming it, just leave a comment below. And don’t forget to subscribe to get an email when we publish new articles. Talk to you next time!