PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : mal wieder LCD probs



Scrat1
31.01.2005, 19:18
hallo,
also nach wochen des codens hab ich nun das erschaffen:


#include <avr/io.h>

#define LCD_PORT PORTD
#define LCD_DATA0_PORT LCD_PORT
#define LCD_DATA1_PORT PORTB
#define LCD_DATA2_PORT LCD_PORT
#define LCD_DATA3_PORT LCD_PORT
#define LCD_RS_PORT LCD_PORT
#define LCD_RW_PORT LCD_PORT
#define LCD_E_PORT LCD_PORT

#define LCD_RS 4
#define LCD_RW 5
#define LCD_E 6
#define DB0 7
#define DB1 0
#define DB2 2
#define DB3 3


void toggle_e(void)
{
LCD_E_PORT |= _BV(LCD_E);
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
LCD_E_PORT &= ~_BV(1 << LCD_E);
}


void delay(unsigned int count)
{
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us // also 1 us
}


void busy(void)
{
char dataH;
char dataL;
LCD_RW_PORT |= _BV(LCD_RW);
LCD_RS_PORT &= ~_BV(LCD_RS);
DDRD = 0xF7; //PD3 als Eingang definieren 0b11110111
LCD_E_PORT |= _BV(LCD_E); // LCD_E auf high
do{
__asm__ __volatile__( "rjmp 1f\n 1:" ); //delay (500ns)
dataH = PIND; //zuerst hohes Nibble lesen
LCD_E_PORT &= ~_BV(LCD_E);
__asm__ __volatile__( "rjmp 1f\n 1:" ); //delay
LCD_E_PORT |= _BV(LCD_E);
__asm__ __volatile__( "rjmp 1f\n 1:" ); //delay
dataL = PIND; //lese niederes Nibble
LCD_E_PORT &= ~_BV(LCD_E);
//Dieser Code liest neben dem Busy-Flag gleich noch den Adresszähler aus
}while(dataH & (1<<DB3));
//while(PIND & (1<<DB3)) {} // solange warten, bis DB3 (busyFlag) auf 0
//LCD_E_PORT &= ~_BV(LCD_E); // LCD_E auf low
}

int main()
{
DDRD = 0xFF;
DDRB = 0xFF;

delay(20000); //warte 20 ms (20000us)

LCD_DATA1_PORT |= _BV(DB1);
LCD_DATA0_PORT |= _BV(DB0);

toggle_e();

delay(5000); //mehr als 4,1 ms warten (4992)

toggle_e();

delay(200); // es muss mehr als 100 us gewartet werden

toggle_e();

delay(200); // es muss mehr als 100 us gewartet werden

LCD_DATA0_PORT &= ~_BV(DB0); //LCD_DATA0_PORT &= ~_BV(DB0);
//PORTD = 0x20>>4; //entspricht 0b00100000
toggle_e();
delay(100); //mehr als 100us warten

busy();

LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT = _BV(DB1); //1 -> high nibble 0b0010 (36) von 40
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 4 + 36 = 40 -> 0x28
toggle_e();
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT = _BV(DB2); //1
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx0100 (4) von 40
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();

//In diesem Fall ist data = 0x28, wie es bereits oben erwähnt wurde.
//Dann werden alle Datenpins wieder auf logisch '0' gesetzt.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0
LCD_DATA0_PORT &= ~_BV(DB0); //0


// Als nächstes soll das Display ausgeschaltet werden. Dies erfolgt durch das Senden von 0x08 (vgl. Datenblatt).
// Das Senden erfolgt analog zu der obigen Erklärung (dort war es 0x28 für den 4-Bit-Modus).
// Danach muss das Display gelöscht werden. Hierzu muss 0x01 gesendet werden (vgl. Datenblatt).
// Zu guter letzt muss noch der Start-Modus (entry mode) definiert werden.
// Hier soll das Display einfach aktiviert und der Cursor deaktiviert werden. Dies erfolgt durch Senden von 0x0C.
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst. (s.u.)
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
delay(100);
//0x08 <- Als nächstes soll das Display ausgeschaltet werden.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 8
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 8 = 8 -> 0x08
toggle_e();
LCD_DATA3_PORT = _BV(DB3); //1
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx1000 (8) von 8
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();

//Dann werden alle Datenpins wieder auf logisch '0' gesetzt.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0
LCD_DATA0_PORT &= ~_BV(DB0); //0




/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
delay(100);
//Danach muss das Display gelöscht werden. Hierzu muss 0x01 gesendet werden
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 1
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 1 = 1 -> 0x01
toggle_e();
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx0001 (1) von 1
LCD_DATA0_PORT = _BV(DB0); //1
toggle_e();

//Dann werden alle Datenpins wieder auf logisch '0' gesetzt.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0
LCD_DATA0_PORT &= ~_BV(DB0); //0





////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
delay(100);
//Hier soll das Display einfach aktiviert und der Cursor deaktiviert werden. Dies erfolgt durch Senden von 0x0C.
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 12 = 12 -> 0x0c
toggle_e();
LCD_DATA3_PORT = _BV(DB3); //0
LCD_DATA2_PORT = _BV(DB2); //1
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx1100 (12) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();

//Dann werden alle Datenpins wieder auf logisch '0' gesetzt.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0
LCD_DATA0_PORT &= ~_BV(DB0); //0

delay(100);
///////////////////////////////////////////////////////////////
//////////////////////INITIALIESIERUNG ABGESCHLOSSEN///////////
///////////////////////////////////////////////////////////////


//Das Schreiben von Daten auf dem Display funktioniert mit
//den bereits oben angeführten Befehlen. RS muss auf H-Pegel sein, R/W auf Low.
LCD_RS_PORT |= _BV(LCD_RS);
LCD_RW_PORT |= _BV(LCD_RW);

//0010 0001=!
delay(100);
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT = _BV(DB1); //1 -> high nibble
LCD_DATA0_PORT &= ~_BV(DB0); //0

toggle_e();
LCD_DATA3_PORT = _BV(DB3); //1
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();
}



