Hallo,
Geduld, Geduld, hier wartet doch keiner in ner Schleife ob Du mal ne
Frage stellst!
Das Nachfolgende musst Du in Deinen eigenen Code umsetzen.
Grundsätzlich läuft das beim HD44780 zum Beispiel so:
1. Instruction "Set DDRAM Adresse" + DDRAM-Adresse
movlw b'01000000' ;40h Ausgabeadresse Zeile 2, Digit 0
iorlw B'10000000' ;HD44780-Befehl "Set DDRAM-Adresse"
movwf LcdControl ;Instruction und DDRAM-Adresse in Variable
RS=0 ;register select: Instruction
RW=0 ;schreiben
;->B'11000000'
2.Jetzt DDRAM-Adresse über den 4Bit-Bus ausgeben:
Busyflagabfrage oder Delay
ANDLW b'11110000' ;unteres Nibble ausmaskieren
movwf LCDPORT ;Oberes Nibble an dass LCD übertragen
Enable =1
nop ;1 Takt warten
Enable= 0
Busyflagabfrage oder Delay
swapf LcdControl,w ;Nibbletausch -> WREG
ANDLW b'11110000' ;Bitmaske anwenden
movwf LCDPORT ;Unteres Nibble an das LCD übertragen
3. Jetzt Zeichen festlegen
movlw "X"
movwf LcdData
RS=1 ;Register select Daten
RW=0 ;schreiben
4. Jetzt Zeichen an LCD senden
sinngemmäß weiter wie mit Variable LcdControl gezeicht
Busyflagabfrage ...
für die weiteren unmittelbar aufeinander folgenden Zeichen in der Zeile
braucht keine neue DDRAM-Adresse gesendet zu werden.
mfg Ottmar
Ottmar K. schrieb:> 4. Jetzt Zeichen an LCD senden> sinngemmäß weiter wie mit Variable LcdControl gezeicht> Busyflagabfrage ...
Und genau da liegt mein Problem. Ich kann ein Zeichen senden (Code1),
aber mit der Routine in Code2 wird es nicht korrekt gesendet und ich
habe keine Ahnung warum.
Ich vermute, dass nur das 6. bit des Zeichens falsch gesendet wird:
'a'=01100001
'!'=00100001
Hallo;
Dein gezeigter Code sieht nicht unbedingt falsch aus;
Aber vielleicht ist Dein Enable zu schnell,
oder der Compiler optimiert was fehlerhaft.
Aber all das sind nur spekulationen,
da du nur einen zu winzigen Ausschnitt vom Programm zeigst.
Vielleicht kannst Du den folgenden Code verstehen,
um ihn auf den PIC umzusetzten:
http://elm-chan.org/fsw/ezlcd/00index_e.htmlhttp://elm-chan.org/docs/lcd/hd44780_e.html
MFG:Markus
Hallo
Versuch mal die oberen 4-Bit zu senden, während das Enable-Bit gesetzt
ist. Zwischen denen schaltest du das Enable-Bit kurz aus, dann wieder
ein. Dann sendest du die 4-Bit, dann schaltest du das Enable-Bit aus und
machst dein delay von 38us. Ich habs immer so gemacht. Ich weiss nicht
ob das etwas ändert, aber vielleicht erkennt er dann die negative Flanke
besser. Dies würde dann aber auch nicht erklären, warum nur 1 Bit falsch
ist. Aber versuchen kannst du's ja. Habe sonst auch keine andere Idee.
An deinem Beispiel erklärt:
chr=0x61;
LCD_RS=1;
hier Enable auf 1 setzen
LCD_D7=(chr>>7)&0x01;
LCD_D6=(chr>>6)&0x01;
LCD_D5=(chr>>5)&0x01;
LCD_D4=(chr>>4)&0x01;
hier Enable auf 0 setzenhier Enable auf 1 setzen
LCD_D7=(chr>>3)&0x01;
LCD_D6=(chr>>2)&0x01;
LCD_D5=(chr>>1)&0x01;
LCD_D4=chr&0x01;
hier Enable auf 0 setzen
Delay10TCYx(19); //Delay ca. 38us
Hier ist der gesamte Code.
@Janik L. (crazygecko) Ich lege die Daten an, und habe dann sowohl eine
steigende als auch eine Fallende flanke beim EN-Signal.
Hallo nochmal;
Dein Programm scheint in der Tat an manchen Stellen ziemlich flott zu
sein;
Die Routinen zu "Bus Width and Initialization" von Elm warten länger
und senden teils auch andere Initialisierungen.
(Figure 4. Software Reset and Initialization, 2. Link zu Elm von oben,
so wie der C-Quellcode auf der Seite vom 1. Link ganz unten.)
Code von Elm - Auszug:
Vor einiger Zeit habe ich auf diesen Routinen für 8051 und SDCC
entwickelt.
Früher habe ich LCDs unter AVR und assembler verwendet.
Meine Erfahrung aus dieser Zeit ist,
dass die Displays jeden Mist anzeigen,
sofern sie überhaupt was machen,
wenn man ihnen mit dem Takt zu sehr "einheizt".
Zu langsam kann man hingegen eigentlich fast nicht takten.
Auch ganze (m)Sec für den Enable etc. waren noch nie zu lang,
für ein LCD, nur für den Anwender davor...
Auch ganz wichtig zu beachten ist,
dass die LCD beim/nach dem Einschalten Zeit benötigen!
Siehe das Delay von 40.000 uSec aus obigem Code!
Ich würde noch versuchen den Zustand des Byte-Portes
über den Debuger oder externe Leds / RS232 anzusehen,
ehe das Enable getaktet wird, um sicherzugehen,
dass der Compiler auch wirklich das an den Port aufbereitet,
nach was es korrekt aussehen sollte.
Da hatte ich mit unter auch schon Fälle,
wo nur ein Umstellen des Codes half,
so dass Zwischenschritte einzeln angeschreiben waren,
samt eigenen temporären Variabelen für Zwischenscritte.
Manchmal hilft auch ein Typ-Cast wie (char)((x >> y) & z) Wunder,
was mich aber hier eher wundern würde.
MFG:Markus
Ich habe deine Initialisierung mal nach
http://www.sprut.de/electronic/lcd/ umgeschrieben, da ich dachte, dass
sie vielleicht so funktioniert. Bei mir ist sie leider nicht gegangen.
Zudem habe ich fesgestellt, dass wenn ich das Display mithilfe eines
anderen Programms initialisiert habe, und dann dein Programm drauf
geladen habe das Display ging. Ich bekam aber am Ende immer noch ein "_"
angezeigt.
Ich habe die Funktionen mehr geschrieben um zu verstehen wie das LCD
funktioniert und etwas zu lernen. Da im Prinzip alles funktioniert bin
ich auch zufrieden.
Weiß jemand wo ich eine LCD Bibliothek downloaden kann bei der ich alle
Ausgänge individuell definieren kann, und nicht an bei den Daten-Pins an
einen Port gebunden bin? Ich brauche das LCD für ein größeres Projekt,
und hätte deshalb gerne eine LCD Bibliothek die sicher funktioniert, um
mir nicht auch noch darüber Gedanken machen zu müssen. Die Bibliothek
sollte auf einen PIC18F45k22 funktionieren.
M. H. schrieb:> Weiß jemand wo ich eine LCD Bibliothek downloaden kann bei der ich alle> Ausgänge individuell definieren kann, und nicht an bei den Daten-Pins an> einen Port gebunden bin?
Überleg die eher, wie du 4-Bit für das LCD hardwaremäßig auf einen Port
bekommst. Dafür gibt es Ports mit mehreren Bits.
L.P. schrieb:> Überleg die eher, wie du 4-Bit für das LCD hardwaremäßig auf einen Port> bekommst.
Ich habe aber schon die Platine, wo das leider nicht so beschalten ist.
Jetzt habe ich die Init Routine wie auf dieser Website beschreiben ist
geschrieben, jetzt funktioniert sie besser...
http://elm-chan.org/docs/lcd/hd44780_e.html
Ich frage mich aber immer noch, was beim Shiften das Problem ist.
Hallo M. H.,
Weshalb das eine nicht funktioniert,
das andere mit Zwischenschritt aber dann schon,
und dann nur an dieser einen Stelle ein Problem,
das verwundert mich auch ein wenig.
Ggf. steht es im Zusammenhang dem Datentyp.
Also mit Vorzeichen (signed) oder ohne (unsigned char)
0b11111111 kann 255 sein, oder auch -1, je nach Datentyp!
Weiter lösen Compiler diverse 8 Bit Aufgaben
über einen 16 Bit Datentyp,
und vielleicht ist hier das Problem zu suchen.
Das von mir angedeutete Typ-Casting wäre damit der Compiler
Deine 8 Bit-Zahl nicht auf 16 bit aufbohrt,
bzw. dass er dies gewaltsam wieder auf 8 Bit kürzt.
(char)(0b 0001 0001 0011 0011)
liefert:
0b 0011 0011
Es schneidet ohne Warnung die 8 MSB einfach ab.
Man sollte das Casting nur vorsichtig einsetzen!
Es könnte aber des Rätsels lösung sein.
LCD_D6=(chr>>6)&0x01; --> LCD_D6 = ((char)(chr >> 6) & 0x01);
Daher hätte ich versucht irgendwie an die Werte zu kommen,
welche man wirklich am Port findet, und wenn es mit dem Voltmeter ist.
Aber gerade bei PIC sollte man mit ICP/ICD einfach debugen können,
was bei Atmel über die ISP nur mit moderner DebugWire geht
und ansonsten Jtag voraussetzt.
Also z.B. ein "while(1);" statt dem 1. "Enable" und mal messen,
Das LCD geht dann zwar natürlich nicht aber Du hast gewissheit,
was dort an den Pins wirklich los ist.
Danach dann das 2. Enable auf selbe Weise ersetzten und messen.
Wenn dort nach Deiner Methode 1 die falschen Bits ankommen
dann geht wirklich beim schieben was schief.
Die Tests sind natürlich mit verschiedenen Zeichen zu widerholen,
z.B. mit 0b1111 1111 und 0b0111 1111 und 0b1010 1010, 0b0101 0101
Ansonsten siehe auch:
Beitrag "Bitshift und Ansi C"http://www.imb-jena.de/~gmueller/kurse/c_c++/c_cast.html
MFG:Markus
Markus B. p. schrieb:> LCD_D6=(chr>>6)&0x01; --> LCD_D6 = ((char)(chr >> 6) & 0x01);
Das Funktioniert auch nicht.
Markus B. p. schrieb:> Die Tests sind natürlich mit verschiedenen Zeichen zu widerholen,> z.B. mit 0b1111 1111 und 0b0111 1111 und 0b1010 1010, 0b0101 0101
Mit diesem Code werden alle 4 Zeichen Richtig ausgegeben:
1
chr2=chr>>5;
2
LCD_D6=(chr2>>1)&0x01;
Den Datentyp in unsigned char zu ändern hat auch nichts gebracht.
Wenn ich das Enable mit einem while(1); ersetz messe ich an LCD_D6 den
falschen Pegel bei diesem Code:
Die Frage ist, ob shiften hier überhaupt sinnvoll ist. Dein µC shiftet
sich hier zu Tode. Zähl doch mal in deiner Funktion ab, wieviele Shifts
du in Summe machst!
1
...
2
LCD_D7=(chr&(1<<7))?1:0;
3
LCD_D6=(chr&(1<<6))?1:0;
4
...
das dürfte pro Bit um einiges effizienter sein.
Allerdings:
für das von dir beobachtete Verhalten hab ich auch keine Erklärung.
Hallo M. H.,
In meiner alten MPLAB 8.30 version habe ich umgestellt auf p18f45k20,
da ich Deinen nicht fand und das mit dem Simulator simuliert.
Ich habe mehrfach "Run to cursor" zu den beiden Enables gemacht,
und die SFR Ausgabe des Simulator beobachtet.
Leider kann ich Deine Probleme im Pic Simulator nicht nachvollziehen;
Alle 3 Bytes werden nach meiner Ansicht korrekt an den 4 Bit ausgegeben,
mit Deiner geposteten ur main.c,
nur an 3 Stellen zum compilieren geändert:
- Include gewechselt
- Config auskommentiert
- ANSELD=0x00 auskommentiert
MFG:MBP
Markus.
Karl Heinz Buchegger schrieb:> ...> LCD_D7 = ( chr & ( 1 << 7 ) ) ? 1 : 0;> LCD_D6 = ( chr & ( 1 << 6 ) ) ? 1 : 0;> ...
Do funktionier es super. Danke.
Das 1 << 7 könnte ich ja auch durch 0b10000000 ersetzen oder gibt es da
irgendeinen Verstecken unterschied?
M. H. schrieb:> Karl Heinz Buchegger schrieb:>> ...>> LCD_D7 = ( chr & ( 1 << 7 ) ) ? 1 : 0;>> LCD_D6 = ( chr & ( 1 << 6 ) ) ? 1 : 0;>> ...> Do funktionier es super. Danke.>> Das 1 << 7 könnte ich ja auch durch 0b10000000 ersetzen oder gibt es da> irgendeinen Verstecken unterschied?
Der Versteckte Unterschied ist die einfachere Lesbarkeit;
Übertrage das mal gedanklich auf 32 Bit...
Viel Spass beim Zählen der Nullen ;-)
MFG:MBP
M. H. schrieb:> Das 1 << 7 könnte ich ja auch durch 0b10000000 ersetzen
warum willst du das tun?
bei 1<<7 seh ich auf einen Blick, dass hier das 7. Bit gesetzt ist.
Warum? Na, weils dort steht! Das steht 7. Für jeden groß und deutlich zu
lesen.
Bei 0b10000000 muss ich 0-er zählen.
> oder gibt es da> irgendeinen Verstecken unterschied?
dadurch das 1<<7 vom Compiler ausgerechnet wird gibt es keinen
Unterschied. Sprich der Compiler ersetzt 1<<7 durch 0b10000000 und
erspart mir so das Bit zählen.
M. H. schrieb:> Das 1 << 7 könnte ich ja auch durch 0b10000000 ersetzen oder gibt es da> irgendeinen Verstecken unterschied?
Solange der Compiler das umsetzt, ist das doch zur Laufzeit völlig
gleichwertig.
M. H. schrieb:> Jetzt funktioniert alles und ich habe auch noch was gelernt (? 1 : 0;)> :-)
Du brauchst dringend ein C-Buch, wenn dich der ?: Operator schon in
Erstaunen versetzt. Da wartet noch jede Menge anderes Zeugs, welches in
jedem noch so grindigem C-Buch erläutert wird.
Jetzt sind noch 2 neue Probleme aufgetaucht:
Wenn ich txt[]="Hallo Welt" in der main definiere gibt es mir nur "Ha"
auf dem LCD aus, wenn ich txt hingegen als globale Variable definiere
gibt es mit den kompletten Text aus.
Wenn ich schreibe LCD_Text(3,1,"Hallo"); gibt es mir auch das Falsche
aus (ein Zeichen das aus 2 senkrechten Strichen besteht) und es kommt
die Warnung:
Warning [2054] suspicious pointer conversion