Connecting the LCD1602 (HD44780) liquid crystal display to the ATmega8 microcontroller in 8-bit mode


Note:

The article is not an original translation. The article was created on the basis of the article (see the source of information indicated below) by translating it, using the main text of the original and supplemented by the author; This code has been tested on a real device f. winstar.

LCD displays (Liquid Crystal Displays) are used to display status or parameters in various devices.

The LCD1602 liquid crystal display is a 16-pin device with 8 data pins (D0-D7) and 3 control pins (RS, RW, EN). The remaining 5 pins are for power supply and LCD backlight. The numbers “1602” indicate the format of the output (displayed) information: 16×02 characters (Figure 1).

The control pins help us set up the LCD display in command mode or data transfer mode. They also help you set the read or write mode and the read or write time.

The 16×2 LCD can be used in 4-bit or 8-bit mode depending on the specification. In order to use it, we need to send certain commands to the LCD in command mode, and once the LCD is configured according to our requirements, we can send the necessary data in data mode.

For more information about the 16×02 LCD display and how to use it, please refer to the datasheet.

Figure 1 - Pinout of the LCD1602 (HD44780) liquid crystal display

Figure 1 – Pinout of the LCD1602 (HD44780) liquid crystal display

The diagram for connecting the LCD1602 (HD44780) liquid crystal display to the ATmega8 microcontroller in 8-bit mode is shown in Figure 2.

Figure 2 - Connecting the LCD1602 liquid crystal display to the ATmega8 microcontroller in 8-bit mode

Figure 2 – Connecting the LCD1602 liquid crystal display to the ATmega8 microcontroller in 8-bit mode

Trimmer resistor R1 is designed to fine-tune the contrast of the display. Resistor R2 is designed to limit the current at the anode of the display backlight.

Table 1 - Hardware Connections

Table 1 – Hardware Connections

Display initialization function:

1. Turn on the power on the LCD

2. Must wait at least 15ms power-on initialization time for LCD1602.

3. Send command 0x38 which will set the LCD display to 2-line, 8-bit mode and 5×8 dots.

4. Send one of the display cursor enable commands (0x0E, 0x0C).

5. Send command 0x06 (move the cursor to the right).

Code Listing:

void LCD_Init (void)	/* LCD Initialize function */
{
	LCD_Command_Dir = 0xFF;	/* Make LCD command port direction as o/p */
	LCD_Data_Dir = 0xFF;	/* Make LCD data port direction as o/p */

	_delay_ms(20);		/* LCD Power ON delay always >15ms */
	LCD_Command (0x38);	/* Initialization of 16X2 LCD in 8bit mode */
	LCD_Command (0x0C);	/* Display ON Cursor OFF */
	LCD_Command (0x06);	/* Auto Increment cursor */
	LCD_Command (0x01);	/* clear display */
	LCD_Command (0x80);	/* cursor at home position */
}

Now that the LCD has been initialized, it is ready to receive data for display.

Function of writing commands (instructions):

1. Send the command value to the LCD1602 data port.

2. Set the RS output to a “low” level, RS = 0 (instruction register).

3. Set the RW pin to “low” level, RW = 0 (write operation)

4. Apply a high to low pulse on the Enable (E) pin with a minimum delay of 450 ns.

When we give an enable pulse, the LCD will capture the data present on pins D0 to D7 and execute it as a command, since RS is a command register.

Code Listing:

void LCD_Command(unsigned char cmnd)
{
	LCD_Data_Port= cmnd;
	LCD_Command_Port &= ~(1<<RS);	/* RS=0 command reg. */
	LCD_Command_Port &= ~(1<<RW);	/* RW=0 Write operation */
	LCD_Command_Port |= (1<<EN);	/* Enable pulse */
	_delay_us(1);
	LCD_Command_Port &= ~(1<<EN);
	_delay_ms(3);
}

Data recording function:

1. Send a command to the data port.

2. Set RS pin to “high” level, RS = 1 (data register)

3. Set the RW pin to “low” level, RW = 0 (write operation)

4. Apply a pulse from “high” to “low” at the Enable (E) pin.

When we give an enable pulse, the LCD will latch the available data (on pins D0-D7) and display it on a 5×8 matrix since RS is a data register.

Code Listing:

void LCD_Char (unsigned char char_data)	/* LCD data write function */
{
	LCD_Data_Port = char_data;
	LCD_Command_Port |= (1<<RS);	/* RS=1 Data reg. */
	LCD_Command_Port &= ~(1<<RW);	/* RW=0 write operation */
	LCD_Command_Port |= (1<<EN);	/* Enable Pulse */
	_delay_us(1);
	LCD_Command_Port &= ~(1<<EN);
	_delay_ms(1);
}

String display function:

This function takes a string (an array of characters) and sends one character at a time to the LCD data function until the end of the string. The for loop is used to send a character on each iteration. The NULL character indicates the end of the string.

Code Listing:

void LCD_String (char *str)		
{
	int i;
	for(i=0;str[i]!=0;i++)  /* send each char of string till the NULL */
	{
		LCD_Char (str[i]);  /* call LCD data write */
	}
}