nun funktioniert das display mit diesem Code nicht, es kommen nur 2 schwarze Balken. (generell geht das display schon).

Hat jemand ne idee was da nicht stimmt?.....


Gruß
Scrat1

noNeed 4 aNick
01.02.2005, 00:09
Ich denk mal, so simpel wird's net sein, aber deine delay Funktion delay't doch immer nur 1 us, oder seh ich das falsch?

Die als Parameter übergebene Variable count wird doch gar nicht miteinbezogen in die Funktion...

Scrat1
01.02.2005, 14:44
oh danke,
habs jetzt so gmacht:


void delay(unsigned int count)
{
int i;
for(i=0;count>i;i++)
{
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us // also 1 us
}
}


es geht aber trotzdem net..

Gruß
Scrat1

Felix G
01.02.2005, 15:17
void toggle_e(void)
{
LCD_E_PORT |= _BV(LCD_E);
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
LCD_E_PORT &= ~_BV(1 << LCD_E);
}
Also diese _BV Geschichte bei den Flags kenne ich nicht,
ich mache das immer direkt mit "|= (1 << Flagname)"bzw "&= ~(1 << Flagname)"

aber so oder so muss ja eigentlich eine der beiden Varianten in deinem Code falsch sein.
(da sonst auch überall das "1 <<" fehlt nehme ich mal an die zweite Schreibweise ist die falsche)

Scrat1
01.02.2005, 15:31
Hallo,
ja danke..
habs verbessert, funzt aber immer noch net.

nun noch ne 2te Frage:

was is das beste um bits zu setzen?
PORTD |= (1 << 6);
PORTD |= _BV(1 << 6);
oder sbi()


Gruß
Scrat1

Thorsten
01.02.2005, 15:53
sbi() ist veraltet und wird bald entfernt.
_BV(bit) ist ein Makro, der preprozessor ersetzt es zu (1 << (bit))
Ob man _BV oder (1<<(bit)) verwendet ist geschmackssache,
persöhnlich finde ich (1<<(bit)) besser, weil _BV nicht jeder kennt.

_BV(1<<6) wird nicht Funktionieren, die 1 wird 6 mal nach rechts
geschoben, _BV() schiebt die 1 noch mal mit dem Ergebnis von
(1<<6) nach rechts, ergibt also Murks.

EDIT:
siehe:
http://jubal.westnet.com/AVR/doc/avr-libc-user-manual/
und dann auf Modules --> Special function registers

01.02.2005, 16:01
Hallo

