Forum: Mikrocontroller und Digitale Elektronik LCD an ATmega 8 Routine, die das Busy Flag abfragt, läuft nicht!


von Olli R. (downunderthunder42)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe hier den ATmega8 und habe die Subroutinen, die für die 
Ansteuerung des LCD (siehe AVR Tutorial) größtenteils neu 
geschrieben/umgeschrieben, so dass nicht mehr überall "delays" 
zwischengepackt werden müssen, sondern stattdessen das Busy Flag 
abgefragt wird.

Leider funktioniert das ganze nicht.

Der Code wird zwar fehlerfrei assembliert aber es tut sich nichts am 
LCD.

wenn ich die lcdroutines.asm, wie sie im AVR-Tutorial zu finden ist, 
verwende läuft alles, allerdings muss ich dann natürlich den PIN_R/W auf 
GND legen.

somit muss irgendwo ein Logikfehler in meiner geänderten lcdroutines.asm 
sein. (Genauer wohl in der Subroutine "lcd_busy".

Ich habe mal beide Programme angefügt:
LCD.rar enthält eine einfache String-Ausgabe mit der lcdroutines.asm aus 
dem Tutorial (ohne Abfrage des Busy-Flag)

LCD_RW1.rar enthält die Stringausgabe mit meiner umgeschriebenen 
lcdroutines.asm (läuft so leider nicht)

Ich betreibe das LCD an PORTC, und die Umschaltung zwischen 
LCD-lesen/schreiben (PIN_RW) liegt auf PD0 an PORTD

von Edding (Gast)


Lesenswert?

Erster befehl:

ldi   temp1, 0<<PC3

Was ist 0, wenn man es um drei Stellen Verschiebt?
.
.
.
Immer noch 0.

von Edding (Gast)


Lesenswert?

und:
das Busy-Bit kannst du erst NACH einem (ganzen!) Befehl abfragen. 
Zwischen den beiden 4Bit-Nibbels geht das nicht.
Und erst recht nicht geht das während der E-Puls gerade läuft. (Der 
E-Puls muss eh nur sehr sehr kurz sein, da waren die NOPs schon richtig)

von Olli R. (downunderthunder42)


Lesenswert?

Edding schrieb:
> ldi   temp1, 0<<PC3
>
> Was ist 0, wenn man es um drei Stellen Verschiebt?

OK schreibt man dann besser:

cbi LCD_DDR, PC3


und zum Schluss wieder

sbi LCD_DDR,PC3

?

von Spess53 (Gast)


Lesenswert?

Hi

Um das Busy-Flag zu Lesen musst du auch mir E wackeln.
1
....
2
wrcmd10:              nop
3
                      sbi lcctl,lc_e             ; Enable high
4
                      nop
5
                      in r16,lcpin               ; Busy Flag
6
                      nop
7
                      cbi lcctl,lc_e             ; Enable low
8
                      nop
9
                      sbi lcctl,lc_e             ; Enable high
10
                      nop
11
                      in r17,lcpin               ; unteres Nibble
12
                      nop 
13
                      cbi lcctl,lc_e             ; Enable low
14
15
                      swap r16
16
                      andi r16,0b10000000        ; Busy 0 ?
17
                      brne wrcmd10
18
....

MfG Spess

von Olli R. (downunderthunder42)


Lesenswert?

Spess53 schrieb:
> Um das Busy-Flag zu Lesen musst du auch mir E wackeln.

Ich werde das mal gleich testen.
Vielen Dank soweit

von Olli R. (downunderthunder42)


Lesenswert?

Spess53 schrieb:
> ....
> wrcmd10:              nop
>                       sbi lcctl,lc_e             ; Enable high
>                       nop
>                       in r16,lcpin               ; Busy Flag
>                       nop
>                       cbi lcctl,lc_e             ; Enable low
>                       nop
>                       sbi lcctl,lc_e             ; Enable high
>                       nop
>                       in r17,lcpin               ; unteres Nibble
>                       nop
>                       cbi lcctl,lc_e             ; Enable low
>
>                       swap r16
>                       andi r16,0b10000000        ; Busy 0 ?
>                       brne wrcmd10
> ....

ach müsste es nicht heissen:
breq wrcmd10 ; schließlich will aus dieser Subroutine, wenn das BusyFlag 
nicht mehr gesetzt ist . LCD Busy --> Busy Flag =1
LCD_ nicht Busy --> Busy Flag = 0  ?

von Peter D. (peda)


Lesenswert?

Man gewinnt durch die Busy-Abfrage aber rein garnichts.

Ein Mensch soll das LCD ja auch ablesen können. Daher macht man 
LCD-Ausgaben mit Absicht viel langsamer, als sie (auch mit Waits) 
benötigen.
Die CPU-Last beträgt <1%, somit ist eine Optimierung nur unnötige 
Arbeit.


Peter

von Spess53 (Gast)


Lesenswert?

Hi

>ach müsste es nicht heissen:...

Nein. Wenn Busy 1 ist, dann ist das LCD noch beschäftigt.

>Man gewinnt durch die Busy-Abfrage aber rein garnichts.

Bitte keine Glaubenskriege.

>Ein Mensch soll das LCD ja auch ablesen können. Daher macht man
>LCD-Ausgaben mit Absicht viel langsamer, als sie (auch mit Waits)
>benötigen.

Darum geht es doch gar nicht.

MfG Spess

von Olli R. (downunderthunder42)


Lesenswert?

Spess53 schrieb:
>>ach müsste es nicht heissen:...
>
> Nein. Wenn Busy 1 ist, dann ist das LCD noch beschäftigt.

das meine ich ja.

andi r16,0b10000000        ; Busy 0 ?
brne wrcmd10

wenn r16 jetzt den Wert 0b10000000 hat, dann ist das Busy Flag ja 
gesetzt.
Die Abfrage darunter sorgt nun dafür, dass die subroutine 2wrcmd10" 
verlassen wird.
Das möchte ich aber erst, wenn das Busy Flag nicht mehr gesetzt ist.
Also breq statt brne?

von Spess53 (Gast)


Lesenswert?

Hi

' brne wrcmd10' springt zur erneuten Abfrage des Busyflags (Anfang des 
Codebeispiels).

MfG Spess

von Olli R. (downunderthunder42)


Angehängte Dateien:

Lesenswert?

ok ich habe jetzt die hier gemachten Verbesserungsvorschläge in die 
Routine eingebracht.
ich habe di Subroutine lcd_busy nach Spess53s Vorschlag geändert.

Die lcd_busy routine rufe ich nun am Ende der lcd_data, am Ende der 
lcd_command und immer nachdem ich die lcd_enable in anderen subroutine 
aufgerufen habe?!

Irgendwie ist da noch der Wurm drin?

von Purzel H. (hacky)


Lesenswert?

Spar dir das Busy und verwende einen Timer. Es gibt etwa 2 Befehle, die 
laenger als sofort gehen, und die erschlaegt man mit dem timer

von Attila (Gast)


Lesenswert?

Bin ziemlicher Anfänger und werde daher hier nur einen kleinen aber 
vielleicht hilfreichen Hinweis geben: Das busy flag kann zwischen den 
beiden nibbles abgefragt werden. Sonst wäre ja, zumindest in meinen 
Augen, die ganze busy flag Abfrage Implementation auch irgendwie 
sinnlos.

von Edding (Gast)


Lesenswert?

Olli R. schrieb:
> und immer nachdem ich die lcd_enable in anderen subroutine
> aufgerufen habe?!

warum das denn?
lcd_enable ist der schnellste teil an der ganzen Geschichte.

dein wait für das busy_flag dauert um Größenordnungen länger.

Abgesehen davon, dass es an der Stelle sowieso falsch ist, und das LCD 
aus dem Takt bringt.

von Edding (Gast)


Lesenswert?

Attila schrieb:
> Das busy flag kann zwischen den
> beiden nibbles abgefragt werden.

Nein.
Um zwischen den beiden Nibbels "umzuschalten", musst du mit E wackeln.
Um Busy auszulesen musst du mit E wackeln. sogar zweimal, da du das 
ganze status-Byte auslesen musst.

von Attila (Gast)


Lesenswert?

Das mit dem Enable stimmt natürlich. Hier meine Version vielleicht hilft 
es ja:

busy:  ldi   temp, 0b00001110  ;Datenleitungen 4-7 als Eingang
  out  DDRD,temp
  cbi  PORTD,3            ;RS=0
  sbi  PORTD,2            ;R/W=1
flag:  sbi  PORTD,1            ;E=1
  nop
  nop
  nop
  in  temp,PIND          ;Oberes nibble einlesen
  cbi  PORTD,1            ;E=0
  rcall  enable            ;E=1"triggert" das untere nibble"
  sbrc  temp,7      ;temp enthält oberes nibble
  rjmp  flag      ;
  cbi  PORTD,2            ;R/W=0
  sbi  PORTD,3            ;RS=1
  ldi  temp, 0b11111110        ;Alle Datenleitungen von PORTD als 
Ausgang
  out    DDRD,temp
  ret

Mir hat es damals "das Genick" gebrochen dass ich nicht daran gedacht 
habe den Port als Ausgang und später als Eingang zu konfigurieren. Wie 
gesagt: Vielleicht hilft es ja!

von Olli R. (downunderthunder42)


Angehängte Dateien:

Lesenswert?

Ok ich glaube ich spar mir das wirklich mit dem Busy.

Zumal das Aufrufen eine Busy-Funktion ja auch ne Menge Befehle 
"verbraucht".

meine jetzige Routine gib leider nur einen Cursor an der Position 2 aus.
Ich habe das mit dem Busy gelöscht und stattdessen delay eingefügt, wie 
ursprünglich auch schon.

In einer weiteren Funktion muss wohl noch ein Fehler sein?

ich habe es mit der ursprünglichen lcdroutines.asm verglichen und konnte 
den Fehler dennoch nicht entdecken?

Heia Jetzt-aber schrieb:
> Spar dir das Busy und verwende einen Timer. Es gibt etwa 2 Befehle, die
> laenger als sofort gehen, und die erschlaegt man mit dem timer

Wie würde man das denn mit nem Timer machen. Ich kenn das jetzt nur mit 
diesen delays?

von Olli R. (downunderthunder42)


Angehängte Dateien:

Lesenswert?

Ok zumindest läuft das Programm mit den delays wieder.

Es ist zwar im Wesentlichen das aus dem Tutorial aber egal.
Ich hab zumindest beim Schreiben ne Menge gelernt.

von Purzel H. (hacky)


Lesenswert?

Man hat ja in der Regel eh einen Systemtimer. Mein bevorzugter Timer ist 
jeweils 10ms. Da kann man irgendwas in der Richtung :

bool    DisplayTimerEnable;
byte    DisplayTimer;


interrupt Timer
..
 if DisplayTimerEnable {
  if (DisplayTimer !=0) DisplayTimer--;
 }

von Spess53 (Gast)


Lesenswert?

Hi

>Man hat ja in der Regel eh einen Systemtimer. Mein bevorzugter Timer ist
>jeweils 10ms. Da kann man irgendwas in der Richtung :

>bool    DisplayTimerEnable;
>byte    DisplayTimer;


>interrupt Timer
..
> if DisplayTimerEnable {
>  if (DisplayTimer !=0) DisplayTimer--;
> }

So, und das Ganze jetzt noch mal in Assembler.

MfG Spess

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.