Notes:

1. LCD turn-on delay. After turning on the LCD1602, we cannot immediately send commands to it, because it takes 15ms to initialize. Therefore, when programming, we need to take care to provide a sufficient power-up delay (> 15 ms) and then send commands to the LCD.

2. After checking the LCD1602 commands, it takes time (in microseconds) to execute them. But for the command 0x01 (i.e. clear the display), the execution takes 1.64 ms. Therefore, after sending the 0x01 command, it is necessary to provide sufficient delay (> 1.63 milliseconds).

Program listing:

#define F_CPU 8000000UL			/* Define CPU Frequency e.g. here 8MHz */
#include <avr/io.h>			/* Include AVR std. library file */
#include <util/delay.h>			/* Include inbuilt defined Delay header file */

#define LCD_Data_Dir DDRB		/* Define LCD data port direction */
#define LCD_Command_Dir DDRC		/* Define LCD command port direction register */
#define LCD_Data_Port PORTB		/* Define LCD data port */
#define LCD_Command_Port PORTC		/* Define LCD data port */
#define RS PC0				/* Define Register Select (data/command reg.)pin */
#define RW PC1				/* Define Read/Write signal pin */
#define EN PC2				/* Define Enable signal pin */
 

void LCD_Command(unsigned char cmnd)
{
	LCD_Data_Port= cmnd;
	LCD_Command_Port &= ~(1<<RS);	/* RS=0 command reg. */
	LCD_Command_Port &= ~(1<<RW);	/* RW=0 Write operation */
	LCD_Command_Port |= (1<<EN);	/* Enable pulse */
	_delay_us(1);
	LCD_Command_Port &= ~(1<<EN);
	_delay_ms(3);
}

void LCD_Char (unsigned char char_data)	/* LCD data write function */
{
	LCD_Data_Port= char_data;
	LCD_Command_Port |= (1<<RS);	/* RS=1 Data reg. */
	LCD_Command_Port &= ~(1<<RW);	/* RW=0 write operation */
	LCD_Command_Port |= (1<<EN);	/* Enable Pulse */
	_delay_us(1);
	LCD_Command_Port &= ~(1<<EN);
	_delay_ms(1);
}

void LCD_Init (void)			/* LCD Initialize function */
{
	LCD_Command_Dir = 0xFF;		/* Make LCD command port direction as o/p */
	LCD_Data_Dir = 0xFF;		/* Make LCD data port direction as o/p */
	_delay_ms(20);			/* LCD Power ON delay always >15ms */
	
	LCD_Command (0x38);		/* Initialization of 16X2 LCD in 8bit mode */
	LCD_Command (0x0C);		/* Display ON Cursor OFF */
	LCD_Command (0x06);		/* Auto Increment cursor */
	LCD_Command (0x01);		/* Clear display */
	LCD_Command (0x80);		/* Cursor at home position */
}

void LCD_String (char *str)		/* Send string to LCD function */
{
	int i;
	for(i=0;str[i]!=0;i++)		/* Send each char of string till the NULL */
	{
		LCD_Char (str[i]);
	}
}

void LCD_String_xy (char row, char pos, char *str)/* Send string to LCD with xy position */
{
	if (row == 0 && pos<16)
	LCD_Command((pos & 0x0F)|0x80);	/* Command of first row and required position<16 */
	else if (row == 1 && pos<16)
	LCD_Command((pos & 0x0F)|0xC0);	/* Command of first row and required position<16 */
	LCD_String(str);		/* Call LCD string function */
}

void LCD_Clear()
{
	LCD_Command (0x01);		/* clear display */
	LCD_Command (0x80);		/* cursor at home position */
}
 
int main()
{

	LCD_Init();			/* Initialize LCD */

	LCD_String("Hello World");	/* write string on 1st line of LCD*/
	LCD_Command(0xC0);		/* Go to 2nd line*/
	LCD_String("8 bit");	/* Write string on 2nd line*/

	return 0;

After downloading the firmware, we will see the following result on the LCD1602 display as shown in Figure 3.

It is good programming practice to create a separate library for our LCD.

Figure 3 - The result of the firmware

Figure 3 – The result of the firmware

The decoding of the most commonly used commands sent from the microcontroller to the LCD1602 (HD44780) display is shown in tables 2.3.

Table 2 - Explanation of the most commonly used commands sent from the microcontroller to the LCD1602 display (HD44780)

table 2 – Deciphering the most commonly used commands sent from the microcontroller to the LCD1602 (HD44780) display

Command execution times are approximate. It is determined by the frequency of the internal RC-oscillator of the LCD display, which, in turn, depends on the technological dispersion and the temperature of the case heating.

Table 3 - Commands for moving to a certain character of the upper or lower line of the screen for the LCD1602 (HD44780) display

Table 3 – Commands for moving to a certain character of the top or bottom line of the screen for the LCD1602 (HD44780) display

A source of information:

https://www.electronicwings.com/avr-atmega/lcd16x2-interfacing-with-atmega16-32

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *