Forum: Mikrocontroller und Digitale Elektronik Busy Flag von LCD abfragen


von Toni (Gast)


Angehängte Dateien:

Lesenswert?

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

von Joerg X. (Gast)


Lesenswert?

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

von Toni (Gast)


Angehängte Dateien:

Lesenswert?

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

von A.K. (Gast)


Lesenswert?

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.

von Null (Gast)


Lesenswert?

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.

von Power (Gast)


Lesenswert?

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!

von Michael U. (Gast)


Lesenswert?

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



von Null (Gast)


Lesenswert?

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.

von Johannes M. (johnny-m)


Lesenswert?

> 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.

von Toni (Gast)


Angehängte Dateien:

Lesenswert?

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

von Null (Gast)


Lesenswert?

Den Display, ich nehme nun einen Characterdisplay an, und nicht einen 
graphischen, muss man natuerlich auf cursor-auto-nach-rechts schalten.

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

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.

...

von Michael U. (Gast)


Lesenswert?

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

von Toni (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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...

...

von holger (Gast)


Lesenswert?

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 !

von holger (Gast)


Lesenswert?

>push und pop temp2 weglassen !

Nee, besser doch nicht. temp2 ist ja keine
lokale Variable. Vergesst den Post :(

von Hannes L. (hannes)


Lesenswert?

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

...

von holger (Gast)


Lesenswert?

@ Hannes

Mein Zitat:
>Vergesst den Post :(

Hast recht. Ich verschwinde wieder in meine
schöne C-Welt ;)

von Toni (Gast)


Angehängte Dateien:

Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

> 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.

...

von André Jagusch (Gast)


Lesenswert?

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é

von 2918 (Gast)


Lesenswert?

Ja, den Port von output auf input umstellen, sonst kommt da nichts.

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
Noch kein Account? Hier anmelden.