Hallo zusammen, ich versuche irgendwie das Busy flag einer LCD anzeige abzufragen. Dazu habe ich die lcd funktionen aus dem Tutorial hier erweiert. Nur leider wills noch nicht richtig funktionierne. Der Source ist im Anhang. Folgendes ist mir aufgefallen. Wenn ich statt lcd_wait_busy, delay5ms aufrufe in der "funktion" lcd_data funktioniert alles einwandfrei. Sobald ich nun delay5ms durch lcd_wait_busy ersetzte wird nur noch der erste Buchstabe ausgegeben. Eine Endlosschleife scheint es aber nicht zu geben, da die LEDs an PortB Leuchten. Also dachte ich mir, wird wohl die busy schleife nicht richtig funktionieren und ist zu kurz ... Daher habe ich in lcd_wait_busy delay5ms aufgerufen. Die Zeit müsste also reichen, da es bei direktem delay5ms ja auch funktioniert hat. Aber von wegen ... die Leds an PortB leuchten wieder, es wird aber trotzdem nur der erste Buchstaben angezeigt. Ich steh nun völlig auf em Schlauch. Das einzige was ich mir erklären kann, das die busy funktion irgend einen müll ausgibt :/ kann aber keinen fehler finden. (Wobei ist das enable in busy nötig? Macht aber in hinblick auf meinen Fehler keinen unterschied :() Hat hierzu jemand eine Idee? Toni
Ja, das Enable ist (immer!) nötig, die Daten die das Display ausgibt (genauer: der LCD-controller) werden nur auf einer der Enable-Flanken aktualisiert (welche: steht im Datasheet), d.h. kein enable->keine Änderung des Busy-flags. Warum? weil das ein Bus ist, sobald da mehrere Geräte dranhängen ist es relativ ungünstig wenn ein gerät einfachso (ungefragt!) die Pegel ändert
danke für die schnelle Antwort. Jetzt hab ich wenigstens schonmal das begriffen ;-). Ich setzte nun den enabled pin in der warteschleife immer kurz auf high und prüfe danach wieder den busy pin. Source ist im Anhang. Jetzt müsste doch diese schleife stimmen oder? Trotzdem wird nur ein A angezeigt. Die Leds an PortB leuchten trotzdem. Was geht jetzt noch schief? Toni
Wenn das Busy-Flag gelesen wird, ist nicht nur dieses eine Bit des Display ein Ausgang, sondern alle. Also nicht nur Bit 3 wird Eingang. Ebenso ist dieser Lesezyklus ein vollständiger 8bit-Zugriff mit 2 4bit-Hälften, grad so wie die Schreibzyklen.
Den Busy pin abzufragen ist eine schlechte Idee, die selten gemacht wird. Diesen Pin kann man sich sparen, wenn man fuer die 2-3 Befehle, bei denen Busy etwas bringt mit einem Timer macht.
Der Busy-Pin macht dann Sinn wenn die Displayausgabe, unabhängig von der Taktfrequenz des µC, die maximale Geschwindigkeit haben und keine Zeichen 'verschlucken' soll. Bei verwendung von Pausenzeiten mus u.U. bei jedem neuen Displaytyp (neue Charge) oder anderem µC die Software angepasst werden. Bei Hobbybastlern kein Thema, in der Massenproduktion ein tödlicher Kostenfaktor. Der Busy-Pin (das Busy-Flag) macht also durchaus Sinn!
Hallo, 2 Sachen, die mir auf die Schnelle auffallen:
1 | lcd_change_port: |
2 | push temp2 |
3 | in temp2, LCD_PORT |
4 | andi temp2, (0<<PIN_RS) | (0<<PIN_RW) | (0<<PIN_E) | 0xF0 ;Alle verwendeten Bits auf null setzten |
5 | or temp2, temp1 ;Daten in temp1 übernehmen |
6 | out LCD_PORT, temp2 ;Ausgabe an Port |
7 | pop temp2 |
8 | ret |
andi temp2,balbla ist unsinnig, Du kannst eine 0 solange schieben wie Du willst, das bleibt eine 0, es ist letztlich also andi temp2,0xF0 und das löscht Bit 0...3 ist das so beabsichtigt? in temp2,LCD_PORT andi temp2,0xF0 ; Datenbist auf 0 or temp2,temp1 out LCD_PORT,temp2 macht das gleiche. Busy-Flag: daß alle Datenbist auf Eingang müssen, damit es keine Busprügelei gibt, wurde schon gesagt, daß der Lesezugriff im 4Bit-Mode aus 2 Zyklen wie der Schreibzugriff besteht, auch. Außerdem: E muß H sein, um die Daten zu lesen, wenn E L ist, geht das Display wieder in TriState... Also sbi LCD_PORT,PIN_E ; E auf H nop ; warten E geht erst im nächsten AVR-Clock auf H und das Display braucht auch einen Moment... nop in temp_1,LCD_PORT ; Bit 7...4 einlesen cbi LCD_PORT,PIN_E ; E hier wieder auf L sbi LCD_PORT,PIN_E ; E auf H nop ; warten E geht erst im nächsten AVR-Clock auf H und das Display braucht auch einen Moment... nop in temp_2,LCD_PORT ; Bit 3...0 einlesen cbi LCD_PORT,PIN_E ; E hier wieder auf L Liest Du nicht beides ein und benutzt einen Loop, bis Busy ok ist, bekommst Du in jeder 2. Runde die Bits 3...0 zurück. Gruß aus Berlin Michael
Man kann sich taeuschen mit dem Busy pin. Bei hohen Stueckzahlen nimmt man gerne den kleinst moeglichen Controller, im kleinst moeglichen Gehaeuse. Dann spart man sich natuerlich den Busy pin. Zumal der Display als User interface nicht schneller als der Benutzer sein muss. Das heisst, bevor ich den Display polle mach ich der ADC etwas anderes prozessrelevantes schneller.
> Dann spart man sich natuerlich den Busy pin.
Das ist bei HD44780-Controllern kein extra Pin, sondern lediglich ein
Bit im ausgelesenen Datenwort und demzufolge ergibt das direkt keine
Einsparung an Pins. Was man sich bei einem Verzicht auf die Busy-Abfrage
allerdings meist sparen kann ist der Read/Write-Pin, da man bei 99%
aller Anwendungen eh nur schreibt und nicht vom Display liest.
Vielen Dank für die Antworten. Habe nun versucht alle Tips ins Programm umzusetzten. Außer die Sache hier ;-) andi temp2, (0<<PIN_RS) | (0<<PIN_RW) | (0<<PIN_E) | 0xF0 Klingt logisch dass das Sinnlos ist ;-). Muss ich mir nochmal anschauen. Aber im wesentlichen machts das was ich will. Zumindest das was ich mir im Simulator angeschaut habe. Alle anderen sachen habe ich nun im Anhang drin. Um es gleich vorweg zu nehmen. Das Display zeigt immer noch nur den ersten Buchstaben ein. Ich habe nun in lcd_wait_busy die beiden 4 bit nibbles eingelesen und im register temp2 zusammen gefügt. So müsste das doch passen oder? Dabei habe ich darauf geachtet, dass enable währen dem lesen auf high ist. (So im nachhinein auch logisch G). Auch das DDRD müsste nun stimmen. Sieht noch jemand ein paar Fehler? g Soviele könnens ja nicht mehr sein. Vielen Dank schonmal. Toni
Den Display, ich nehme nun einen Characterdisplay an, und nicht einen graphischen, muss man natuerlich auf cursor-auto-nach-rechts schalten.
Ich bin inzwischen wieder von der Busy-Abfrage weg. Stattdessen verwende ich etwas "Bildschirmspeicher" im SRAM des AVRs, in den die Routine "LCD_DATA" die Zeichen reinlegt. Das geht sehr schnell, da keinerlei Warterei nötig ist. Der Bildschirmspeicher ist linear organisiert, kann also mit "Fließtext" beschrieben werden, der auch Zeilenumbrüche (13) enthalten kann. In der Mainloop wird dann (durch einen Timer synchronisiert) alle 1ms..2ms der Job "LCD_UPDATE" aufgerufen, der das nächste Zeichen an das LCD schickt und dabei die verschachtelten Ausgabepositionen entwirrt. Somit wird eine Wartezeit von 1..2ms eingehalten, ohne dass das Programm irgendwo in einer Warteschleife hängt und Rechenzeit verschwendet. Natürlich bekommt dieser Job keinen exclusiv-Interrupt, die Synchronisation übernimmt ein sowiso laufender Timer-Interrupt ganz nebenbei. Angenehmer Nebeneffekt: Nimmt man das LCD zum Debuggen, so bremst es das Programm nicht (nennenswert) aus. Man darf sogar schneller in den Bildschirmspeicher schreiben, als das Update zum LCD erfolgt, ohne dass es irgendwo einen Stau gibt (das ist bei einem herkömmlichen Ringbuffer nicht ungestraft möglich). Die Routinen im Anhang sind für das WINTEK-LCD von Pollin (4 x 27 Zeichen) mit zwei Controllern ausgelegt. Der Einsatz erfolgt derzeit auf Mega8 und Mega48. Eine Version für LCD 2 x 24 Zeichen läuft auch auf dem Tiny2313, eine Version für LCD 8 x 24 Zeichen (Controller MS50530) ist auf einem Mega8535 im Einsatz. ...
Hallo, ich habe mir Deine Source hier jetzt nicht komplett angeschaut, ganz allgemein: Das Display wird nur durch den E-Takt gesteuert, solange E auf L ist, kann mit den anderen Leitungen passieren, was will. RW, RS und die Daten können bei Ausgabe also schon vor der L/H-Flanke gesetzt werden und müssen dann bin nach der H/L-Flanke stabil bleiben. Solange der nächste Zyklus das gleiche macht, müssen nur die nächsten Daten ran und wieder E-Clock. Beim Lesen genauso, nur daß während E auf H ist, gelesen werden muß. Die jeweiligen Zeiten aus dem Datzenblatt des Display-Controllers beachten, im Zweifel erstmal ein paar NOP überall dazwischen, zu langsam stört nicht. Steht beim Lesen RS richtig? Ansonsten kann RS und RW während der ganzen Lesegeschichte stehen bleiben, nur E taktet. Gruß aus Berlin Michael
Guten Abend zusammen. Ich habe den Fehler nun glaube ich gefunden. Hab aber keine Ahnung wie ich ihn lösen soll. Das Problem tritt in lcd_change_port auf. Wenn dort das erste mal das RW bit gesetzt wurde, steht es beim zweiten aufruf immer noch da. Folge ist, dass die nachfolgenden Zeichen nach dme A mit gesetzem RW bit gesendet wird :(. Die ganze lcd_change_port gechichte mach ich eignetlich nur aus dem Grund, dass ich die lcd funktionen flexibel halten kann. Oben wird definiert welcher PIN welche funktion hat. Nicht verwendete pins des Port (bei mir pin 7) sollen aber nicht vom den lcd funktionen beeinflusst werden. Daher habe ich versucht mit andi temp2, (0<<PIN_RS) | (0<<PIN_RW) | (0<<PIN_E) | 0xF0 Alle pins die verwendet werden auf 0 zu setzten, um nachher mit ori die neuen werte anzulegen. Nur funktioneirt die Sache leider nicht mit dem "auf 0 setzten" :(. Gäbe es eine andere Möglichkeit die Pins zu ändern, sodass der nicht verwendete PIN, nicht von der neuen ausgabe beeinflusst wrid. Das einzige was mir eingefallen ist: cbr LCD_PORT, PIN_RS cbr LCD_PORT, PIN_RW ... aber das geht doch bestimmt schöner oder? Thx hannes für deinen Source :). Die Technik klingt interessant :). Trotz allem ;-) will ich das ncoh hinbekommen mit dem busy flag ;-9 Schönen Abend noch. Toni
CBR ist schon richtig, aber CBR erfordert nicht die Bitnummern, sondern die Bitmaske. cbr temp2, (1<<PIN_RS) | (1<<PIN_RW) | (1<<PIN_E) löscht also in temp2 die angegebenen Bits (in einem Rutsch). Danach können mit ORI oder SBR die entsprechenden Bits gesetzt werden oder mit OR die Bits eines anderen Registers dazugeholt werden. Eine ältere Version des LCD-Treibers mit Busywait findest Du hier: Beitrag "Re: Hilfe! LCD-Ansteuerung" Da sollte allerdings die Zählschleife für den Notausstieg deaktiviert werden, die war bei schnellem Takt etwas zu kurz. Das war auch einer der Gründe, auf virtuelles LCD (Bildschirmspeicher im AVR-SRAM) umzustellen. Übrigens: Ich finde es gut, dass Du versuchst, bis ins Detail vorzudringen. Das machen heutzutage nicht mehr viele... ...
Ich bin ja nur ein schnöder C Programmierer, aber ich würde das so machen: lcd_change_port: in temp2, LCD_PIN andi temp2, (0<<PIN_RS) | (0<<PIN_RW) | (0<<PIN_E) | 0xF0 ;Alle verwendeten Bits auf null setzten or temp2, temp1 ;Daten in temp1 übernehmen out LCD_PORT, temp2 ;Ausgabe an Port ret push und pop temp2 weglassen !
>push und pop temp2 weglassen !
Nee, besser doch nicht. temp2 ist ja keine
lokale Variable. Vergesst den Post :(
Hmmm..... > lcd_change_port: > in temp2, LCD_PIN Warum LCD_PIN? Man will ja nicht von außen anliegende Ereignisse einlesen, sondern den aktuellen Ausgangszustand des Ports, also: in temp2,LCD_PORT > andi temp2, (0<<PIN_RS) | (0<<PIN_RW) | (0<<PIN_E) | 0xF0 ;Alle > verwendeten Bits auf null setzten Da kann man auch gleich schreiben: andi temp2,0xF0, denn nach links geschobene Nullen löschen keine Bits. Bits lassen sich in ASM sehr einfach mit cbr temp2,bitmaske löschen. > or temp2, temp1 ;Daten in temp1 übernehmen > out LCD_PORT, temp2 ;Ausgabe an Port ...
@ Hannes
Mein Zitat:
>Vergesst den Post :(
Hast recht. Ich verschwinde wieder in meine
schöne C-Welt ;)
So :) jetzt funktionierts endlich :). Die sache bei change_port war ausschalggebend :). Jetzt muss ich nur mal den ganzen source entrümpeln :(. Sieht furchtbar aus mitterlweile. Wo hast du das mit LCD_PIN gefunden? Habe das nur noch beim busy lesen. Hast du den aller ersten source angeschaut? Die andi sache ist mir nun klar g Mit cbr funktionierts nun einwandfrei :). Eine Frage hätte ich noch: In lcd Data beim setzten des RC pins hab ich auch müll gemacht: andi temp1, (1<<PIN_RS) | 0b00001111 Logisch dass RS nie high wird. Bzw nur durch eine Zufall wenn temp1 zufällig an der stelle auch ne 1 hat. Habe das nun durch: andi temp1, 0b00001111 sbr temp1, (1<<PIN_RS) ersetzt. Lässt sich das irgendwie zusammenfassen? Eher weniger oder? Toni
ODER Bit setzen XOR Bit toggeln UND Bit löschen, Bit zur Abfrage ausmaskieren Bit setzen ori r16, 0b10101111 alle 1 Bits werden in r16 geseztt Bit löschen andi r16, 0b10101111 alle 0 bits werden in r16 gelöscht
> UND Bit löschen, Bit zur Abfrage ausmaskieren Dabei muss man aber die Bits angeben, die NICHT gelöscht werden sollen. Und damit das einfacher aussieht, unterstützt der AVR-Assembler auch die Befehle SBR (entspricht ORI) und CBR (entspricht ANDI mit dem invertierten Wert). Also SBR (Set Bits in Register) setzt die angegebenen Bits, CBR (Clear Bits in Register) löscht die angegebenen Bits. Die Bits können dabei wie bei LDI oder ORI angegeben werden, also auch durch nach links geshiftete Einsen. ...
Hallo, ich habe mal eine wahrscheinlich blöde Frage zu dem Thema busy flag lesen. Ich versuche das auch gerade, da das Timing als schwierig gestaltet und ich generell denke das es so besser wäre. Ob sichs lohnt ist eine ander Frage, ist ja Hobby :-). Also wenn ich das busy flag lesen muss dann passiert das auf der selben "Leitung" mit der ich auch die schreibenden Zugriffe mache. Müsste ich da nicht erst den port von output auf input umstellen? Noch eine Frage zu Displays, ich habe ein 4x16 und kann mittlerweile alle Felder ansteuern, aber wenn ich in jedes Feld ein Zeichen setze fangen manche pixel an zu flackern oder verschwinden ganz. Ist das Display defekt oder gibt es einen anderen Grund dafür? Viele Grüsse, André
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.