Forum: Mikrocontroller und Digitale Elektronik Tutorial LCD initialisieren


von Fabian R. (flo_rida)


Lesenswert?

Hallo,

bin gerade dabei mir die LCD Ansteuerung mithilfe des Tutorials 
beizubringen. Leider Funktioniert es nicht wie gewünscht. Ich habe 
erstmal nur den Code von 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD#Routinen_zur_LCD-Ansteuerung_im_4-Bit-Modus 
und weiter unten das: 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD#Anwendung 
kopiert. Ich verwende einen atmega8a und habe .include "m8def.inc" in 
.include "m8adef.inc" geändert. Da ich des weiteren alles in eine Datei 
gepackt habe entfällt bei mir das allerletzte .include 
"lcd-routines.asm". Nun habe ich mir das Datenblatt meines Displays zur 
Hand genommen http://www.lcd-module.de/pdf/doma/2_16.pdf und auf Seite 4 
unter Hinweis folgenden Satz gelesen: "Im 4-Bit Mode ist die 
Busy-Abfrage vor jedem Bytezugriff notwendig." Sooo nun erstmal die 
Frage: hat hier schonmal jemand das Display ohne Busy-Flag Abfrage zum 
laufen bekommen? Im mitgelieferten Datenblatt ist dieser Satz nämlich 
nicht zu finden.

Grüße
Flo Rida


edit: Meine das DIP162-DNLED, sorry

: Bearbeitet durch User
von Rainer U. (r-u)


Lesenswert?

Ich denke, dass kaum einer das Busy-Flag liest: dazu müsste man schonmal 
die R/W-Leitung umschalten zum Lesen, und die liegt bei den allermeisten 
Beispielen (auch im Tutorial) permanent auf GND.

Bei einem LCD kann viel schiefgehen: Leitungen vertauscht oder 
vergessen, Kontrast nicht richtig eingestellt...

Ich empfehle Dir, das Tutorial zunächst 1:1 umzusetzen (so ein Mega8 
kostet ja nicht viel), dann Dein Programm anzupassen und dann den Chip 
zu ändern.


Oder wenn Du es bequem haben willst: Mit Bascom ist die LCD-Ansteuerung 
mit 2 Zeilen erledigt.. :-)

von Teo D. (teoderix)


Lesenswert?

Fabian Rauer schrieb:
> "Im 4-Bit Mode ist die
> Busy-Abfrage vor jedem Bytezugriff notwendig."

Wenn das im Dabla steht(und das tut es definitiv) wird das sicher 
notwendig sein!

von picasm (Gast)


Angehängte Dateien:

Lesenswert?

Rainer Unsinn schrieb:
> Ich denke, dass kaum einer das Busy-Flag liest: dazu müsste man schonmal
> die R/W-Leitung umschalten zum Lesen, und die liegt bei den allermeisten
> Beispielen (auch im Tutorial) permanent auf GND.

Wenn man sich nicht an die Tutorials hält und einfach alles selbst 
macht, dann kommt es auf die paar Zeilen auch nicht mehr an:

von Klaus (Gast)


Lesenswert?

Aus deinem Datenblatt!

Hier ist auch der ganze Port gemeint im 8 bit Modus

>HINWEIS
>Die in der
>Tabelle angegebenen
>Ausführungszeiten gelten nur bei
>Abfrage des Busy Flags; d.h. vor
>jedem Schreib- und Lesezugriff
>muß das Busy Flag BF auf 0
>abgefragt werden.

Du kannst auch ohne Busy abfrage machen aber die
Zeiten sind eben länger.

>Wird das Busy
>Flag nicht abgefragt, so sind die
>Ausführungszeiten zum Teil
>wesentlich länger als angegeben.

Die Busy abfrage kann im 4 Bit modus wegelassen werden
aber die Delays müssen wie oben entsprechend angepasst werden.

>Im 4-Bit Mode ist die Busy-Abfrage
>vor jedem Bytezugriff notwendig

Im 4 Bit Modus sendest du ein Byte in dem du, das obere und untere 
halbyte
sendest und dabei jedesmal die Busy-Abfrage durchführst.

von Karl H. (kbuchegg)


Lesenswert?

Teo Derix schrieb:
> Fabian Rauer schrieb:
>> "Im 4-Bit Mode ist die
>> Busy-Abfrage vor jedem Bytezugriff notwendig."
>
> Wenn das im Dabla steht(und das tut es definitiv) wird das sicher
> notwendig sein!

