ATMega328 4Bit LCD Display Control

This article is about the ATMega328 and how to control it with a 16x2 character LC-Display. Everything is programmed in C with Amtel Studio. The software is loaded to the microcontroller via a programmer (AVRISP). The display is connected to PORTD with a 4-bit line.

How the LCD display works

The displays available on the market are based on the HD44780 standard. This standard means that the display supports almost all characters of the ASCII character table. Therefore, it is possible to display the most important characters. The display controller, which is integrated in the display, can generate these characters and send them to the matrix. In addition to the already 208 known characters, it is also possible to draw any other characters and signs. The display controller handles most of the operations, so the code for the microcontroller is very short.

Standalone ATMega328 LCD Display 4 Bit Wiring - Schaltplan

Wiring Shematics

In addition to the microcontroller, a 16 MHz clock is needed, which contains a quartz oscillator with two capacitors. In addition to the display, a 10K potentiometer is needed to adjust the contrast of the LCD. The display can be controlled with 8 or 4 data lines. In this example, the display is controlled with 4-bit, as it can save 4 data lines. In addition, the display requires two more data lines (EN & RS), which are responsible for the activation and control of the display. The R / W pin is not needed and therefore connected to ground. The last two pins are used for the backlight.

Pinbelegung vom LCD
Pin Function
VSS GND (ground)
VDD 5V (positive pole)
V0 Contrast setting
RS switching (0 = command, 1 = data)
RW read / write (connected to GND)
E Enable (activates display control)
D0 - D7 data bits (4-bit = D0-D3, 8-bit = D0-D7)
A Anode (positive pole of LED)
K cathode (negative pole of LED)

Sourcecode in C

The source code provides the minimum functionality needed for the display. There are no additional libraries required. The individual pins for the data lines do not need to be defined, since all lines are connected to the same port and therefore ports 4-7 are automatically defined for them. EN & RS must be specified separately. The individual tasks have been divided into functions, which makes it easy to call a specific function several times. The sample code writes a static string to the first line. The second line displays the runtime of the controller in seconds.

4-Bit 16x2 LCD Example
More information at
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#define LCD_Port PORTD			//Define LCD Port (PORTA, PORTB, PORTC, PORTD)
#define LCD_DPin  DDRD			//Define 4-Bit Pins (PD4-PD7 at PORT D)
#define RSPIN PD0			//RS Pin
#define ENPIN PD1 			//E Pin
int runtime;			 //Timer for LCD

void LCD_Init (void)
	LCD_DPin = 0xFF;		//Control LCD Pins (D4-D7)
	_delay_ms(15);		//Wait before LCD activation
	LCD_Action(0x02);	//4-Bit Control
	LCD_Action(0x28);       //Control Matrix @ 4-Bit
	LCD_Action(0x0c);       //Disable Cursor
	LCD_Action(0x06);       //Move Cursor
	LCD_Action(0x01);       //Clean LCD

void LCD_Action( unsigned char cmnd )
	LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0);
	LCD_Port &= ~ (1<<RSPIN);
	LCD_Port |= (1<<ENPIN);
	LCD_Port &= ~ (1<<ENPIN);
	LCD_Port = (LCD_Port & 0x0F) | (cmnd << 4);
	LCD_Port |= (1<<ENPIN);
	LCD_Port &= ~ (1<<ENPIN);

void LCD_Clear()
	LCD_Action (0x01);		//Clear LCD
	_delay_ms(2);			//Wait to clean LCD
	LCD_Action (0x80);		//Move to Position Line 1, Position 1

void LCD_Print (char *str)
	int i;
	for(i=0; str[i]!=0; i++)
		LCD_Port = (LCD_Port & 0x0F) | (str[i] & 0xF0);
		LCD_Port |= (1<<RSPIN);
		LCD_Port|= (1<<ENPIN);
		LCD_Port &= ~ (1<<ENPIN);
		LCD_Port = (LCD_Port & 0x0F) | (str[i] << 4);
		LCD_Port |= (1<<ENPIN);
		LCD_Port &= ~ (1<<ENPIN);
//Write on a specific location
void LCD_Printpos (char row, char pos, char *str)
	if (row == 0 && pos<16)
	LCD_Action((pos & 0x0F)|0x80);
	else if (row == 1 && pos<16)
	LCD_Action((pos & 0x0F)|0xC0);

int main()
	LCD_Init(); //Activate LCD
	LCD_Print("WWW.AEQ-WEB.COM");	//Begin writing at Line 1, Position 1

	while(1) {
		char showruntime [16];
		itoa (runtime,showruntime,10);
		LCD_Action(0xC0);		//Go to Line 2, Position 1
		LCD_Print("RUNTIME (s): ");
Info: This article has been partially translated automatically and may contain errors.

You Might Also Like


Social Media