Du hast doch schon schön mit den Markos angefangen, dann bleibe auch
dabei. Macht doch alles viel besser lesbar.

Beispiel:


#define SET_ENABLE PORTD |= _BV(LCD_E);
#define RESET_ENABLE PORTD &= ~ _BV(LCD_E);
#define TOGGLE_ENABLE PORTD ^= _BV(LCD_E);

Im Code dann einfach:

SET_ENABLE;


MFG
Dieter

Scrat1
01.02.2005, 18:37
Danke für den Tipp, aber erstmal sollte das Programm funktionieren... ;)


Gruß
Scrat1

01.02.2005, 19:43
Hallo

Recht hast du schon, das das Programm erstmal laufen sollte.

Wenn du meinen Rat befolgt hättest, wär es dir selber aufgefallen.


//Das Schreiben von Daten auf dem Display funktioniert mit
//den bereits oben angeführten Befehlen. RS muss auf H-Pegel sein, R/W auf Low.
LCD_RS_PORT |= _BV(LCD_RS);
LCD_RW_PORT |= _BV(LCD_RW);

Oben im Text schreibst du es noch richtig und dann.

Hoffe das wars.

Denn Fehler hast du ja bestimmt schon verbessert.


void toggle_e(void)
{
LCD_E_PORT |= _BV(LCD_E);
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
LCD_E_PORT &= ~_BV(1 << LCD_E);
}

MFG
Dieter

Scrat1
01.02.2005, 20:06
Gut danke ;) (wurde verbessert)

so langsam könnts was werden ;)

also am schluss soll auf dem display ein "!" zu sehen sein.
des is der Binärcode: 00101000 ganz am Ende.





Gruß
Scrat1

noNeed 4 aNick
01.02.2005, 22:09
Ach übrigens, du scheinst das ganze ja variabel zu programmieren (Wenn man sich mal so die ganzen Define's anschaut)-

Aber in der busy() greifst du trotzdem auf DDRD zu und weißt diesem Register auch noch einen Konkreten Wert zu...

Scrat1
04.02.2005, 16:10
Oh Danke,
werd ich auch noch verbessern, aber mir gehts jetzt weniger um die kompatibilitä etc. sondern, dass es bei mir funktioniert... ;)



Gruß
Scrat1

noNeed 4 aNick
05.02.2005, 18:21
Bleibt denn dein Display immernoch schwarz?
Bei meinem war's glaub ich so, dass es solange schwarz war, bis es initalisiert wurde...

Da deine delay Funktion aber jetzt richtig arbeiten sollte, kann es dann ja egtl nur an der busy liegen.

Kannst du mal nen Link zu deinem Datasheet posten, bzw den Namen deines Displays?
Bei mir war das damals so, dass das Display in irgend nem Befehl an irgend nem Pin anders initalisiert wurde, als ich's in den Tutorials gelesen habe...

Da hab ich auch sehr lange nach Fehlern gesucht...

Scrat1
05.02.2005, 19:56
Hallo,
jo es bleiben 2 schwarze Balken.

ich hab das Display bei Ebay ersteigert in der Beschreibung heißtes:


Ihr bietet auf ein sehr gut ablesbares (grosser bereich des "Sichtwinkels"), 4-Zeiliges Display der Marke HYUNDAI HB16401 (16 Zeichen pro Zeile), mit Controller HD44780 (bzw. kompatibel) für "Standard" 14-pin Anschluss. Das Display lässt sich hervorragend mit LCD-Programmen wie "LCD-STUDIO" o.Ä. ansteuern, um z.B Systeminformationen des PC abzufragen, Temperatur, Speicherplatz auf HD, MP3-Player-Anzeige, usw...

Maße des Displays: Gesamt= 87x60mm / Aktive Fläche= 61x25mm

Das LC-Display hat keine Hintergrundbeleuchtung und wird ohne Anschlusskabel geliefert.


aber das Display funktioniert ja mit Peter Fleury's Library: http://homepage.sunrise.ch/mysunrise/peterfleury/

naja isch schau mir nochmal die Busy Funktion an...



Gruß
Scrat1

Scrat1
06.02.2005, 12:48
Also,
ich hab jetzt noch n Fehler gefunden (bei der busy-funktion). Und zwar hab ich da den Eingang nicht mehr auf Ausgang zurückgesetzt.

