Guten Abend Community,
ich bin mal wieder am einen C-Code am verzweifeln.
Ich versuche ein LCD Display (KS0073, 4 Zeilen je 20 Zeichen) im 4 Bit-Modus betreiben.
Dabei ist das Display am PORTD von einem ATmega 8 Controller angeschlossen:
- Datenleitung D0-D3 an Pin D0-D3
- RS an Pin D4
- RW an Pin D5
- Enable an Pin D6
Ich versuche ohne Fremdbibliothek auszukommen, damit der Lerneffekt möglichs hoch sein soll.
Habe mir natürlich die "fertigen" Ideen von Peter Fleury angeschaut, wie er es macht (Aber nicht getestet ob diese Bib. bei mir laufen).
Dabei ist mir beim Initialisieren schon was auf gefallen:
In der Bib. von Peter Fleury wird das Display 3 mal einen Reset unterzogen:
Code:
/* reset LCD */
delay(16000); /* wait 16ms after power-on */
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
delay(4992); /* wait 5ms */
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
delay(64); /* wait 64us */
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
delay(64); /* wait 64us */
Aber laut Datenblatt des KS0073 wird der 4 Bit-Modus so Initialisiert (mein Code):
Code:
_delay_ms(50); // Nachdem die Versorgungsspannung anliegt, braucht das Display min. 20ms bis es bereit ist. Hier sicherheits halber 50ms.
LCD_cmd(0x33); // 2x Softreset (?).
LCD_cmd(0x32); // 1x Softreset, da nach auf 4Bit Modus.
LCD_cmd(0x2C); // Erweitertes Funktionsregister freischalten.
LCD_cmd(0x09); // Erweitertes Funktionsregister: 4 Zeilen aktivieren.
LCD_cmd(0x28); // Erweitertes Funktionsregister sperren.
LCD_cmd(0x0C); // Display einschalten, Cursor aus, Blinken aus.
LCD_cmd(0x01); // Display löschen.
_delay_ms(1.6); // Befehl Display löschen dauert länger als andere Befehle.
LCD_cmd(0x06); // Display fertig machen. => Initialisierung ist beendet.
Die LCD_cmd Funktion sieht so aus:
Code:
void LCD_cmd(uint8_t data)
{
uint8_t data_L, data_H;
data_L=data&0x0F; // Datenbyte erzeugen b0000.xxxx
data_H=data>>4; // Datenbyte erzeugen b0000.xxxx
LCD_PORT=data_H; // Erst das höhere Nibbel auf die Daten-Pins legen.
LCD_PORT&=~(1<<LCD_RW_PIN); // RW-Pin auf low für Schreibzugriff.
LCD_PORT&=~(1<<LCD_RS_PIN); // RS-Pin auf low für Kommando Byte.
LCD_enable(); // LCD Display signalisieren, dass Datenbyte abgeholte werden kann.
LCD_PORT=data_L; // Das niedrigere Nibbel auf die Daten_Pins legen.
LCD_PORT&=~(1<<LCD_RW_PIN); // RW-Pin auf low für Schreibzugriff.
LCD_PORT&=~(1<<LCD_RS_PIN); // RS-Pin auf low für Kommando Byte.
LCD_enable(); // LCD Display signalisieren, dass Datenbyte abgeholte werden kann.
}
void LCD_enable()
{
LCD_PORT|=(1<<LCD_E_PIN);
_delay_us(50);
LCD_PORT&=~(1<<LCD_E_PIN);
}
Das Fragezeichen in der Init stellt meine erste Frage da: Warum muss ich das Display 3x zurücksetzten? Im Datenblatt habe ich nichts gefunden (s. 59 steht die Init für 4Bit), oder überlesen.
Das ist die eine Frage... Mittlerweile wird das Display über die oben genannte Funktion initialisiert.
Und nun das wo ich im Moment scheiter:
Code:
// Begrüßng schreiben
LCD_zeichen('I');
LCD_zeichen('c');
Die Funktion dazu:
Code:
void LCD_zeichen(uint8_t data)
{
uint8_t data_L, data_H;
data_H=data>>4;
data_H=data_H&0x0F; // Datenbyte erzeugen b0000.xxxx
data_L=data&0x0F; // Datenbyte erzeugen b0000.xxxx
LCD_PORT=data_L; // Erst das höhere Nibbel auf die Daten-Pins legen.
LCD_PORT&=~(1<<LCD_RW_PIN); // RW-Pin auf low für Schreibzugriff.
LCD_PORT|=(1<<LCD_RS_PIN); // RS-Pin auf high für DatenByte.
LCD_enable(); // LCD Display signalisieren, dass Datenbyte abgeholte werden kann.
LCD_PORT=data_H; // Das niedrigere Nibbel auf die Daten_Pins legen.
LCD_PORT&=~(1<<LCD_RW_PIN); // RW-Pin auf low für Schreibzugriff.
LCD_PORT|=(1<<LCD_RS_PIN); // RS-Pin auf high für DatenByte.
LCD_enable(); // LCD Display signalisieren, dass Datenbyte abgeholte werden kann.
}
Was ist mir aufgefallen:
- Das ich hier die Nibbels umgekehrt senden muss wie bei den Kommandos ( Bei Kommandos erst High-Nibbel, dann Low-Nobbel. Beim Zeichenschreiben erst Low-Nibbel, dann High-Nibbel).
- Wenn ich das 'I' alleine schreie, wird es richtig dargestellt. Kommen mehre Buchstaben dazu gibt es Buchstabensalat.
Warum? Wo ist mein Denkfehler, oder habe ich das Display falsch initialisiert?
Vollständigkeitshalber mal den Kompletten C-Code von mir:
Code:
/*
* BMA020.c
*
*
* Created: 26.01.2014 14:28:04
* Author: Jimmy
*
* Pin Konfiguration:
*** PC 4: SDA
*** PC 5: SCL
***
*** PD0-PD3: Daten LCD-Display
*** PD4: RS LCD-Display
*** PD5: RW LCD-Display
*** PD6: Enable (freigabe)
*/
#include <avr/io.h>
#include <stdlib.h>
#define F_CPU 8000000UL
#include <util/delay.h>
// ****** Port D umbezeichen ******
#define LCD_PORT PORTD // Port D ist nun LCD_PORT
#define LCD_data0_PIN PD0 // Pin D0 ist nun LCD_data0_PIN
#define LCD_data1_PIN PD1 // Pin D1 ist nun LCD_data1_PIN
#define LCD_data2_PIN PD2 // Pin D2 ist nun LCD_data2_PIN
#define LCD_data3_PIN PD3 // Pin D3 ist nun LCD_data3_PIN
#define LCD_RS_PIN PD4 // Pin D4 ist nun LCD_RS_PIN
#define LCD_RW_PIN PD5 // Pin D5 ist nun LCD_RW_PIN
#define LCD_E_PIN PD6 // Pin D6 ist nun LCD_E_PIN
int16_t poti_wert, x, x_LSB, y, y_LSB, z, z_LSB;
//****** LCD Display Enable Kommando ******
void LCD_enable()
{
LCD_PORT|=(1<<LCD_E_PIN);
_delay_us(50);
LCD_PORT&=~(1<<LCD_E_PIN);
}
//****** Kommandos für LCD Display ******
void LCD_cmd(uint8_t data)
{
uint8_t data_L, data_H;
data_L=data&0x0F; // Datenbyte erzeugen b0000.xxxx
data_H=data>>4; // Datenbyte erzeugen b0000.xxxx
LCD_PORT=data_H; // Erst das höhere Nibbel auf die Daten-Pins legen.
LCD_PORT&=~(1<<LCD_RW_PIN); // RW-Pin auf low für Schreibzugriff.
LCD_PORT&=~(1<<LCD_RS_PIN); // RS-Pin auf low für Kommando Byte.
LCD_enable(); // LCD Display signalisieren, dass Datenbyte abgeholte werden kann.
LCD_PORT=data_L; // Das niedrigere Nibbel auf die Daten_Pins legen.
LCD_PORT&=~(1<<LCD_RW_PIN); // RW-Pin auf low für Schreibzugriff.
LCD_PORT&=~(1<<LCD_RS_PIN); // RS-Pin auf low für Kommando Byte.
LCD_enable(); // LCD Display signalisieren, dass Datenbyte abgeholte werden kann.
}
//****** LCD Display initialisieren ******
void LCD_init(void)
{
_delay_ms(50); // Nachdem die Versorgungsspannung anliegt, braucht das Display min. 20ms bis es bereit ist. Hier sicherheits halber 50ms.
LCD_cmd(0x33); // 2x Softreset (?).
LCD_cmd(0x32); // 1x Softreset, da nach auf 4Bit Modus.
LCD_cmd(0x2C); // Erweitertes Funktionsregister freischalten.
LCD_cmd(0x09); // Erweitertes Funktionsregister: 4 Zeilen aktivieren.
LCD_cmd(0x28); // Erweitertes Funktionsregister sperren.
LCD_cmd(0x0C); // Display einschalten, Cursor aus, Blinken aus.
LCD_cmd(0x01); // Display löschen.
_delay_ms(1.6); // Befehl Display löschen dauert länger als andere Befehle.
LCD_cmd(0x06); // Display fertig machen. => Initialisierung ist beendet.
}
//****** Zeichen im Display ausgeben ******
void LCD_zeichen(uint8_t data)
{
uint8_t data_L, data_H;
data_H=data>>4;
data_H=data_H&0x0F; // Datenbyte erzeugen b0000.xxxx
data_L=data&0x0F; // Datenbyte erzeugen b0000.xxxx
LCD_PORT=data_L; // Erst das höhere Nibbel auf die Daten-Pins legen.
LCD_PORT&=~(1<<LCD_RW_PIN); // RW-Pin auf low für Schreibzugriff.
LCD_PORT|=(1<<LCD_RS_PIN); // RS-Pin auf high für DatenByte.
LCD_enable(); // LCD Display signalisieren, dass Datenbyte abgeholte werden kann.
LCD_PORT=data_H; // Das niedrigere Nibbel auf die Daten_Pins legen.
LCD_PORT&=~(1<<LCD_RW_PIN); // RW-Pin auf low für Schreibzugriff.
LCD_PORT|=(1<<LCD_RS_PIN); // RS-Pin auf high für DatenByte.
LCD_enable(); // LCD Display signalisieren, dass Datenbyte abgeholte werden kann.
}
//****** Hauptfunktion ******
int main(void)
{
// Portrichtung
DDRD=0xFF;
DDRB=0x01;
//Display initialisieren
LCD_init();
// Begrüßng schreiben
LCD_zeichen('I');
LCD_zeichen('C');
while(1)
{
PORTB=0x01; // Den Controller beschäftigen
}
}
Zum vergleich, die Bib von Peter Fleury im Anhang
Hoffe ihr könnt mir weiter helfen.
Lesezeichen