Das bezieht sich nur darauf, dass im 4 Bit Modus vor jeder Übertragung 
eines Bytes das Busy Flag abzufragen ist, wenn man überhaupt das Busy 
Flag verwendet.
Man könnte ja auch der Meinung sein, man müsse für jedes Nibble das Busy 
Flag befragen.

Die erste Frage lautet also:
Will ich grundsätzlich das Busy Flag abfragen oder warte ich einfach im 
Code eine gewisse Zeit ab.
Nur dann, wenn die Antwort darauf lautet "Jep, ich will Busy Flag 
abfragen", dann wird der Satz relevant als Antwort auf die Frage: Wie 
oft muss ich es dann abfragen, wenn ich doch für jedes Daten-Byte 2 
Übertragungen benötige.

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Da ham se sich aber SEHR ungeschickt ausgedrückt! Für merkwürdig hab 
ich das allerdings schon gehalten.

von Fabian Rauer (Gast)


Lesenswert?

Äh ok. Vielen Dank für eure Meinungen dazu.
 Also Code passt 100%ig zum LCD? Dann wohl ein Verdrahtungsfehler.

Grüße
Fabian Rauer

von Fabian R. (flo_rida)


Lesenswert?

Jetzt muss ich mich leider doch nochmal zurückmelden. Ich habe den 
folgenden Code irgendwo im Internet gefunden, ich weiß leider nicht mehr 
wo:
1
.include "m8adef.inc"
2
3
.def temp   = r16
4
.def temp1  = r17
5
6
main:
7
             ldi      temp, HIGH(RAMEND)  ;Stackpointer initialisieren
8
             out     SPH, temp
9
             ldi     temp, LOW(RAMEND)  
10
             out     SPL, temp
11
12
      ldi    temp,0xFF      ;Port D auf Ausgang
13
      out    DDRD,temp
14
15
      
16
init:    ;ldi  temp, 0b00110000  ;3 mal laut Tutorial senden
17
      ;out  PORTD,temp      ;(diesen Teil versuchsweise weggelassen)
18
      ;rcall  enable
19
      ;rcall  zeit
20
      ;rcall  enable
21
      ;rcall  zeit
22
      ;rcall  enable
23
      ;rcall  zeit
24
25
      ldi    temp, 0b00100000  ;oberes nibble function set setzt:
26
      out    PORTD,temp      ;4 bit modus 
27
      rcall  enable
28
      rcall  zeit
29
      rcall  zeit
30
      rcall  zeit
31
      ldi    temp, 0b11000000  ;unteres nibble function set setzt:
32
      out    PORTD,temp      ;zweizeiliges Display und 5*10 dit Display
33
      rcall  enable
34
      rcall  zeit
35
36
      ldi    temp, 0b00000000  ;oberes nibble Display on/off control
37
      out    PORTD,temp
38
      rcall  enable
39
      rcall  zeit
40
      ldi    temp, 0b11110000  ;unteres nibble Display on/off control setzt:
41
      out    PORTD,temp      ;Display ein,Cursor ein,Cursor blinkt
42
      rcall  enable
43
      rcall  zeit
44
45
      ldi    temp, 0b00000000  ;oberes nibble clear display
46
      out    PORTD,temp
47
      rcall  enable
48
      rcall  zeit
49
      ldi    temp, 0b00010000  ;unteres nibble clear display setzt:
50
      out    PORTD,temp      ;Clear display, return cursor to home
51
      rcall  enable 
52
      rcall  zeit
53
54
      ldi    temp, 0b00000000  ;oberes nibble entry mode set
55
      out    PORTD,temp
56
      rcall  enable
57
      rcall  zeit
58
      ldi    temp, 0b01100000  ;unteres nibble entry mode set setzt:
59
      out    PORTD,temp      ;DD-RAM Adresse inkrementieren
60
      rcall  enable
61
      rcall  zeit
62
63
      sbi    PORTD,3        ;RS=1
64
65
w:  rjmp  w
66
    
67
68
enable:    
69
      sbi    PORTD,1        ;E=1
70
      nop
71
      nop
72
      nop
73
      cbi    PORTD,1        ;E=0
74
      ret
75
76
zeit:    ldi  temp,0xFF        ;eine 80ms Warteschleife
77
WGLOOP0:     ldi  temp1,0xFF
78
WGLOOP1:     dec  temp1
79
            brne WGLOOP1