Dann hab ich noch gesehen, dass ich öfters das busy-flag abfragen muss.
und noch einen weiteren initialisierungsteil einbauen muss.

Code sieht jetzt so aus:


#include <avr/io.h>

#define LCD_PORT PORTD
#define LCD_DATA0_PORT LCD_PORT
#define LCD_DATA1_PORT PORTB
#define LCD_DATA2_PORT LCD_PORT
#define LCD_DATA3_PORT LCD_PORT
#define LCD_RS_PORT LCD_PORT
#define LCD_RW_PORT LCD_PORT
#define LCD_E_PORT LCD_PORT

#define LCD_RS 4
#define LCD_RW 5
#define LCD_E 6
#define DB0 7
#define DB1 0
#define DB2 2
#define DB3 3

#define Ende all_low(); //WELCHES NUN all_low MEINS all_high PETER FLEURY'S


void toggle_e(void)
{
LCD_E_PORT |= (1 << LCD_E);
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
LCD_E_PORT &=~(1 << LCD_E);
}

void all_high(void)
{
LCD_DATA0_PORT |= _BV(DB0);
LCD_DATA1_PORT |= _BV(DB1);
LCD_DATA2_PORT |= _BV(DB2);
LCD_DATA3_PORT |= _BV(DB3);
}

void all_low(void)
{
LCD_DATA3_PORT &= ~_BV(DB3);
LCD_DATA2_PORT &= ~_BV(DB2);
LCD_DATA1_PORT &= ~_BV(DB1);
LCD_DATA0_PORT &= ~_BV(DB0);
}

void delay(unsigned long count)
{
long i;
for(i=0;count>i;i++)
{
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us // also 1 us
}
}


void busy(void)
{
LCD_RW_PORT |= _BV(LCD_RW);
LCD_RS_PORT &= ~_BV(LCD_RS);
DDRD = 0xF7; //PD3 als Eingang definieren 0b11110111
LCD_E_PORT |= _BV(LCD_E); // LCD_E auf high

while(PIND & (1<<DB3)) {} // solange warten, bis DB3 (busyFlag) auf 0
LCD_E_PORT &= ~_BV(LCD_E); // LCD_E auf low
DDRD = 0xFF; //und alles auf Ausgang natürlich
}

