Interfacing LCD 16x2 with ATMEGA32 AVR Microcontroller in 4-bit mode

Tashini Hansika
6 min readJan 17, 2022

--

Hello guys…! Today I came up with a very interesting and easy way to connect LCD with the Atmega32 microcontroller and code the LCD.

I used a 16x2 LCD module. The term LCD stands for liquid crystal display. It is one kind of electronic display module used in an extensive range of applications like mobile phones, calculators, computers, TV sets, etc. These displays are mainly preferred for multi-segment light-emitting diodes and seven segments. The main benefits of using this module are inexpensive, simply programmable, animations, and there are no limitations for displaying custom characters, special and even animations, etc.

The display has 16 pins. It has 8 data pins (D0-D7) and 3 control pins (RS, RW, EN). The remaining 5 pins are for supply and backlight for the LCD. In 4-bit mode, data/command is sent in a 4-bit format. Only 4 data (D4-D7) pins of 16x2 of LCD are connected to the microcontroller. The EN line is called ‘Enable’. This control line is used to tell the LCD that the microcontroller has sent data to it or the microcontroller is ready to receive data from the LCD. The RS line is the “Register Select” line. The next control pin is RW. It means Read/Write control line. When RW is low (0), the information on the data bus is being written to the LCD. When RW is high (1) the program is effectively querying the LCD.

VCC - connect to 5V
VSS - connect to ground
VEE - contrast adjustment
RS - register select 0:command, 1:data
RW - read/write 0:write 1:read
EN - Enable, falling edge trigged
D0-D7 - Data pins
A/LED+ - Back-light Anode(+)
K/LED- -Back-light Cathode(-)

It includes 16 columns and 2 rows. So, it will have 32 characters in total and each character will be made of 5x8 pixel dots. Its operating voltage is 5.0V and current consumption is 1.6mA. The duty cycle is1/16 and the built-in controller is 7066 or Equivalent. Operating temperature in between 0–50℃. It can work on both 8-bit and 4-bit. but, I used it in 4-bit mode. It uses only 4 data lines. The idea of 4-bit communication is introduced to save pins of the microcontroller.

The internal circuit of the LCD

Blog Diagram
Layers of LCD Display

An LCD panel is constructed of many layers. All the layers that are present in the LCD panel front polarizer are the process or state in which rays of light exhibit different properties in different directions, especially the state in which all the vibration takes place in one plane. The front polarizer is applied to the outside surface of the top piece of glass. The top layer of glass also provides structural support for the LCD panel. A transparent coating of Indium Tin Oxide(IoT) is applied to the bottom side of the top layer of glass. ITO is conductive and forms the backplane or the common electrodes of the LCD panel. The patterns of the backplane and segment ITO form the numbers, letters, symbols, icons, etc. The direction of “rubbing” of the polyimide on the bottom glass is perpendicular to that of the polyimide on the top glass. This orientation creates a twist in the LC fluid. The next layer is the polyimide coating on the bottom glass followed by the ITO segment electrodes. Applied to the external surface of the bottom glass is the rear polarizer. Depending on the type of viewing mode employed by the LCD panel, the axis of polarization may be the same as the front polarizer or phase-shifted by 90 degrees from the front polarizer.

Specifications of LCD Display

• Input Voltage – 5.0 V
• Supply Current – 1.0 mA (without backlight)
• Display format – 16*2 characters
• Duty Cycle – 1/16
• System Interface – 4 bit or 8 bit
• 5*8 dots include cursor
• Built – in – controller: ST 7066 (or equivalent)
• Operating Temperature 0-50℃
• Storage Temperature -10℃ − 60℃

Functions in LCD.h file

#ifndef LCD_H_#define LCD_H_
#include <avr/io.h>#define F_CPU 8000000UL#include <util/delay.h>#define LCD_CMD_CLEAR_DISPLAY 0x01#define LCD_CMD_CURSOR_HOME 0x02// Display control#define LCD_CMD_DISPLAY_OFF 0x80#define LCD_CMD_DISPLAY_NO_CURSOR 0x0c#define LCD_CMD_DISPLAY_CURSOR_NO_BLINK 0x0E#define LCD_CMD_DISPLAY_CURSOR_BLINK 0x0F// Function set#define LCD_CMD_4BIT_2ROW_5X7 0x28#define LCD_CMD_8BIT_2ROW_5X7 0x38//LCD DATA AND CONTROL PORTS#define DATA_BUS PORTA#define CTL_BUS PORTB#define DATA_DDR DDRA#define CTL_DDR DDRB//LCD DATA PINS#define LCD_D4 4#define LCD_D5 5#define LCD_D6 6#define LCD_D7 7// LCD CONTROL PINS#define LCD_EN 3#define LCD_RW 2#define LCD_RS 1//functions prototypevoid lcd_init(void);void lcd_send_command (uint8_t );void lcd_write_character(uint8_t );void lcd_write_word(uint8_t[]);void lcd_clear(void);void lcd_set_courser(uint8_t,uint8_t);void lcd_goto_xy (uint8_t , uint8_t );

