Optimierter Code für die parallele Ansteuerung eines LCD Moduls über 2 Leitungen und ein Schieberegister (Autor: Roland Elmiger).
//-------------------------------------------------------------------------
// LCD-Routine für LC-Meter (2-Bit)
//-------------------------------------------------------------------------
// Roland Elmiger, HB9GAA
// Letzter Update : 25.09.2007
//-------------------------------------------------------------------------
#include "Includes.h"
#define LCD_Daten LATBbits.LATB5 //LCD-Daten Ausgang
#define LCD_Clock LATBbits.LATB4 //LCD-Clock Ausgang
#define Zeile1 0x00 //1. LCD-Zeile
#define Zeile2 0x40 //2. LCD-Zeile
#define Func_Set 0b00101000 //2 Zeilen und 5x7 Zeichen, 4 Bit
#define Disp_On 0b00001100 //Anzeige ein
#define Disp_On_C 0b00001110 //Anzeige ein, Cursor ein
#define Disp_On_B 0b00001111 //Anzeige ein, Cursor ein und blinken
#define Disp_Off 0b00001000 //Anzeige aus
#define Clr_Disp 0b00000001 //Anzeige löschen
#define Entry_Inc 0b00000110 //Auto-Inkrement
#define Entry_Inc_S 0b00000111 //Auto-Inkrement, Anzeige schieben
#define Entry_Dec 0b00000100 //Auto-Dekrement
#define Entry_Dec_S 0b00000101 //Auto-Dekrement, Anzeige schieben
#define CGRAM 0b01000000 //CGRAM, Least Significant 6-bit are for address
#define DD_Ram_Addr 0b10000000 //Least Significant 7-bit are for address
#define DD_Ram_UL 0b10000000 //Upper Left coner of the Display
// Ein Clock senden
//-------------------------------------------------------------------------
void Clock (void)
{
LCD_Clock=1;
Nop();
LCD_Clock=0;
}
// Ein Nibble senden (unteres Nibble von n, c=0 als Cmd, c=1 als Char)
//-------------------------------------------------------------------------
void NibbleOut(unsigned char n, unsigned char c) //ein nibble an LCD senden
{
char Temp, i;
Temp=n & 0x0F; //das nibble speichern und hinausschieben
for (i=8; i>0; --i) //das Shift Register löschen
{
Clock(); //Clock ausgeben
}
//Bit-7 -----------------------------------------
LCD_Daten=1; //das Gate Bit setzen
Clock(); //Clock ausgeben
//Bit-6 -----------------------------------------
LCD_Daten=0; //das Lamp-Bit zurücksetzen
if (Flag1bits.Lamp_On==1u) //Test, ist LAMP-Bit 1 oder 0?
LCD_Daten=1; //das Lamp-Bit setzen
Clock(); //Clock ausgeben
//Bit-5 -----------------------------------------
LCD_Daten=0; //das PowerOnOff-Bit zurücksetzen
if (Flag1bits.PowerOnOff==1u) //Test, ist PowerOnOff-Bit 1 oder 0?
LCD_Daten=1; //das PowerOnOff-Bit setzen
Clock(); //Clock ausgeben
//Bit-4 -----------------------------------------
LCD_Daten=0; //das RS Bit setzen
if (c==1u) //wenn c = 1
LCD_Daten=1;
Clock(); //Clock ausgeben
//Bit-3 bis 0 ------------------------------------
for (i=4;i>0;--i)
{
LCD_Daten=0;
if (Temp & 0x08) //das nibble zum Output schieben
LCD_Daten=1;
Temp=Temp<<1;
Clock(); //Clock ausgeben
}
LCD_Daten=1; //Clock auf der Datenleitung ausgeben
Nop();
LCD_Daten=0;
}
// Ein Kommando an das LCD-Modul senden
//-------------------------------------------------------------------------
void Send_Cmd(char c) {
//zuerst den obere Nibble des Bytes senden
NibbleOut(c>>4,0); //RS = 0, Kommandomodus
NibbleOut(c,0); //sende das untere Nibble des Bytes
}
// Ein Zeichen an das LCD-Modul senden
//-------------------------------------------------------------------------
void Send_Clr_Disp(void) {
Send_Cmd (Clr_Disp); //Display löschen
Delay100TCYx(164); //mindestens 4.1ms warten
}
void Send_Dot(void) {
Send_Cmd ('.'); //Punkt ausgeben
}
void Send_Space(void) {
Send_Cmd (' '); //Leerzeichen ausgeben
}
void Send_Char(char c) {
//zuerst den obere Nibble des Bytes senden
NibbleOut(c>>4,1); //RS = 1, Datenmodus
NibbleOut(c,1); //sende das untere Nibble des Bytes
}
// Cursor auf LCD setzen (Adresse in W, 0-27h und 40h-67h
//-------------------------------------------------------------------------
void Set_Cursor(unsigned char x, unsigned char y)
{
unsigned char pos;
pos = (y*0x40 + x)|0x80; / /Adresse aufbereiten
Send_Cmd(pos); //und als Command senden
}
// Data an LCD senden
//-------------------------------------------------------------------------
void Data2Disp(rom char*putstr)
{
unsigned char ps;
while((ps = *putstr) != 0xFF)
{
putstr++;
if (ps== 0xFF) break;
Send_Char(ps);
}
}
// Text an aktueller Cursorposition ausgeben
//-------------------------------------------------------------------------
void DispMsg(char*putstr)
{
char ps;
while((ps = *putstr))
{
putstr++;
if (ps== 0) break;
Send_Char(ps);
}
}
void DispROMMsg(rom char*putstr)
{
char ps;
while((ps = *putstr))
{
putstr++;
if (ps== 0) break;
Send_Char(ps);
}
}
// Text an Position x,y ausgeben (x = 0..15, y = 0..1
//-------------------------------------------------------------------------
void DispMsg2Pos(char *putstr, unsigned char x, unsigned char y)
{
char ps;
Set_Cursor(x, y);
while((ps = *putstr))
{
putstr++;
if (ps== 0) break;
Send_Char(ps);
}
}
void DispROMMsg2Pos(rom char *putstr, unsigned char x, unsigned char y)
{
char ps;
Set_Cursor(x, y);
while((ps = *putstr))
{
putstr++;
if (ps== 0) break;
Send_Char(ps);
}
}
// LCD initialisieren (2 Zeilen)
//-------------------------------------------------------------------------
void Init_LCD() {
Delay100us(150); //15ms warten
NibbleOut(0b00110011,0); //Reset als Command senden
Delay100TCYx(164); //mindestens 4.1ms warten
NibbleOut(0b00110011,0); //Reset als Command senden
Delay10TCYx(40); //100us warten
NibbleOut(0b00110011,0); //Reset als Command senden
Delay10TCYx(40); //100us warten
NibbleOut(0b00100010,0); //4-Bit Mode setzen
Delay10TCYx(40); //100us warten
Send_Cmd(Func_Set); //Befehl für 2 Zeilen und 5x7 Zeichen
Send_Cmd(Disp_On); //Anzeige einschalten
Send_Cmd(Entry_Inc); //jedes neue Zeichen wird hinter das letzte
Send_Cmd(CGRAM);
Data2Disp(Text3); //Spezial Zeichen in LCD laden
Send_Clr_Disp(); //Anzeige löschen
Delay100us(41); //mindestens 4.1ms warten
}
// Verzögerungsroutinen
//-------------------------------------------------------------------------
// Verzögerung ca. n x 100us
//-------------------------------------------------------------------------
void Delay100us(char time)
{
unsigned char i;
for (i=time;i>0u;i--)
Delay10TCYx(40); //n x 100us warten
}
// Verzögerung ca. n x 0.1s
//-------------------------------------------------------------------------
void Delay0s1(char time)
{
unsigned char i;
for (i=time;i>0u;i--)
Delay10KTCYx(40); //n x 100ms warten
}