int
main(void)
{
/* write data (RS=1, RW=0) */
/* write instruction (RS=0, RW=0) */
DDRD = 0xFF;
DDRB = 0xFF;


delay(20000); //warte 20 ms (20000us)

LCD_DATA1_PORT |= (1<<DB1);
LCD_DATA0_PORT |= (1<<DB0);

toggle_e();
delay(5000); //mehr als 4,1 ms warten (4992)
toggle_e();
delay(200); // es muss mehr als 100 us gewartet werden
toggle_e();
delay(200); // es muss mehr als 100 us gewartet werden

LCD_DATA0_PORT &= ~_BV(DB0); //LCD_DATA0_PORT &= ~_BV(DB0);

//PORTD = 0x20>>4; //entspricht 0b00100000
toggle_e();
delay(100); //mehr als 100us warten

busy();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0


//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT |= _BV(DB1); //1 -> high nibble 0b0010 (36) von 40
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 4 + 36 = 40 -> 0x28
toggle_e();
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT |= _BV(DB2); //1
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx0100 (4) von 40
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();


//In diesem Fall ist data = 0x28, wie es bereits oben erwähnt wurde.
//Dann werden alle Datenpins wieder auf logisch '0' gesetzt.

Ende

// Als nächstes soll das Display ausgeschaltet werden. Dies erfolgt durch das Senden von 0x08 (vgl. Datenblatt).
// Das Senden erfolgt analog zu der obigen Erklärung (dort war es 0x28 für den 4-Bit-Modus).
// Danach muss das Display gelöscht werden. Hierzu muss 0x01 gesendet werden (vgl. Datenblatt).
// Zu guter letzt muss noch der Start-Modus (entry mode) definiert werden.
// Hier soll das Display einfach aktiviert und der Cursor deaktiviert werden. Dies erfolgt durch Senden von 0x0C.
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst. (s.u.)
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
busy();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0



delay(100);
//0x08 <- Als nächstes soll das Display ausgeschaltet werden.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 8
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 8 = 8 -> 0x08
toggle_e();
LCD_DATA3_PORT |= _BV(DB3); //1
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx1000 (8) von 8
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();


Ende

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
busy();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

delay(100);
//Danach muss das Display gelöscht werden. Hierzu muss 0x01 gesendet werden
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 1
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 1 = 1 -> 0x01
toggle_e();
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx0001 (1) von 1
LCD_DATA0_PORT |= _BV(DB0); //1
toggle_e();

Ende

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
busy();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

delay(100);
//Hier soll das Display set entry mode DB1 und DB2
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 12 = 12 -> 0x0c
toggle_e();
LCD_DATA3_PORT &= ~_BV(DB3);
//LCD_DATA3_PORT = _BV(DB3); //0
LCD_DATA2_PORT |= _BV(DB2); //1
LCD_DATA1_PORT |= _BV(DB1);
//LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx1100 (12) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();

Ende

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
busy();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

delay(100);
//Hier soll das Display einfach aktiviert und der Cursor deaktiviert werden. Dies erfolgt durch Senden von 0x0C.
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 12 = 12 -> 0x0c
toggle_e();
LCD_DATA3_PORT |= _BV(DB3); //0
LCD_DATA2_PORT |= _BV(DB2); //1
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx1100 (12) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();

Ende

delay(100);
///////////////////////////////////////////////////////////////
//////////////////////INITIALIESIERUNG ABGESCHLOSSEN///////////
///////////////////////////////////////////////////////////////


//CLRSCR
busy();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

delay(100);
//Danach muss das Display gelöscht werden. Hierzu muss 0x01 gesendet werden
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 1
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 1 = 1 -> 0x01
toggle_e();
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx0001 (1) von 1
LCD_DATA0_PORT |= _BV(DB0); //1
toggle_e();

Ende

////////////////////////////////////////////////////
//Das Schreiben von Daten auf dem Display funktioniert mit
//den bereits oben angeführten Befehlen. RS muss auf H-Pegel sein, R/W auf Low.
LCD_RS_PORT |= _BV(LCD_RS);
LCD_RW_PORT &= ~(1 << LCD_RW); // LCD_RW_PORT |= _BV(LCD_RW);
toggle_e();
//0010 0001=!
delay(100);
busy();

//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT |= _BV(DB1); //1 -> high nibble
LCD_DATA0_PORT &= ~_BV(DB0); //0

toggle_e();
LCD_DATA3_PORT |= _BV(DB3); //1
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();
}


was bei dem Display jetzt neuerdings passiert ist, dass nicht mehr nur 2 Balken schwarz sind, sondern, dass bei Zeile 2 und 4 die oberen drei Pixel Reihen auch schwarz sind.
Das ist aber nur sichtbar wenn man den Kontrast sehr sehr dunkel dreht.

Das gewünschte Zeichen wird aber nicht ausgegeben.

Gruß
Scrat1

06.02.2005, 12:57
Hallo

Lass die Busy Abfrage erstmal ganz raus und setze entsprechende Delays.
Kannst du später immer noch anpassen. Simuliere das ganze und schau dir alle Pins genau an.

Wieso sind deine DatenPins so wild belegt. Besteht nicht die Möglichkeit, die DB0 bis DB 3 schön auf einen Port zu legen ?


Vereinfacht die Sache am Anfang.

MFG
Dieter

Scrat1
09.02.2005, 17:57
Also habs jetzt geschafft 2 Sachen waren zu machen:
1. 0x28 = 40 = 0b0010 1000 und nicht 0b0010 0100 !!
2. Entry Mode musste noch gesetzt werden 0b0000 0111

jetzt sieht der Code so aus:


#include <avr/io.h>

#define LCD_PORT PORTD
#define LCD_DATA0_PORT LCD_PORT
#define LCD_DATA1_PORT PORTB
#define LCD_DATA2_PORT LCD_PORT
#define LCD_DATA3_PORT LCD_PORT
#define LCD_RS_PORT LCD_PORT
#define LCD_RW_PORT LCD_PORT
#define LCD_E_PORT LCD_PORT

#define LCD_RS 4
#define LCD_RW 5
#define LCD_E 6
#define DB0 7
#define DB1 0
#define DB2 2
#define DB3 3

#define Ende all_low(); //WELCHES NUN all_low MEINS all_high PETER FLEURY'S
#define busy delay(500); //busi();