Circuit diagram

Circuit diagram of LCD display

Atmel Studio C code

#include "lcd2.h"/**Function name  : lcd_init*Parameters     : void*return       : void*purpose        : initialize LCD pins as output*       and setting up the operation mode(4-bit)*      default setting (cursor on)*/void lcd_init(void){DATA_DDR = (1<<LCD_D7) | (1<<LCD_D6) | (1<<LCD_D5)| (1<<LCD_D4);CTL_DDR |= (1<<LCD_EN)|(1<<LCD_RW)|(1<<LCD_RS);DATA_BUS = (0<<LCD_D7)|(0<<LCD_D6)|(1<<LCD_D5)|(0<<LCD_D4);CTL_BUS|= (1<<LCD_EN)|(0<<LCD_RW)|(0<<LCD_RS);_delay_ms(5);CTL_BUS &=~(1<<LCD_EN);_delay_ms(5);lcd_send_command(LCD_CMD_4BIT_2ROW_5X7); /*2 line,5*7 matrix in 4-bit mode*/_delay_ms(5);lcd_send_command(LCD_CMD_DISPLAY_CURSOR_BLINK); /*Auto Increment cursor*/_delay_ms(5);lcd_send_command(0x80); /*display off*/}/**Function name  : lcd_send_command*Parameters: uint8_t command*return: void*purpose: sending a command to LCD by sending*       the first nibble then the second nibble*      enabling and disabling the LCD in between*/void lcd_send_command (uint8_t command){DATA_BUS=((command&0b11110000)); /*Sending upper nibble*/CTL_BUS &=~(1<<LCD_RS);  /*RS=0, command reg*/CTL_BUS |=(1<<LCD_EN);   /*Enable pulse*/_delay_ms(5);CTL_BUS &=~(1<<LCD_EN);_delay_ms(5);DATA_BUS=((command&0b00001111)<<4); /*Sending lower nibble*/CTL_BUS |=(1<<LCD_EN);_delay_ms(5);CTL_BUS &=~(1<<LCD_EN);_delay_ms(5);}/**Function name  : lcd_write_word*Parameters     : uint8_t word[20]*return       : void*purpose        : printing a full word to the*       LCD (Maximum 20 characters)*/void lcd_write_word(uint8_t word[20]){int i=0;while(word[i]!='\0'){lcd_write_character(word[i]);i++;}}/**Function name  : lcd_write_character*Parameters: uint8_t character*return: void*purpose: sending one character to LCD by sending*        the first nibble first then the second nibble*       enabling and disabling the LCD in between*/void lcd_write_character(uint8_t character){DATA_BUS=((character & 0b11110000));CTL_BUS|=(1<<LCD_RS);CTL_BUS |=(1<<LCD_EN);_delay_ms(5);CTL_BUS &=~(1<<LCD_EN);_delay_ms(5);DATA_BUS=((character & 0b00001111)<<4);CTL_BUS |=(1<<LCD_EN);_delay_ms(5);CTL_BUS &=~(1<<LCD_EN);_delay_ms(5);}/**Function name  : lcd_clear*Parameters     : void*return       : void*purpose        : Clearing the LCD screen by sending*      the LCD_CMD_CLEAR_DISPLAY command to LCD*/void lcd_clear(void){lcd_send_command(LCD_CMD_CLEAR_DISPLAY);_delay_ms(5);}void lcd_goto_xy (uint8_t line,uint8_t pos)    //line = 0 or 1{lcd_send_command((0x80|(line<<6))+pos);_delay_us (50);}
int main(void){/* Replace with your application code */lcd_init();_delay_ms(20);lcd_init();
_delay_ms(20);
lcd_write_word("Hello Coders"); //Display "Not Registered"
_delay_us(20);
lcd_goto_xy(1,0);
lcd_clear();
_delay_ms(20);
}

lcd_init function: lcd_init is an LCD initialize function. LCD power-on delay always waiting for 5ms. It sends 0x28 command to initialize 2 lines 5x8 matrix, 4-bit mode LCD 16x2 and send 0x0c command for display on. Now our LCD is ready to accept data for displaying.

lcd_send_command function: First, send a High nibble of command. Then, make RS pin low, RW pin low and give high to low pulse at Enable (E). send lower nibble command. Now we can send the command value to the LCD data port.

lcd_write_character function: when we give an enable pulse the LCD latches the data present and displays it on a 5x8 matrix, as RS is a data register.

lcd_write_word function: this function takes a string and sends one character at a time to the LCD data function till the end of the string. A while loop is used for sending a character in each iteration. A null character indicates the end of the string.

lcd_clear function: this will clear the display and bring the cursor back to the (0,0) point.

--

--

Tashini Hansika

A passionate IT Undergraduate from University of Moratuwa