Hallo:)
ich habe mir selber jetzt ein serielles LCD-Display zusammengebaut das
über 3 Anschlüsse mit dem Microcontroller angeschlossen wird. Nur die
CLK, Enable und der Datenbus sind mit dem Microcontroller verbunden.
Zwischen dem Microcontroller habe ich ein Schieberegister angeschloessen
dass die Daten an das LCD-Display leiten soll.
Den Schaltplan habe ich im Anhang auch hinzugefügt.
Hab auch mein programm auf dem Microcontroller draufgespielt und die
einzelnen Pinnen mit dem Oszilloskop überprüft. Signale bekamme ich an
den jeweiligen Pins wenn z.b clock auf high schaltete setze der datenbus
auch auf high und das umgekehrt.
Ich habe glaube ich bei der Initialisierung bestimmt ein Fehler gemacht
nur ich weiss nicht wo genau:(. Bei einer bestimmten steigenden
Clock-flanke schaltet sich die Hintergrundbeleuchtung meiens Displays
aus:(
Hoffe könnt mir was weiter helfen^^
dass macht er nur wenn ich mein programmm draufspiele, dann wird das
display dunkel. Außerdem zeigt mir dann dieses display nichts an was ich
programmiert habe :(
also ist der plan selber schonmal falsch oder wie darf ich das jetzt
verstehen? hab diesen plan von ulrich radig gefunden. Dies wurde mir
auch empfohlen.
leider ja mir ist nicht im klaren wieso er eine for schleife für die
initialisierung des 4 bit und der DD-Ram benutzt. Ich würde dies
komplett weg lassen und nur die beiden Initialisierungen aufschreiben.
Hab den code etwas geändert genau so:
void lcd_init (void)
{
//Set Port Direction Register
DDR_LCD_DATA_ENABLE |= (1<<LCD_DATA_ENABLE);
DDR_LCD_CLOCK |= (1<<LCD_CLOCK);
DDR_LCD_DATA |= (1<<LCD_DATA);
PORT_LCD_DATA_ENABLE &= ~(1<<LCD_DATA_ENABLE);
//Wait a short Time afer Power on
WAIT(10);
lcd_write (0x22,0); //Init in 4 Bit Mode
lcd_write (0x80,0); //Set DD-Ram Adresse = 0
lcd_write (0x40,0); //1 Zeilen
lcd_write (0xD0,0); //Display On
} sofern dies richtig jetzt nun ist. Dies habe ich so aus dem Datenblatt
entnommmen hoffe habe alles wichtige in meiner lcd_init enthalten.
Adrian schrieb:> leider ja mir ist nicht im klaren wieso er eine for schleife für die> initialisierung des 4 bit und der DD-Ram benutzt.
Eben.
Die korrekte Sequenz, die funktioniert lautet:
Du präsentierst dem LCD an den Datenbits D4 bis D7 erst mal eine 3 (d.h
D4 auf 1, D5 auf 1). Und das 3 mal hintereinander, wobei jedesmal RS auf
0 bleibt und natürlich so wie immer die Enable Leitung gepulst wird.
Aber Achtung: du musst zwischen den Enable Pulsen Wartezeiten einhalten!
Erst dann ist sicher gestellt, dass das LCD auf jeden Fall im 8-Bit
Modus ist, egal was vorher passiert ist.
Und erst dann präsentierst du ihm einmalig eine 2 an den Datenleitungen
D4 bis D7 (also D5 auf 1).
WIeder: Rs muss auf 0 bleiben und auf Enable wird ein Puls erzeugt.
Und erst dann ist das LCD im 4-Bit Modus und du kannst erstmals die
Funktion lcd_write benutzen.
PS: Du kannst ein LCD beliebig langsam ansteuern. D.h. wenn du die
Möglichkeit dazu hast, dann kannst du an die Ausgangsleitungen vom
Schieberegister, bzw an die Enable Steuerleutung etwas zusätzlich
anschliessen, womit du die Pegel erkennen kannst und somit siehst, ob da
die Pegel rauskommen, so wie sie eigentlich sein sollten.
Du darfst die Pulse, die zeitlichen Abstände etc. beliebig langsam
machen, so dass du als Mensch da noch mitkommst. Nur zu schnell darf es
nicht sein. Es gibt da minimal einzuhaltende Wartezeiten. Insbesondere
die ersten Initialisierungsschritte sind da kritisch.
AVR-Tutorial: LCD
snayer2311 schrieb:> ich weiss gerade nicht ob das so richtig ist wie dues mir gerade gesagt> hast
So wie Karl Heinz es gesagt hat, ist es richtig. So wie du es machst,
ist es falsch. Lies einfach mal das Datenblatt zum Display und überleg,
ob die Zeiten und Abläufe, die darin auftauchen auch in deinem Programm
auftauchen. Du musst gerade zu Beginn der Initialisierung (Datenbreite)
das Timing unbedingt einhalten.
1
lcd_write(0x22,0);//Init in 4 Bit Mode
Dass du da über einen Trick schnell hintereinander eine 0x2 sendest
hilft da nicht weiter und Kommentare kann das Display auch nicht
lesen...
1
gotoConversionLoop;
> weiss gerade nicht ob das so richtig ist
Ist das C?
Dann ist es falsch: ein Anfänger braucht sicher kein GOTO in einem Stück
C-Code...
> Nibbel
Noch so einer: ein halbes Byte ist ein Nibble, der mit einem Nippel
nun so gar nichts zu tun hat...
> Dass du da über einen Trick schnell hintereinander eine 0x2 sendest
Ja, das ist mir auch aufgefallen. Das könnte vielleicht sogar
funktionieren. Glücklich bin ich damit trotzdem nicht.
@snayer2311
Der springende Punkt ist, dass du zum Umschalten in den 4 Bit Modus die
Funktion lcd_write noch nicht benutzen kannst!
Genau das hab ich versucht dir klar zu machen.
du kannst die shift_out benutzen, denn die gibt im Grunde ja ein Nibble
kontrolliert an das Schieberegister aus. Allerdings ist das Interface
für diese Funktion etwas 'unhandlich', weil der Aufrufer die Bits
zurecht schieben muss und nicht die Funktion das selber macht. Eventuell
würde ich mir da eine eigene Funktion shift_out_nibble machen, die den
Zurechtschiebeteil an die Datenbits erledigt, damit ich in lcd_init den
Teil nicht habe (den das ist beim Fehlersuchen in der lcd_init eher
unpraktisch, wenn man an dieser Stelle laufend um die Ecke denken muss)
Aber da musst du durch. Genau deswegen hab ich es angesprochen, dass du
den ganzen Vorgang beliebig langsam machen darfst. Nutze das tatsächlich
aus! Häng meinetwegen ein paar LED an die Leitungen, die zum LCD gehen
und sieh dir an, welche Pegel wann da am LCD ankommen. Du MUSST die
angegebene Sequenz dort aufleuchten sehen. 3 mal hintereinander das
Bitmuster für 3 an den Datenleitungen und dann einmalig das Bitmuster
für 2 an den Datenleitungen. Wenn du langsam machst, dann überfährst du
auch ganz sicher nicht das LCD.
Sorry. Aber solche 'Spezialsachen' kann man nun mal nicht machen, wenn
man nicht gewillt ist, sich mit der Materie zu beschäftigen. Daher geb
ich dir auch nur Tips und sag dir, was du letzten Endes an den Ausgängen
vom Schieberegister sehen musst. Aber machen .. musst DU es.
Habe ich soweit gemacht jetzt meckert, eine eigene Funktion geschreiben
die den Zurechtschiebeteil macht ohne die lcd_write Funktion
zuschreiben. Jetzt meckert er über einen Fehler den ich nicht verstehe.
Irgendein zeichen fehlt aber entdecke den Fehler nicht
Error 1 expected ';', ',' or ')' before '=' token F:\Hauptprojekt
serielle Displaysteuerung\SeriellesDisplay\SeriellesDisplay\lcd.c 20
27 SeriellesDisplay
er
Anscheinend soll das Programm so von Ulrich Radig funktionieren ohne
dass man da was ändern sollte. Wieso solle ich da eine neue Funktion
schreiben wenn lcd_write ja nur dass alles in dem Schieberegister
schreibt und die Funktion shift_data out eigentlich das was in dem
Schieberegister steht ins display aufnimmt. Am ende dieser Funktion ist
ja dieses enable dass die alle daten des Displays im Schieberegister
aufnimmt.
Hab auf seiner Seite genau mir das gleiche serielle Display
zusammengebaut.
hmm dann hab ich i-wie ein anders Problem mache gerade eine Fehler
analyse und möchte mal sowie es ulrich radig gemacht hatte meine pins am
portC anschließen.
snayer2311 schrieb:> Wieso solle ich ....
Weil Ulli 2007 mit der damailgen Compilergeneration wusste was er tat.
Er hatte das Wissen und das Können, das durchzuziehen.
Du hingegen sträubst dich seit Tagen, dir eine simple Hilfsfunktion zu
schreiben, so dass du die Grund-Initialisierung ...
1
voidlcd_init()
2
{
3
//Set Port Direction Register
4
//LCD_DDR = 0x07;
5
DDR_LCD_DATA_ENABLE|=(1<<LCD_DATA_ENABLE);
6
DDR_LCD_CLOCK|=(1<<LCD_CLOCK);
7
DDR_LCD_DATA|=(1<<LCD_DATA);
8
PORT_LCD_DATA_ENABLE&=~(1<<LCD_DATA_ENABLE);
9
10
_delay_ms(50);// 16 sollten eigentlich reichen
11
12
shift_out_nibble(0x03);
13
_delay_ms(10);// minimum 4.1 ms
14
shift_out_nibble(0x03);
15
_delay_ms(1);// minimum 0.1 ms
16
shift_out_nibble(0x03);
17
_delay_ms(1);
18
19
shift_out_nibble(0x02);
20
_delay_ms(1);
21
22
// ab jetzt sind wir im 4-Bit Modus und lcd_write kann benutzt werden
23
24
lcd_write(0x0C,0);//Display On
25
}
... schreiben kannst bzw. anstelle der NOP da einfach mal ein paar
längere _delay_xx einzufügen und mit ein paar LED oder einem Voltmeter
nachzusehen ob auch alles richtig angeschlossen ist. (und mit 'längere'
meine ich nicht Millisekunden, sondern durchaus Zeiten im
Sekundenbereich oder noch länger)
Aber es ist ok. Die Funktion shift_out_nibble wäre zwar in 5 Minuten
geschrieben (vor allen Dingen deshalb weil man sich an lcd_write
orientieren kann, aber lediglich ein Nibble ausgibt und nicht ein ganzes
Byte) und die Zeitsteuerung von NOP auf _delay_xx umgestellt, du rödelst
dafür lieber tagelang rum und klebst an Code fest, den du nicht
verstehts bzw. an einem Übertragungsmechanismus den du nicht verstehst,
bzw. an Code dessen Details du nicht verstehst.
Vereinfacht gesagt und auf einen Punkt gebracht.
habs jetzt soweit alles geändert wies mir beschrieben wurde hoffe das
stimmt zumindest. hab ein problem beim debuggen und zwar stoppt er bei
schon beim ersten delay und bleibt dann bei running fest hängen. was
kann ich da machen?
snayer2311 schrieb:> Hallo:) Ich bin mir nicht gerade sicher ob diese Funktion die Daten auch> richtig in das schieberegister reinstellt
Was heißt du bist dir nicht sicher?
Schreib dir ein Testprogramm
1
intmain()
2
{
3
...
4
5
shift_data_out(0x01<<3);
6
7
while(1)
8
;
9
}
und sieh nach (Voltmeter oder LED), ob am Pin DB4 vom LCD eine 1 anliegt
und alle anderen auf 0 sind.
Dasselbe probierst du mit 0x02, 0x04 und 0x08 und den Pins DB5, DB6 und
DB7 am LCD, die jeweils auf 1 liegen müssen und die jeweils anderen auf
0. Wenn du dann noch ein bischen spielen willst, dann probierst du das
noch mit anderen Kombinationen der 'Zahlenwerten' bzw. der RS Leitung.
Dann bist du sicher.
Das ganze geht schneller, als hier eine Frage einzutippen und so ganz
nebenbei erhöht das auch noch deine Programmierpraxis und deine
Fähigkeiten dir selbst zu helfen, indem du dir überlegst, wie man etwas
testen kann.
Dein Problem: du sitzt da wie der Hase vor der Schlange, weil dein LCD
nicht reagiert. Gut.
Was du übersiehst: damit ein LCD funktioniert, muss eine komplexe Kette
von Aktionen korrekt sein. Und die kann man alle einzeln testen und
sicherstellen, dass sie funktionieren. Das beginnt mit der Verkabelung,
führt über die korrekte Ansteuerung der dazwischen liegenden IC (in
deinem Fall das Schieberegister) und endet erst zum Schluss in der
korrekten Initialisierungssequenz. Aber jeder Schritt ist für sich
einzeln testbar. Und dieses Prinzip der aufeinander aufbauenden Tests
vom einfachen zum immer komplexeren ist ein allgemeines Prinzip. Daher
ist es gut darin eine gewisse Praxis zu haben. Das wird dir auch in
Zukunft noch so manches mal aus der Patsche helfen, wenn du dich
überwindest und in diese Einzeltests ein wenig Zeit investierst.
Soweit habe ich das verstanden nur mein problem ist gerade welche
schleife ich für die funktion shift_data_out verwenden soll. hab gerade
diese schleife genommmen
for (unsigned char a=4; a>0; a--)
{
if ( (data & (1<<(a-1))) != 0)
{
PORT_LCD_DATA |= (1<<LCD_DATA); //Data PIN (High)
}
else
{
PORT_LCD_DATA &= ~(1<<LCD_DATA); //Data PIN (LOW)
}
Clock();
}
enable();
}
Beim Compilieren ist immer die lcd leitung null und ich messe an
ausgängen nichts. Dann wie erreiche ich zum beispiel dass ich an db4
eine 1 bekomme wenn meine schleife 4 mal durchläuft?
Soweit funktioniert bei mir die Initialisierung. Ich sehe einen blinken
Curser und kann ihn beliebig switchen wie ich es gerne möchte. Aber wenn
ich ein Wort ausgeben möchte funktioniert das mit der funktion
lcd_print(0,0,"Hallo"); irgendwie nicht. Ich bekomme dann links nur
zwei große striche etwa so || und ein komisches Zeichen heraus und der
kurser bleibt dann stehen.
Was muss da umstellen in meiner Funktion?
Hier ist mein Projekt zu der Seriellen Display-Ansteuerung. Hat alles
jetzt wunderbar funktioniert. Ich hab mein Fehler gefunden warum es
nicht funktioniert hatte. Der Fehler lag an der Compilierung meines
AVR-Dragons. Er hat meinen Programmtext anders Programmiert als der
AVR-Burn Compiler.
Ich nehme jetzt in Zukunft AVR-Burn um mein Programmtext zu compilieren.
Hi
>Der Fehler lag an der Compilierung meines AVR-Dragons.
Der Dragon compiliert überhaupt nichts.
>Er hat meinen Programmtext anders Programmiert als der AVR-Burn Compiler.
Der Dragon sieht gar nichts von deinem Programmtext. AVR-Burn (falls das
so heißt) dürfte auch kein Compiler sein.
MfG Spess