void toggle_e(void)
{
LCD_E_PORT |= (1 << LCD_E); //LCD_E_PORT |= _BV(LCD_E);
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
LCD_E_PORT &=~(1 << LCD_E); //LCD_E_PORT &= ~_BV(LCD_E);
}

void all_high(void)
{
LCD_DATA0_PORT |= _BV(DB0);
LCD_DATA1_PORT |= _BV(DB1);
LCD_DATA2_PORT |= _BV(DB2);
LCD_DATA3_PORT |= _BV(DB3);
}

void all_low(void)
{
LCD_DATA3_PORT &= ~_BV(DB3);
LCD_DATA2_PORT &= ~_BV(DB2);
LCD_DATA1_PORT &= ~_BV(DB1);
LCD_DATA0_PORT &= ~_BV(DB0);
}

void delay(unsigned long count)
{
long i;
for(i=0;count>i;i++)
{
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us
asm volatile ("rjmp 1f\n 1:"); //warte 500ns 0,543 us // also 1 us
}
}


void busi(void)
{
//char dataH;
//char dataL;
LCD_RW_PORT |= _BV(LCD_RW);
LCD_RS_PORT &= ~_BV(LCD_RS);
//DDRD &= ~(1 << LCD_E);
DDRD = 0xF7; //PD3 als Eingang definieren 0b11110111
LCD_E_PORT |= _BV(LCD_E); // LCD_E auf high
/*
do{
__asm__ __volatile__( "rjmp 1f\n 1:" ); //delay (500ns)
dataH = PIND; //zuerst hohes Nibble lesen
LCD_E_PORT &= ~_BV(LCD_E);
__asm__ __volatile__( "rjmp 1f\n 1:" ); //delay
LCD_E_PORT |= _BV(LCD_E);
__asm__ __volatile__( "rjmp 1f\n 1:" ); //delay
dataL = PIND; //lese niederes Nibble
LCD_E_PORT &= ~_BV(LCD_E);
//Dieser Code liest neben dem Busy-Flag gleich noch den Adresszähler aus
}while(dataH & (1<<DB3));
*/

while(PIND & (1<<DB3)) {asm volatile ("nop");} // solange warten, bis DB3 (busyFlag) auf 0
LCD_E_PORT &= ~_BV(LCD_E); // LCD_E auf low
DDRD = 0xFF; //und alles auf Ausgang natürlich
}

