In this post I’ll show how to connect and use a 16 x 2 LCD on a Raspberry Pi.
The LCD I am using is a Blue Character OLED(LCD) 16x2 from adafruit.
This display has ultra-high contrast and any-angle readability. It has the best display I have seen on any LCD.
This LCD uses the HD44780 controller which is present in almost all LCDs.
LCDs that use this controller usually have 14 or 16 pins. This LCD has 16, numbered from 0 to 16 as shown below.
![]() | ![]() |
Sometimes these pins are present, but not used. Eg, pins 15 & 16 are for back-light and they are not used on this LCD. It depends on the manufacture.
HD44780 pins in Detail | |
---|---|
Pin 1 | Ground. |
Pin 2 | Supply Voltage for OLED and logic |
Pin 3 | Is usually connected to a potentiometer to control the contrast of the display. |
Pin 4 | The register select signal (RS) determines whether the Data Bit values are interpreted as a command (E.g. clear screen) or data (aka: a character to display). |
Pin 5 | Is the Read/Write pin. In read mode, this pin is used to get feedback from the LCD to work out if the LCD can accept commands or to indicate it is too busy. We don’t need this function as we can wait the maximum time for a command to be written (200us) before sending the next command. If read is enabled and Pin4 on the LCD is connected to a pin on your Raspberry Pi, there is a chance that you can destroy your Pi. We only ever want to write to the LCD, we never want to read from it. So this should always be connected to ground. |
Pin 6 | The enable pin (E)functions as the command/data latching signal for the LCD. The LCD will latch in whatever is on the Data Bits and process it on the falling edge of the E signal Meaning, when this pin goes low, the LCD will take the input from the data pins at this time. |
Pins 7 to 14 | Are the data pins. In 4 pin mode, only pins 11 to 14 are used. |
Pins 15 & 16 | Are used for the backlight if present. |
Wiring the LCD up
Below shows how to wire up the LCD to the Raspberry Pi. We will be using 4 pin mode, so there is no need to connect pins 7 to 10. This LCD doesn't use the backlight pins, pins 15 and 16. It also doesn't use the contrast pin, pin 3.
Code
In the past, you would have had to know the registers used by the controller to setup the display, position the cursor or even write a single character. There was also timing issues to take into consideration. This is no more, with thanks to WiringPi.
Installing WiringPi;
pi@raspberrypi ~ $ git clone git://git.drogon.net/wiringPi
pi@raspberrypi ~ $ cd wiringPi
pi@raspberrypi ~ $ git pull origin
pi@raspberrypi ~ $ ./build
The code below is a very simple example of displaying some text on the top line of the LCD. There is a complete list of all the functions in the LCD library on the WiringPi website.
#include <wiringPi.h> //WiringPi headers #include <lcd.h> //LCD headers from WiringPi #include <stdio.h> //Needed for the printf function below //Pin numbers below are the WiringPi pin numbers #define LCD_RS 3 //Register select pin #define LCD_E 0 //Enable Pin #define LCD_D4 6 //Data pin 4 #define LCD_D5 1 //Data pin 5 #define LCD_D6 5 //Data pin 6 #define LCD_D7 4 //Data pin 7 int main() { int lcd; //Handle for LCD wiringPiSetup(); //Initialise WiringPi //Initialise LCD(int rows, int cols, int bits, int rs, int enable, int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7) if (lcd = lcdInit (2, 16,4, LCD_RS, LCD_E ,LCD_D4 , LCD_D5, LCD_D6,LCD_D7,0,0,0,0)){ printf ("lcdInit failed! \n"); return -1 ; } lcdPosition(lcd,0,0); //Position cursor on the first line in the first column lcdPuts(lcd, "Character LCD"); //Print the text on the LCD at the current cursor postion getchar(); //Wait for key press lcdClear(lcd); //Clear the display }
- Lines 1 and 2 are required as these are the headers for the WiringPi LCD library.
- Lines 7 to 12 are the definitions for the pins used to connect the LCD to the Raspberry Pi. Pin numbers can be found here.
- Line 21 will initialise the LCD with lcdInit()
The augments used in the lcdint() function are;
(int rows, int cols, int bits, int rs, int enable, int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7)
rows = Number of rows on the LCD
cols = Number of columns on the LCD
bits = Number of bits or data pins used. Either 8 or 4.
rs = Register select pin
enable = Enable pin
d0-d7 = 8 or 4 bit mode. In for 4 bit mode, only specificity pins from d0 to d3. If using 8 bit mode, you need to specify pins from d0 to d7. In the example code above, we are using 4 bit mode.
The code below is what was used in the video at the top of this post
Compile with;
#include <signal.h> #include <stdlib.h> #include <stdio.h> #include <wiringPi.h> #include <lcd.h> #include <string.h> #include <time.h> char level0[8] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111}; char level1[8] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111}; char level2[8] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111}; char level3[8] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111}; char level4[8] = { 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}; char level5[8] = { 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}; char level6[8] = { 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}; char level7[8] = { 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}; #define COLUMNS 16 #define LCD_RS 3 #define LCD_E 0 #define LCD_D4 6 #define LCD_D5 1 #define LCD_D6 5 #define LCD_D7 4 void uptime(void); void memory(void); void volume(void); void scrollText(void); void INThandler(int sig); int mymillis(void); char message[] = "WWW.OZZMAKER.COM"; int count =0; int j = 0; FILE *uptime_file, *mem_file; char *temp; int lcd; int main() { signal(SIGINT, INThandler); wiringPiSetup () ; if (lcd = lcdInit (2, 16,4, LCD_RS, LCD_E ,LCD_D4 , LCD_D5, LCD_D6,LCD_D7,0,0,0,0)){ printf ("lcdInit failed! \n"); return -1 ; } int uptimeTimer; while(1){ lcdClear (lcd); volume(); sleep(1); memory(); sleep(4); lcdClear (lcd); uptimeTimer = mymillis(); while ((mymillis() - uptimeTimer) < 5000) uptime(); sleep(1); lcdClear (lcd); scrollText(); } } void uptime(void) { unsigned int uptime_unsorted = 0; unsigned char c; unsigned int DD; unsigned int HH; unsigned int MM; unsigned int SS; uptime_file=fopen("/proc/uptime","r"); if(NULL != uptime_file) { while((c=fgetc(uptime_file))!= '.') { unsigned int i; i = atoi(&c); uptime_unsorted = (uptime_unsorted * 10) + i; } SS = uptime_unsorted % 60; MM = uptime_unsorted / 60 % 60; HH = uptime_unsorted / 60 / 60 % 24; DD = uptime_unsorted / 60 / 60 / 24; printf("\x1B[2J"); printf("Uptime:D%i,%02i:%02i:%02i\n",DD,HH,MM,SS); lcdPosition(lcd,0,0); lcdPrintf(lcd,"Uptime: Days %i", DD); lcdPosition(lcd,4,1); lcdPrintf(lcd,"%02i:%02i:%02i",HH,MM,SS); } else { printf("Open file \"proc/uptime\" failed!\n"); } } void memory(void) { char MemTotal[35]; char MemFree[35]; char total[35]; char free[35]; lcdClear (lcd); mem_file=fopen("/proc/meminfo","r"); if(NULL != mem_file) { fscanf(mem_file,"%*s%s%*s", MemTotal); fscanf(mem_file,"%*s%s%*s", MemFree); printf("\x1B[2J"); lcdPosition(lcd,0,0); lcdPrintf(lcd,"MemTotal-%sk",MemTotal); lcdPosition(lcd,0,1); lcdPrintf(lcd,"MemFree -%sk",MemFree); fclose(mem_file); } else { printf("Open file \"/proc/meminfo\" failed!\n"); } } void volume(void) { //Defined custom characters for volume display lcdCharDef (lcd, 0, level0); lcdCharDef (lcd, 1, level1); lcdCharDef (lcd, 2, level2); lcdCharDef (lcd, 3, level3); lcdCharDef (lcd, 4, level4); lcdCharDef (lcd, 5, level5); lcdCharDef (lcd, 6, level6); lcdCharDef (lcd, 7, level7); lcdClear (lcd); int i; lcdPosition (lcd, 9,1); lcdPuts (lcd, ":Volume"); for (i = 0; i < 7; i++){ lcdPosition (lcd, i, 1); lcdPutchar (lcd, i); usleep(400000); } } 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 = COLUMNS; 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++; } } void INThandler(int sig) { lcdClear (lcd); fclose(uptime_file); signal(sig, SIG_IGN); exit(0); } int mymillis(void) { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec) * 1000 + (tv.tv_usec)/1000; }
[wp_ad_camp_1]
The LCD->Pi wiring diagram has an error, the sire from the LCD RS line (4) is going to the Pi connector pin 17 (3.3 v power), it should be going to ping 15 (GPIO3).
Ooops…
I have updated the diagram.
thanks!
i try compiling but found error
root@mobile:/home/pi# gcc lcd-lg.c
lcd-lg.c: In function âuptimeâ:
lcd-lg.c:215:1: error: expected declaration or statement at end of input
I have fixed the issue.
You need to compile with;
gcc -o lcd lcd.c -lwiringPi -lwiringPiDev
Thanks for your post. i have compiled the first code successfully but nothing was shown on the LCD . i used gcc -o lcd lcd.c -lwiringPi -lwiringPiDev to compile the code
pi@raspberrypi ~/wiringPi-f18c8f7/examples $ gcc -o lcd lcd1.c -lwiringPi -lwiringPiDev
pi@raspberrypi ~/wiringPi-f18c8f7/examples $
please help
thanks in advance
Now it works there was command missing which is sudo ./lcd ..i am new to gcc i got to know that the previous command is used to compile the code and the last one is used to play it .. thanks again for your post 🙂
when I used wiringPiSetupGpio() instead of wiringPiSetup() works fine
Hey, can you provide link to each library you have used?
THanks
Thanks… many.. many.. you made my day.. Initially it was not running …
I have to change only GPIO pins of Rpi, which I have done after going though lcd.c library
can it possible to replace a particular character on 16*2 lcd,if yes , please give me the code in c.on my er.saurabh2890@gmsil.com email id.
I Follow each step in this tutorial but nothing is displayed on the LCD. IThe code is compiled and running without any error. But no message appears in the display. Any Help would be more than greatful. Thanks 😉
Hello, my display for the first code does not show anything, and the second code show gibberish.. Can u please contact me and help me ? It woul be awesome ! Thank you, Tlásky.
hi TLASKY,
have you added 10k preset to pin no.3 on 16*2 lcd…..if not please add…..
any one can mail me code for servo motor…….. I’m facing some sort of problems.