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 }