AEQ-WEB

ATMega328 4Bit LCD Display Control
ATMega328
06.08.2018

Switch language to: en Englisch

ATMega328 16x2 4-Bit LCD Display

Zu diesem Artikel gibt es auch ein Video auf Youtube: Standalone ATMega328 16x2 LCD Display ansteuern mit 4-Bit in C - Amtel Studio

In diesem Beitrag zeigen wir, wie mit dem ATMega328 ein 16x2 Zeichen Display angesteuert wird. Programmiert wird alles in C mit Amtel Studio. Die Software wird mittels Programmer (AVRISP) auf den Mikrocontroller geladen. Das Display wird auf PORTD mit einer 4-Bit Leitung angeschlossen.


Wie das LCD Display funktioniert

Die auf den Markt erhältlichen Displays orientieren sich nach dem HD44780-Standard. Dieser Standard bedeutet, dass das Display fast alle Zeichen vom ASCII-Zeichensatz unterstützt. Daher ist es möglich, die wichtigsten Zeichen auch ohne großen Aufwand anzuzeigen. Im Display-Controller, der fest im Display verbaut ist, werden diese Zeichen generiert und an die Matrix gesendet. Neben den bereits 208 bekannten Zeichen, ist es auch möglich, jedes andere beliebige Zeichen anzuzeigen. Da der Display-Controller einen Großteil aller Operationen übernimmt, bleibt der Code für den Mikrocontroller relativ klein.


Standalone ATMega328 LCD Display 4 Bit Wiring - Schaltplan

Verdrahtungsplan

Neben den Mikrocontroller wird ein 16 Mhz Taktgeber benötigt, der einen Schwingquarz mit zwei Kondensatoren enthält. Neben dem Display wird noch ein 10K Potentiometer benötigt, über das der Kontrast vom LCD eingestellt wird. Das Display kann mit 8 oder 4 Datenleitungen angesteuert werden. In diesem Beispiel wird das Display mit 4-Bit angesteuert, da man dadurch 4 Datenleitungen einsparen kann. Zusätzlich benötigt das Display noch zwei weitere Datenleitungen (EN & RS), die für die Aktivierung und Steuerung vom Display zuständig sind. Der R/W Pin wird nicht benötigt und daher mit der Masse verbunden. Die letzten zwei Pins werden für die Hintergrundbeleuchtung verwendet.


Pinbelegung vom LCD
Pin Funktion
VSS GND (Masse)
VDD 5V (Positiver Pol)
V0 Kontrasteinstellung
RS Umschaltung (0=Befehl,1=Daten)
RW Lesen/Schreiben (wird mit GND verbunden)
E Enable (Aktiviert Displaysteuerung)
D0 - D7 Daten-Bits (4-Bit=D0-D3, 8-Bit=D0-D7)
A Anode (Pluspol der LED Beleuchtung)
K Kathode (Minuspol der LED Beleuchtung)

Sourcecode in C

Der Quellcode bietet den minimalen Funktionsumfang, der für das Display benötigt wird. Es sind keine zusätzlichen Bibliotheken erforderlich. Die einzelnen Pins für die Datenleitungen müssen nicht definiert werden, da alle Leitungen am selben Port hängen und daher automatisch die Ports 4-7 dafür definiert werden. EN & RS müssen extra angegeben werden. Die einzelnen Aufgaben wurden in Funktionen aufgeteilt, wodurch ein mehrmaliges Aufrufen einer bestimmter Funktionen problemlos möglich ist. Der Beispielcode schreibt in die erste Zeile einen statischen String. In der zweiten Zeile wird die Laufzeit des Controllers in Sekunden ausgegeben.


/*
4-Bit 16x2 LCD Example
More information at www.aeq-web.com
*/
#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
	_delay_ms(2);
}

void LCD_Action( unsigned char cmnd )
{
	LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0);
	LCD_Port &= ~ (1<<RSPIN);
	LCD_Port |= (1<<ENPIN);
	_delay_us(1);
	LCD_Port &= ~ (1<<ENPIN);
	_delay_us(200);
	LCD_Port = (LCD_Port & 0x0F) | (cmnd << 4);
	LCD_Port |= (1<<ENPIN);
	_delay_us(1);
	LCD_Port &= ~ (1<<ENPIN);
	_delay_ms(2);
}

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);
		_delay_us(1);
		LCD_Port &= ~ (1<<ENPIN);
		_delay_us(200);
		LCD_Port = (LCD_Port & 0x0F) | (str[i] << 4);
		LCD_Port |= (1<<ENPIN);
		_delay_us(1);
		LCD_Port &= ~ (1<<ENPIN);
		_delay_ms(2);
	}
}
//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);
	LCD_Print(str);
}

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): ");
		LCD_Print(showruntime);
		_delay_ms(1000);
		runtime++;
	}
}