80
             dec  temp
81
             brne WGLOOP0
82
             ret

natürlich will ich nicht dass ihr das durchschaut. Aber was auffällig 
ist, dass das untere Nibble immer 0 ist. Nun ist meine Frage wie kann es 
sein, dass auf meinem Display was erscheint wo ich doch nach der 
Anleitung im Tutorial gegangen bin? Diese Anleitung sieht nämlich nur 
eine Anbindung an der Datenbits 4-7 des Displays an die Portpins 0-3 
vor?

Viele Grüße
Fabian Rauer

von c-hater (Gast)


Lesenswert?

Fabian Rauer schrieb:

> natürlich will ich nicht dass ihr das durchschaut.

Das ist dir gründlich misslungen. Ich versteh' das. Mehr noch: es hat 
mich auch nur zweieinhalb Sekunden gekostet, die Quelle des Codes zu 
finden...

> Aber was auffällig
> ist

..., daß du immer nur geklauten Code hier postest. Wie wäre es, wenn du 
statt dessen einfach mal lernst, den auch zu verstehen, und damit die 
Kompetenz erlangst, Fehler darin zu suchen und/oder ihn deinen eigenen 
Bedürfnissen entsprechend anpassen zu können...

Programmieren ist nicht wirklich sowas wie ein Puzzle, auch wenn es 
vielen Copy&Paste-Idioten zunächst vielleicht so vorkommen mag...

von Mike (Gast)


Lesenswert?

Teo Derix schrieb:
> Wenn das im Dabla steht(und das tut es definitiv) wird das sicher
> notwendig sein!

Dann wäre das Display bei den HD44780-kompatiblen ein echter Außenseiter 
und definitiv nicht kompatibel.

Diverse gut ohne Lesebefehl funktionierende EA DIP162 beweisen, dass 
auch ohne Busy das Display wunderbar funktioniert, wenn man ihm bei 
einigen länger dauernden Befehlen die Zeit für die Ausführung gönnt. Da 
das Display ziemlich deterministisch ist und es eigentlich auch keinen 
Grund gibt, das letzte aus dem Display heraus zu holen und dafür den µC 
damit zu beschäftigen, das Busy-Flag abzufragen, kann der µC in der 
Zwischenzeit besser etwas sinnvolles tun.

von Fabian R. (flo_rida)


Lesenswert?

Nun gut also dann Fange ich woanders an. Ausgangspunkt war folgender: 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD#Routinen_zur_LCD-Ansteuerung_im_4-Bit-Modus

Da steht:
1
           ldi temp1, 0b00000010        ; 4bit-Modus einstellen
2
           out PORTD, temp1
3
           rcall lcd_enable
4
           rcall delay5ms
5
           ldi temp1, 0b00101000        ; 4Bit / 2 Zeilen / 5x8
6
           rcall lcd_command

meiner Meinung deckt die zweite Anweisung auch den Befehl des ersten 
Bitmusters mit ab. Wieso ist das hier so gewählt? Die Anleitung meines 
HD44780 ermöglicht eine gemeinsame Übertragung der Einstellungen.

Grüße
Fabi

von Fritz (Gast)


Lesenswert?

Fabian Rauer schrieb:
> Wieso ist das hier so gewählt?

Weil sich der Controller zu diesem Zeitpunkt im 8-Bit-Modus befindet. 
Das untere Nibble des Befehls steht also nicht zur Verfügung. Die 
fehlenden zwei Einstellungen müssen also später im 4-Bit-Modus 
nachgeholt werden.

Mache dir auch den Unterschied zwischen lcd_enable und lcd_command klar.

Ich finde das AVR-Tutorial einen ungünstigen Einstieg in das Thema LCD 
(und gehe für diese Aussage schonmal in Deckung). Für einen Anfänger 
wäre es sicher einfacher, ein LCD zunächst ausschließlich im 8-Bit-Modus 
zu betreiben.

Am Atmega8(A) wird die Sache dann weiter kompliziert, weil man für einen 
zusammenhängenden Port mit 8 Bit entweder den USART oder die externe 
Taktversorgung blockieren muss.

von Thomas (kosmos)


Lesenswert?

Man kann auch ein Latch nehmen um das LCD im 8 Bit Modus zu betreiben 
und hat den Port jederzeit für andere Dinge zur Verfügung. Habe ich 
immer so gemacht als ich mit einem ATtiny26 nicht alle Pinsel opfern 
wollte um möglichst alle ADC Kanäle zu nutzen.