int
main(void)
{
/* write data (RS=1, RW=0) */
/* write instruction (RS=0, RW=0) */
DDRD = 0xFF;
DDRB = 0xFF;


delay(20000); //warte 20 ms (20000us)
all_low();
LCD_DATA1_PORT |= (1<<DB1);
LCD_DATA0_PORT |= (1<<DB0);

toggle_e();

delay(5000); //mehr als 4,1 ms warten (4992)

toggle_e();

delay(200); // es muss mehr als 100 us gewartet werden

toggle_e();

delay(200); // es muss mehr als 100 us gewartet werden

LCD_DATA0_PORT &= ~_BV(DB0); // des muss genommen werden, weil ich ja 0b0010 0000 haben will und oben ist 0b0011 0000 also DB0 löschen!!!!

toggle_e();
delay(100); //mehr als 100us warten

busy//();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst. 0x28 = Function set
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT |= _BV(DB1); //1 -> high nibble 0b0010 (36) von 40
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 8 + 32 = 40 -> 0x28
toggle_e();
LCD_DATA3_PORT |= _BV(DB3);
LCD_DATA2_PORT &= ~_BV(DB2);
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx0100 (4) von 40
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();


//In diesem Fall ist data = 0x28, wie es bereits oben erwähnt wurde.
//Dann werden alle Datenpins wieder auf logisch '0' gesetzt.

Ende

// Als nächstes soll das Display ausgeschaltet werden. Dies erfolgt durch das Senden von 0x08 (vgl. Datenblatt).
// Das Senden erfolgt analog zu der obigen Erklärung (dort war es 0x28 für den 4-Bit-Modus).
// Danach muss das Display gelöscht werden. Hierzu muss 0x01 gesendet werden (vgl. Datenblatt).
// Zu guter letzt muss noch der Start-Modus (entry mode) definiert werden.
// Hier soll das Display einfach aktiviert und der Cursor deaktiviert werden. Dies erfolgt durch Senden von 0x0C.
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst. (s.u.)
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
busy//();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0



delay(100);
//0x08 <- Als nächstes soll das Display ausgeschaltet werden.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 8
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 8 = 8 -> 0x08
toggle_e();
LCD_DATA3_PORT |= _BV(DB3); //1
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx1000 (8) von 8
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();


Ende

// jetzt kommt lcd_clrscr und set_entry_mode
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

busy//();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

delay(100);
//Danach muss das Display gelöscht werden. Hierzu muss 0x01 gesendet werden
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 1
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 1 = 1 -> 0x01
toggle_e();
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx0001 (1) von 1
LCD_DATA0_PORT |= _BV(DB0); //1
toggle_e();

Ende
// was soll des sein ? 0b0000 0110 ?? aha des isch set entry mode DB1 und DB2
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
busy//();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

delay(100);
//Hier soll das Display set entry mode DB1 und DB2
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 12 = 12 -> 0x0c
toggle_e();
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT |= _BV(DB2); //1
LCD_DATA1_PORT |= _BV(DB1); //1 -> high nibble 0bxxxx1100 (12) von 12
LCD_DATA0_PORT |= _BV(DB0); //1 <- nach datasheet kann aber auch 0 sein
toggle_e();

Ende

////////////////////////////////////////////////////////////
////////////////*///////////////////////////////////////////
////////////////////////////////////////////////////////////
busy//();


LCD_RS_PORT &= ~_BV(LCD_RS);
LCD_RW_PORT &= ~_BV(LCD_RW); //Daten als Befehl zu deuten sind. Dies erfolgt durch RS=0 und RW=0

delay(100);
//Hier soll das Display einfach aktiviert und der Cursor deaktiviert werden. Dies erfolgt durch Senden von 0x0C.
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0b0000 (0) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0

// macht insgesamt 0 + 12 = 12 -> 0x0c
toggle_e();
LCD_DATA3_PORT |= _BV(DB3); //1
LCD_DATA2_PORT |= _BV(DB2); //1
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble 0bxxxx1100 (12) von 12
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();

Ende

delay(100);
///////////////////////////////////////////////////////////////
//////////////////////INITIALIESIERUNG ABGESCHLOSSEN///////////
///////////////////////////////////////////////////////////////

////////////////////////////////////////////////////
//Das Schreiben von Daten auf dem Display funktioniert mit
//den bereits oben angeführten Befehlen. RS muss auf H-Pegel sein, R/W auf Low.
LCD_RS_PORT |= _BV(LCD_RS);
LCD_RW_PORT &= ~(1 << LCD_RW); // LCD_RW_PORT |= _BV(LCD_RW);

// ES WIRD Hi ausgegeben!!
//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT |= _BV(DB2); //1
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble
LCD_DATA0_PORT &= ~_BV(DB0); //0

toggle_e();
LCD_DATA3_PORT |= _BV(DB3); //1
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble
LCD_DATA0_PORT &= ~_BV(DB0); //0
toggle_e();
busy


//Die beiden Nibble werden nun hintereinander an das LCD gesendet, das obere zuerst.
LCD_DATA3_PORT &= ~_BV(DB3); //0
LCD_DATA2_PORT |= _BV(DB2); //1
LCD_DATA1_PORT |= _BV(DB1); //1 -> high nibble
LCD_DATA0_PORT &= ~_BV(DB0); //0

toggle_e();
LCD_DATA3_PORT |= _BV(DB3); //1
LCD_DATA2_PORT &= ~_BV(DB2); //0
LCD_DATA1_PORT &= ~_BV(DB1); //0 -> high nibble
LCD_DATA0_PORT |= _BV(DB0); //1
toggle_e();
busy
}


leider funktioniert die Busi funktion noch nicht. Naja das werd ich noch hinbekommen, aber wenn jemand schon den Fehler sieht, kann er ihn ruhig sagen ;)


Also Danke nochmals für eure Hilfe!!


Gruß
Scrat1

pebisoft
12.02.2005, 10:28
hallo, ich möchte am lcd 2x24 ein kommawert einer sinusfunktion ausgeben mit 4 nachkommastellen. wer kann helfen.
mfg pebisoft