/* LCD Include-Datei
*
* Spezielle Version für 4x20 LCD
*
* LCD_CTRL stellt ein, welcher Controllertyp (wichtig für DD-RAM-Adressen)
* Einige Routinen sind für ein EA DIP204-4 mit KS0073 Controller notwendig, aber auskommentiert
*
* Das LCD ist folgendermaßen angeschlossen:
* PC4 = RS
* PC5 = Enable
* PC0-PC3 = D4-D7
* R/W ist n.c.
*
*
*/
#include <avr/io.h>
#include <util/delay.h>
#include "lcd_tools.h"
#define LCD_CTRL 0 // (0 = HD44780, 1= KS0073)
#define delay(us) _delay_loop_2 (((F_CPU/4000)*us)/1000) // wartet µs
/**
@brief wartet Millisekunden
@param Zeit in Millisekunden
@return none
*/
void delay_ms(uint16_t ms)
{
for(uint16_t t=0; t<=ms; t++)
_delay_ms(1);
}
/**
@brief Enable Leitung togglen
@param none
@return none
*/
void lcd_flash_e ()
{
PORTC = PORTC | ( 1<<DDC5 ) ; // Enable = HIGH
delay(100); // kurz warten, damit Flanke entsteht
PORTC = PORTC & ~( 1<<DDC5 ) ; // Enable = LOW
delay(100); // Warten, bis der durch Enable angelegte Befehl hoffentlich verarbeitet wurde
}
/**
@brief Kommando oder Zeichen an Display senden:
@param rs=0 => Kommando, rs=1 => Zeichen
@return none
*/
void lcd_write (uint8_t data, uint8_t rs)
{
uint8_t dataBits ;
if (rs) // write data (RS=1, RW=0)
dataBits=0x10; // RS liegt an Pin 4 = B 0001 0000 = H 10
else // write instruction (RS=0, RW=0)
dataBits=0;
PORTC = dataBits | (data>>4); // output high nibble first, zzgl. Zustand für RS-Leitung
lcd_flash_e ();
PORTC = dataBits | (data&0x0F); // output low nibble, zzgl. RS-Leitung
lcd_flash_e ();
}
/**
@brief Display loeschen
@param none
@return none
*/
void lcd_cls ()
{
lcd_write(0x00,0); // B 0000 0000 => Clear
delay(4000); // dauert eine Weile
lcd_write(0x01,0); // B 0000 0001 => Cursor Home
delay(4000); // dauert eine Weile, Wert ausprobiert
}
/**
@brief Zeichenausgabe
@param none
@return none
*/
void lcd_writechar ( char zeichen)
{
lcd_write (zeichen, 1);
}
/**
@brief gibt eine Zeichenkette auf dem LCD aus
@param none
@return none
*/
void lcd_writetext ( char *text)
{
uint8_t i = 0;
while (text[i]!=0)
{
lcd_writechar(text[i]);
i++;
}
}
/**
@brief Zeilenwechsel
@param none
@return none
*/
void lcd_gotoline (uint8_t zeile)
{
if (LCD_CTRL == 0)
{
if (zeile == 1) lcd_write(0x80,0); // B 1000 0000 => DD-RAM Adress Set 1. Zeile/1.Spalte
if (zeile == 2) lcd_write(0x80+0x40,0); // B 1010 0000 => DD-RAM Adress Set 2. Zeile/1.Spalte
if (zeile == 3) lcd_write(0x80+0x14,0); // B 1010 0000 => DD-RAM Adress Set 3. Zeile/1.Spalte
if (zeile == 4) lcd_write(0x80+0x54,0); // B 1010 0000 => DD-RAM Adress Set 4. Zeile/1.Spalte
}
else
{
if (zeile == 1) lcd_write(0x80,0); // B 1000 0000 => DD-RAM Adress Set 1. Zeile/1.Spalte
if (zeile == 2) lcd_write(0x80+0x20,0); // B 1010 0000 => DD-RAM Adress Set 2. Zeile/1.Spalte
if (zeile == 3) lcd_write(0x80+0x40,0); // B 1010 0000 => DD-RAM Adress Set 3. Zeile/1.Spalte
if (zeile == 4) lcd_write(0x80+0x60,0); // B 1010 0000 => DD-RAM Adress Set 4. Zeile/1.Spalte
}
}
/**
@brief Cursorpositionieren
@param Zeile, Spalte
@return none
*/
void lcd_gotopos (uint8_t zeile, uint8_t spalte)
{
if (LCD_CTRL == 0)
{
if (zeile == 1) lcd_write(0x80+0x00+spalte-1,0); // DD-RAM Adress 1. Zeile + Spalte
if (zeile == 2) lcd_write(0x80+0x40+spalte-1,0); // DD-RAM Adress 2. Zeile + Spalte
if (zeile == 3) lcd_write(0x80+0x14+spalte-1,0); // DD-RAM Adress 3. Zeile + Spalte
if (zeile == 4) lcd_write(0x80+0x54+spalte-1,0); // DD-RAM Adress 4. Zeile + Spalte
}
else
{
if (zeile == 1) lcd_write(0x80+0x00+spalte-1,0); // DD-RAM Adress 1. Zeile + Spalte
if (zeile == 2) lcd_write(0x80+0x20+spalte-1,0); // DD-RAM Adress 2. Zeile + Spalte
if (zeile == 3) lcd_write(0x80+0x40+spalte-1,0); // DD-RAM Adress 3. Zeile + Spalte
if (zeile == 4) lcd_write(0x80+0x60+spalte-1,0); // DD-RAM Adress 4. Zeile + Spalte
}
}
/**
@brief gibt eine int-Zahl auf dem Display aus. Integriert, damit auf string.h verzichtet werden kann
@param Zahl
Anzahl der Stellen (führende Leerzeichen)
space=0 => führende Nullen, 1 => führende Leerzeichen
@return none
*/
void lcd_writezahl (int32_t zahl, uint8_t pos, uint8_t spacer)
{
int32_t output;
char sign = '0';
pos--; // Korrektur des Parameters für Benutzerfreundlichkeit
if (spacer) sign=' ';
// negatives Vorzeichen oder Leerzeichen
if (zahl < 0)
{
lcd_writechar ('-');
zahl *= -1; // positive Zahl
}
output = zahl;
// Hunderttausender-Dezimalstelle oder Leerzeichen (Ausblenden fuehrender Nullen)
if (zahl >= 100000) lcd_writechar (0x30 + output/100000); else if (pos >= 5) lcd_writechar (sign);
output = output % 100000;
// Zehntausender-Dezimalstelle oder Leerzeichen (Ausblenden fuehrender Nullen)
if (zahl >= 10000) lcd_writechar (0x30 + output/10000); else if (pos >= 4) lcd_writechar (sign);
output = output % 10000;
// Tausender-Dezimalstelle oder Leerzeichen
if (zahl >= 1000) lcd_writechar (0x30 + output/1000); else if (pos >= 3) lcd_writechar (sign);
output = output % 1000;
// Hunderter-Dezimalstelle oder Leerzeichen
if (zahl >= 100) lcd_writechar (0x30 + output/100); else if (pos >= 2) lcd_writechar (sign);
output = output % 100;
// Zehner-Dezimalstelle oder Leerzeichen
if (zahl >= 10) lcd_writechar (0x30 + output/10); else if (pos >= 1) lcd_writechar (sign);
// einer Dezimalstelle oder Leerzeichen
lcd_writechar (0x30 + output % 10);
}
/**
@brief Zuerst den 8-Bit-Modus aktivieren, Ist wichtig, falls LCD schon im 4-Bit Modus war und dann
nach einem Programm-Reset vergeblich versucht würde, den 4-Bit Modus erneut zu aktivieren.
Dann in 4-Bit Modus umschalten.
@param none
@return none
*/
void lcd_set4bit ()
{
PORTC = 0x03; // 8-Bit Modus aktivieren (B 0011 0000 = H 30, High Nibble => B 0011 = H 03
lcd_flash_e (); // Datenübernahme
delay_ms(5); // sicherheitshalber warten da wir BUSY nicht überprüfen können
// Das ganze 2x wiederholen:
PORTC = 0x03;
lcd_flash_e ();
delay(200);
PORTC = 0x03;
lcd_flash_e ();
delay(200);
lcd_write(0x2,0); // B 0000 0010 => in 4-Bit-Modus umschalten
delay(200);
}
/**
@brief Portrichtung einstellen. Extern, damit man dies separat aufrufen kann, wenn bspw. LCD schon initialisiert ist und
per Watchdog ein Reset ausgelöst wurde, man dann aber nicht das Display neu initialisieren möchte, damit es schneller weiter geht
@param none
@return none
*/
void lcd_port_ini ()
{
DDRC = 0x3F; // setze Portrichtung (1 = Ausgang): 0011 1111
}
/**
@brief Display initialisieren. Einmal als erstes aufrufen
@param none
@return none
*/
void lcd_ini ()
{
lcd_port_ini();
DDRC = 0x3F; // setze Portrichtung (1 = Ausgang): 0011 1111
delay_ms(100); // 40ms warten bis LCD wirklich bereit! Wir können nicht BUSY auswerten.
// Es gibt Displays die so lange brauchen (z. B. Optrex DMC20481)
lcd_set4bit(); // ab jetzt 4-Bit-Modus
// lcd_write(0x2C,0); // 4x20 Spezial: Function Set (0010 1100): 4-Bit, 2 Line, RE-Bit, Dot Scroll, Normal Mode
// lcd_write(0x09,0); // 4x20: Extended Function Set (0000 1001): 5 dot font, Normal Cursor, 4 Line Display
lcd_write(0x28,0); // B 0010 1000 => Function Set: 4Bit (kein 8-Bit Bus), zweizeiliges Display, 5x7 Dots/Zeichen (kein 5x10), RE-Bit aus
// lcd_write(0x0F,0); // B 0000 1000 => Display On/Off: Display ein, Cursor an, Blinken an
lcd_write(0x0C,0); // B 0000 1000 => Display On/Off: Display ein, Cursor aus, Blinken aus
lcd_write(0x06,0); // B 0000 0110 => Entry Mode Set: DD-RAM autom. inkr., Cursor bewegen
lcd_cls(); // Display löschen
}
Lesezeichen