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
Erster befehl: ldi temp1, 0<<PC3 Was ist 0, wenn man es um drei Stellen Verschiebt? . . . Immer noch 0.
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)
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 ?
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
Spess53 schrieb: > Um das Busy-Flag zu Lesen musst du auch mir E wackeln. Ich werde das mal gleich testen. Vielen Dank soweit
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 ?
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
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
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?
Hi ' brne wrcmd10' springt zur erneuten Abfrage des Busyflags (Anfang des Codebeispiels). MfG Spess
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?
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
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.
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.
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.
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!
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?
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.
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--; }
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.