Hello there!! In this post I’ll tell you about 16×2 LCD’s and their interfacing in 8 bit mode. As you all know LCD stands for liquid crystal display. Now earlier we used to use 7 segment displays for display purposes, but now LCD’s are preferred. The main reason is we need less number of databus lines for interfacing LCD’s as compared to 7 segment displays. Other reason is we can print various characters on the screen. Now the basic characters are already saved inside CGROM(Character Generator ROM). So you need to send only the ASCII values in order to display the character on screen. So let us see what a 16×2 LCD reakky means. It has 2 rows and 16 columns. So basically a 16×2 LCD has 32 blocks where one can display data. Each block has certain number of pixels. You can draw your own character by saving the pattern of pixels.

Ok then let’s begin. First things first lets get the datasheet. The link is : Datasheet Link

Please download the datasheet because a datasheet tells you everything there is to know the electrical parameters, command registers, pin-outs and so on. Assuming you have the datasheet with you, let’s go further.

Pin-out:

Now there is a protruding rectangular portion on this LCD. This will help you identify which pin is which. Now let us see what each pin does exactly. But then they have also printed 16 and 1 on the back of LCD, so no need to worry about connecting the pins inverted.

The pin features are explained in the table. The contrast adjust input is nothing but output taken from a pot.

So basically when you vary the pot , you get different values of voltage from the voltage divider network. And thus you can change the contrast to suit your visual needs. (Caution: Do not give the LCD voltage greater than 5 Volts. Your LCD may get damaged. By more I’m not talking about 5.1 Volts but 6 V and beyond.)

RS, R/W,E are the control signals of LCD. DB0 to DB7 are the databus lines. You send the command word as well as the data to be written on this bus.

Let’s see a little about the control signals first.

RS : This stands for register select. The two registers in LCD are the data register and the command word/code register. In order to tell LCD that the bits on databus are for which register we make use of RS control signal via the RS pin. When you make this pin high you select data register, where you’ll send the ASCII values to be displayed on screen. When you make RS low you select the command word register where you’ll be sending all the commands for configuring and initializing the LCD.

RS = 1 —–> Data Register

RS = 0 —–> Command Code Register

R/W : This stands for read or write. The read is active high signal and write is active low. Thus when you want to read from the LCD you make the signal on this pin high and when you want to write you make the signal on this pin low.

R/W = 1 —-> Read Operation

R/W = 0 —-> Write Operation.

(For those who are wondering why W has no bar on its top indicating an active low signal, there should be one. Its just that I don’t know how to type W bar!!)

E : This stands for enable. This is a edge triggering signal which is used while writing or reading data to/from LCD respectively. E line is negative edge triggered for write while it is positive edge triggered for the read. The timing diagram given in datasheet tells about the minimum delay between the level transitions.

E = high to low / negative edge triggered —-> Write

E = low to high / positive edge triggered —-> Read

Busy Flag : The concept of busy flag is beautiful. Now the LCD internal processor takes time to latch and make the necessary adjustments as per the command word. While the LCD’s internal processor is busy this flag is set. So one should check the status of this flag before sending the next command word or data. D7 is the busy flag pin. You’ll have to configure the port pin connected to D7 pin as input while checking the flag condition. Along with this we need to make RS = 0 and R/W = 1 , since this is read operation and busy flag is given by command code register mode.

Busy Flag = 1 —-> LCD Busy

Busy Flag = 0 —-> LCD can take next data/command

Well you can give delays also for LCD to finish work, but this is better way if you have enough port pins. Because for reading busy flag status you need R/W signal and thus a port pin.

List of LCD Instructions

Using the above table you can make any command byte. For example we’ll be using this LCD in 8 bit mode so make DL = 1, N = 1 and F =0 respectively. The hexadecimal value that we get is 0x38/038h. This is the command word that we must send to the LCD to initialize it in 8 bit mode and use 2 lines with 5×7 dots.

So these are few of the instruction codes that you come across frequently. Of course you can make these on your own by using the command code syntax table.

DDRAM address:

Display data random access memory. This is where the data you send to data register is stored. And it so happens that you can send the address of block to the command code register to position the cursor at that particular block. For example you want to position the cursor at row 2 column 10 , just send 0CAh to the command code register. So that is about the DDRAM and positioning the cursor.

Connection Diagram:

The connections are shown in the above pictures.

Code:

/* 8bit_lcd.h * Created on: 12-Nov-2013 * Author: Manpreet */ #include <msp430g2553.h>; #define DR P2OUT = P2OUT | BIT0 // define RS high #define CWR P2OUT = P2OUT & (~BIT0) // define RS low #define READ P2OUT = P2OUT | BIT1 // define Read signal R/W = 1 for reading #define WRITE P2OUT = P2OUT & (~BIT1) // define Write signal R/W = 0 for writing #define ENABLE_HIGH P2OUT = P2OUT | BIT2 // define Enable high signal #define ENABLE_LOW P2OUT = P2OUT & (~BIT2) // define Enable Low signal unsigned int i; unsigned int j; void delay(unsigned int k) { for(j=0;j<=k;j++) { for(i=0;i<100;i++); } } void data_write(void) { ENABLE_HIGH; delay(2); ENABLE_LOW; } void data_read(void) { ENABLE_LOW; delay(2); ENABLE_HIGH; } void check_busy(void) { P1DIR &= ~(BIT7); // make P1.7 as input while((P1IN&BIT7)==1) { data_read(); } P1DIR |= BIT7; // make P1.7 as output } void send_command(unsigned char cmd) { check_busy(); WRITE; CWR; P1OUT = (P1OUT & 0x00)|(cmd); data_write(); // give enable trigger } void send_data(unsigned char data) { check_busy(); WRITE; DR; P1OUT = (P1OUT & 0x00)|(data); data_write(); // give enable trigger } void send_string(char *s) { while(*s) { send_data(*s); s++; } } void lcd_init(void) { P2DIR |= 0xFF; P1DIR |= 0xFF; P2OUT &= 0x00; P1OUT &= 0x00; send_command(0x38); // 8 bit mode send_command(0x0E); // clear the screen send_command(0x01); // display on cursor on send_command(0x06);// increment cursor send_command(0x80);// cursor position }

Sample Code

/* LCD_own.c * Created on: 12-Nov-2013 * Author: Manpreet * In this program we interface the lcd in 8 bit mode. We send strings and display it on the screen. */ #include "8bit_lcd.h" void main(void) { WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer lcd_init(); send_string("Manpreet Singh"); send_command(0xC0); send_string("Minhas"); while(1){} }

For code explanation watch:



Output:

This is all regarding the 8 bit mode interfacing. I’ll be writing about 4 bit mode and creating custom character if I successfully learn and perform the same. Thank you for reading this post. Hope it was useful and informative.

References :

The 8051 Microcontroller and Embedded Systems using Assembly and C by Mazidi (ISBN-978-81-317-1026-5)

HD44780U Datasheet (Download Link)