-
mal wieder LCD probs
hallo,
also nach wochen des codens hab ich nun das erschaffen:
Code:
#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
-
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...
-
oh danke,
habs jetzt so gmacht:
Code:
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
-
Code:
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)
-
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
-
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
-
Hallo
Du hast doch schon schön mit den Markos angefangen, dann bleibe auch
dabei. Macht doch alles viel besser lesbar.
Beispiel:
Code:
#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
-
Danke für den Tipp, aber erstmal sollte das Programm funktionieren... ;)
Gruß
Scrat1
-
Hallo
Recht hast du schon, das das Programm erstmal laufen sollte.
Wenn du meinen Rat befolgt hättest, wär es dir selber aufgefallen.
Code:
//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.
Code:
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
-
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