von Fabian R. (flo_rida)


Lesenswert?

Also ganz ehrlich mein Display scheint kaputt zu sein. Der Anschluss ist 
wie folgt:

PD5  PD4  PD3  PD2  PD1  PD0
E    RS   D7   D6   D5   D4

Damit ist es wie im Tutorial angeschlossen.

Mit folgendem Code initialisiere ich das Display:
1
.include "m8adef.inc"
2
3
.def temp   = r16
4
.def temp1  = r17
5
6
init:
7
longwait:
8
  ldi    temp, 255
9
  rcall  zeit          ;Diplay bekommt 12,75ms zum selber initialisieren
10
  dec    temp
11
  brne  longwait
12
13
  ldi    temp, 0b00000010      ;setzt Display in
14
  out    PORTD,temp        ;function set und data lenght 4-Bit 
15
  rcall  enable
16
  rcall  zeit
17
18
  ldi    temp, 0b00000010      ;oberes nibble für:
19
  out    PORTD,temp        ;function set und data lenght 4-Bit
20
  rcall  enable
21
  ldi    temp, 0b00001100      ;unteres nibble für:
22
  out    PORTD,temp        ;2-Zeilig und 5x8 Font, letzten beiden immer NULL
23
  rcall  enable
24
  rcall  zeit
25
26
  ldi    temp, 0b00000000      ;oberes nibble für:
27
  out    PORTD,temp        ;Display ON/OFF control
28
  rcall  enable  
29
  ldi    temp, 0b00001111      ;unters nibble für:
30
  out    PORTD,temp        ;Display ein, Cursor ein, Cursor blinken
31
  rcall  enable
32
  rcall  zeit
33
34
  ldi    temp, 0b00000000      ;oberes nibble für:
35
  out    PORTD,temp        ;Display control
36
  rcall  enable  
37
  ldi    temp, 0b00000001      ;unters nibble für:
38
  out    PORTD,temp        ;Display löschen, cursor auf 1.Spalte von 1.Zeile
39
  rcall  enable
40
  rcall  zeit            ;eigentlich zu kurz, aber ist letzte Übertragung der ans Display geht
41
42
enable:    
43
  sbi    PORTD,5        ;E=1
44
  nop
45
  nop
46
  nop
47
  cbi    PORTD,5        ;E=0
48
  ret
49
50
51
52
zeit:
53
  ldi  temp,0x42        ;eine 50us Warteschleife
54
WGLOOP:
55
  dec  temp
56
  brne WGLOOP
57
  ret
58
59
main:
60
  ldi    temp, HIGH(RAMEND)  ;Stackpointer initialisieren
61
  out    SPH, temp
62
  ldi    temp, LOW(RAMEND)  
63
  out    SPL, temp
64
65
  ldi    temp,0xFF      ;Port D auf Ausgang
66
  out    DDRD,temp
67
68
  rcall  init

Nur tut sich leider gar nichts. Um auszuschließen, dass das Display in 
einem undefinierten Zustand ist schalte ich es zu jedem Codetest vorher 
aus und wieder an. Die SUT_CKSEL steht auf INTRCOSC_4MHZ_6CK_0MS.
Kann es sein, dass noch irgendwelche Zeiten nicht stimmen?

Grüße
Fabi

von Fritz (Gast)


Lesenswert?

Fabian Rauer schrieb:
> Also ganz ehrlich mein Display scheint kaputt zu sein.

Jaja, Hauptsache du hast nichts falsch gemacht.

Einfach mal ein paar offensichtliche Fehler in deinem Code:

main wird nicht erreicht und schon gar nicht zu Beginn ausgeführt. 
Anders als in C, beginnt die Ausführung in asm nicht bei main (der 
Assembler kennt gar keine labels, das ist nur eine Gedächtnisstütze für 
dich) sondern "oben".

Damit sind jedenfalls der SP und das DDR nicht korrekt initialisiert.

Du hast da eine schöne Endlosschleife gebaut. Überlege dir doch mal, was 
da eigentlich passiert. Ich sehe mindestens zwei Fehler. Für den einen 
gibt deine IDE bestimmt auch eine Warnmeldung aus.


Versuch doch endlich mal zu verstehen, was du da in kleinen 
Variationen abtippst.

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.