Forum: Mikrocontroller und Digitale Elektronik Assemblerprogr. LCD ansteuerung will nicht funktionieren


von toni (Gast)


Lesenswert?

Nabend!!!

Vielleicht erbarmt sich mal jemand, und schaut mal kurzerhand über den 
code drüber, denn der will einfach nicht funktionieren; mache jez den 3 
tag daran rum.

was soll passieren: LCD-Ansteuerung mit einer 4-bit datenleitung an ein 
2x8 display. das LCD wird initialisiert, danach bleibt es dunkel, bzw. 
hell. die obere reihe wird nach dem einschalten hell, also gehe ich 
davon aus, das es zumindest mal initialisiert wird. demnach muss der 
fehler irgendwo in dem unterprogramm Daten: stecken, oder nach der 
eigentlichen ini der falsche code für den 4 bit ansteuermodus. ich finde 
nur leider kein fehler :(.

im 8 bit modus funktioniert fast der selbe code allergings tadellos. 
kann es sein, das das display nur im 8 bit modus angesteuert werden 
kann?!

und von mir schonmal ein fettes danke an die, die sich die mühe machen 
und mal scnell drüberschauen.
1
;definitionsdatei
2
3
.equ DBport= portd ; ausgabeport
4
.equ RWport= portc ; RS,RW, E
5
.equ DBddr= ddrd ; datenrichtung ausgabe
6
.equ RWddr= ddrc ; datenrichtung rs, rw, e
7
.equ pine= 3    ;PD3 = Pin5
8
.equ pinrs= 5    ;PD2= Pin4
9
10
.device mega8
11
.include "m8def.inc"
12
13
14
rjmp start
15
16
;****************Warteschleifen*******************
17
ms2:     
18
             ldi r24, low (125)         ;// 2000 = µs = 2ms; 4 = takte
19
             ldi r25, high (125)        ;// 2000 = µs = 2ms; 4 = takte
20
  ms21:      sbiw r24,1                 ;//2takte
21
             brne ms21                  ;//2takte
22
             ret                        ;//4takte
23
24
ms5:                          
25
             ldi r24, low (1250)         ;// 5000 = µs = 5ms; 4 = takte
26
             ldi r25, high (1250)        ;// 5000 = µs = 5ms; 4 = takte
27
  ms51:      sbiw r24,1                 ;//2takte
28
             brne ms51                  ;//2takte
29
             ret                        ;//4takte
30
31
ms10:                         
32
             ldi r24, low (2500)         ;// 10000 = µs = 10ms; 4 = takte
33
         ldi r25, high (2500)        ;insgesamt 4Takte
34
  ms101:     sbiw r24,1                 ;//2takte
35
             brne ms101                  ;//2takte
36
             ret                        ;//4takte
37
38
; Stack initialisieren
39
start:
40
41
ldi r16, LOW(RAMEND)
42
out SPL, r16
43
44
ldi r16, HIGH(RAMEND)
45
out SPH, r16
46
47
ldi r16, 0xff
48
out ddrd, r16
49
ldi r16, 0xff
50
out ddrc, r16
51
52
; ----- LCD Anfang -----
53
54
;****************hier starten********************
55
rcall ms10
56
rcall ms10
57
rcall ini
58
59
rjmp haupt
60
61
;****************Daten/Befehle senden*************
62
63
;----------Daten Senden
64
daten:    sbi portc,  pinrs
65
      mov r18,   r17
66
      andi r17, 0b11110000
67
      out portd,  r17
68
      nop
69
      sbi portc,   pine 
70
      nop
71
      nop
72
      nop
73
      nop
74
      cbi portc,   pine
75
      swap r18
76
      andi r18, 0b11110000
77
      out portd,  r18
78
      nop
79
      sbi portc,   pine 
80
      nop
81
      nop
82
      nop
83
      nop
84
      cbi portc,   pine
85
      cbi portc,  pinrs
86
      nop
87
      rcall ms2
88
      ret
89
90
;----------Befehle Senden
91
befehl:    cbi portc,  pinrs
92
      mov r18,   r17
93
      andi r17, 0b11110000
94
      out portd,  r17
95
      sbi portc,   pine 
96
      nop
97
      nop
98
      nop
99
      nop
100
      cbi portc,   pine
101
      swap r18
102
      andi r18, 0b11110000
103
      out portd,  r18
104
      nop
105
      sbi portc,   pine 
106
      nop
107
      nop
108
      nop
109
      nop
110
      cbi portc,   pine
111
      rcall ms2
112
      ret
113
114
;----------Befehl für ini mit zeit
115
befehlini:  cbi portc,  pinrs
116
      out portd,  r17
117
      nop
118
      sbi portc,  pine
119
      nop 
120
      nop
121
      nop
122
      nop
123
      cbi portc,   pine
124
      rcall ms5
125
      ret
126
127
;****************Initialisierung******************
128
ini:  ldi r17,   0x00
129
      out portd,   r17
130
      ldi r17,  $30  ;$30 = 3 mal auf ausgang
131
      rcall befehlini  ; 1 befehl senden
132
      rcall befehlini  ; 2 befehl senden
133
      rcall befehlini  ; 3 befehl senden
134
      ldi r17, 0b00100000  ; 4-bit interface
135
      rcall befehlini
136
      ;Function set
137
      ldi r17,   0b00101000 ;Funtion set, DL, N, F  
138
      rcall befehl
139
      ldi r17,  0b00000001  ;display löschen
140
      rcall befehl
141
      ldi r17,  0b00000110  ;Kursor nach rechts wandernd, kein Display shift
142
      rcall befehl  
143
      ldi r17,   0b00001100   ;Display ein  
144
      rcall befehl
145
      ret
146
147
;----------------Hauptprogramm-------------------
148
149
haupt:
150
151
ldi r17, '0'
152
rcall daten
153
ldi r17, '8'
154
rcall daten
155
ldi r17, '/'
156
rcall daten
157
ldi r17, '1'
158
rcall daten
159
ldi r17, '5'
160
rcall daten
161
162
loop:
163
rjmp loop

von Neb N. (bluemorph)


Lesenswert?

Mhh, also, ich hab die letzten Tage auch an meinen Display verbracht und 
mich damit abgequält. In deinem Code kann ich eigentlich kein Fehler 
finden. Was nicht heißt das keiner drin ist smile!

Aber wie hast du denn das Display mit Port D verbunden?? So??

Display:               Port D:
DB7                    PB7
DB6                    PB6
DB5                    PB5
DB4                    PB4

Und was ist mit deinem RW Pin?? Liegt der die ganze Zeit auf Low?

MfG BlueMorph

von norad (Gast)


Lesenswert?

Also! Ich würde spontan sagen das Du vergessen hast die Datenleitungen 
von
µC  Portd 4-7 zu Display D0-D3 richtig anzuschliessen.

Sieht so aus als ob Du wie im 8-Bit Modus senden würdest.

Ausserdem fällt mir auf das Du trotzdem noch einen zweiten Port 
verbratest.

Du könntest alles über einen Port senden. Z.B. Portd  in dem Format:

7   6   5   4    3    2    1     0

   EN  RS  RW    D a t e n b y t e

von Hannes Lux (Gast)


Lesenswert?

> Also! Ich würde spontan sagen das Du vergessen hast die Datenleitungen
> von µC  Portd 4-7 zu Display D0-D3 richtig anzuschliessen.

D0-D3 des LCDs bleibt im 4-Bit-Modus normalerweise unbeschaltet, es wird 
D4-D7 verwendet.

...

von toni (Gast)


Lesenswert?

Moin!!!

danke erstmal für die ersten antworten.

"
Aber wie hast du denn das Display mit Port D verbunden?? So??

Display:               Port D:
DB7                    PB7
DB6                    PB6
DB5                    PB5
DB4                    PB4
"

richtig, genau so. der rest liegt am port c. rw liegt auf gnd, brauch 
ich erstmal nicht, da ich das busy noch nicht abfrage und alles über 
diese warteschleifen auf gut dünken steuere.
aber das freut mich schonmal ein wenig, ads ich nicht der einzigste bin, 
der keinen fehler entdeckt. der code vom tutorial funktioniert leider 
nämlich auch nicht, und dabei wird noch nichtmal das lcd initialisiert.

um weitere kommentare wäre ich dankbar :)

von toni (Gast)


Lesenswert?

achso, noch was:

"
Also! Ich würde spontan sagen das Du vergessen hast die Datenleitungen
von
µC  Portd 4-7 zu Display D0-D3 richtig anzuschliessen.

Sieht so aus als ob Du wie im 8-Bit Modus senden würdest.

Ausserdem fällt mir auf das Du trotzdem noch einen zweiten Port
verbratest.

Du könntest alles über einen Port senden. Z.B. Portd  in dem Format:

7   6   5   4    3    2    1     0

   EN  RS  RW    D a t e n b y t e
"

die anschluss belegung spielt nun erstmal keine rolle, ich habs für 
mich, der besseren übersicht halber, alles auf 2 ports gelegt. ich will 
erstmal nur, das ich einen funktionierenden code habe, dann wird 
optimiert und mehr elemente hinzugefügt.

von Hannes Lux (Gast)


Lesenswert?

> rcall ms10
> rcall ms10
> rcall ini

Vermutlich ist die Wartezeit viiiieeeeelll zu kurz...
Ich bevorzuge Zeiten an 250ms...

...

von toni (Gast)


Lesenswert?

leider nicht, funktioniert auch mit 250 ms nicht :(

von Klaus (Gast)


Lesenswert?

Hallo!

Hannes hat natürlich recht. Sorry!
>D0-D3 des LCDs bleibt im 4-Bit-Modus normalerweise unbeschaltet, es wird
>D4-D7 verwendet


Aber hier meine ich hast Du ein paar Probleme. Es fehlen Pausen.
Mach mal ein paar Warteschleifen rein wie im nachfolgenden Beispiel.

>ini:
       Mach mal hier ne größere Pause rein
>      ldi r17,   0x00
>      out portd,   r17
>      ldi r17,  $30  ;$30 = 3 mal auf ausgang
>      rcall befehlini  ; 1 befehl senden
       Pause > 100ms
>      rcall befehlini  ; 2 befehl senden
       Pause > 100ms
>      rcall befehlini  ; 3 befehl senden
       Pause > 100ms
>      ldi r17, 0b00100000  ; 4-bit interface
>      rcall befehlini
       Pause > 100ms
>      ;Function set
>      ldi r17,   0b00101000 ;Funtion set, DL, N, F
>      rcall befehl
>      ldi r17,  0b00000001  ;display löschen
>      rcall befehl
       Pause > 500ms  wegen Display löschen
>      ldi r17,  0b00000110  ;Kursor nach rechts wandernd, kein Display
>      rcall befehl
>      ldi r17,   0b00001100   ;Display ein
>      rcall befehl
      ret

Das nicht einhalten der Pausen kann zu fehlerhaften Initialiserung 
führen vor allem beim beim Start der Ini und Display löschen sollte man 
ausreichend warten.
Manche Displays machen da ganz schön Probleme z.b. c-control I2C-Display

von PillePalle (Gast)


Lesenswert?

Moin

Dir ist bekannt das die Befehle im 8Bit Modus gesendet werden müssen um 
den LCD Controller in den 4-Bit Modus zu versetzen ?

Beispiel:
1
;ATmega8 (clock frequency doesn't matter, tested with 1 MHz to 8 MHz)
2
; PortD.1 -> LCD RS (register select)
3
; PortD.2 -> LCD RW (read/write)
4
; PortD.3 -> LCd E (Enable)
5
; PortD.4 ... PortD.7 -> LCD data.4 ... data.7
6
; the other LCd data lines can be left open or tied to ground.
7
; the pin Vo can fit to GND for maximum of contrast 
8
9
;********************************************************************
10
LCD_wait:        ;read address and busy flag until busy flag cleared
11
  rcall  LCD_getaddr
12
  andi  return, 0x80
13
  brne  LCD_wait
14
  ret
15
16
17
LCD_delay:
18
  clr  r2
19
  LCD_delay_outer:
20
  clr  r3
21
    LCD_delay_inner:
22
    dec  r3
23
    brne  LCD_delay_inner
24
  dec  r2
25
  brne  LCD_delay_outer
26
ret
27
28
LCD_init:     
29
;**** for the most LCD you must write 3times a dummy command before you change to 4Bit***
30
;this is corrected by www.bellibot.com :-)) - before !you have only one LineLCD ***
31
  
32
  ldi  temp, 0b00001110  ;control lines are output, rest is input
33
  out  DDRD, temp
34
  
35
  rcall  LCD_delay    ;first, we'll tell the LCD that we want to use it
36
  ldi  arg, 0x20      ;in 4-bit mode.
37
  rcall  LCD_command8    ;LCD is still in 8-BIT MODE while writing this command!!!
38
39
  rcall  LCD_delay
40
  ldi  arg, 0x20    ;NOW: 2 lines, 5*7 font, 4-BIT MODE!     ** DUMMY ***
41
  rcall  LCD_command    ;
42
  
43
  rcall  LCD_wait
44
  ldi  arg, 0x20    ;NOW: 2 lines, 5*7 font, 4-BIT MODE!     ** DUMMY ***
45
  rcall  LCD_command    ;
46
47
  rcall  LCD_wait
48
  ldi  arg, 0x28    ;NOW: 2 lines, 5*7 font, 4-BIT MODE!     ** this change to 4bit 2 lines **
49
  rcall  LCD_command    ;after this point you don't can change anything 'show HD44780 Datasheet'
50
51
  rcall  LCD_wait
52
  ldi  arg, 0x0F    ;now proceed as usual: Display on, cursor on, blinking
53
  rcall  LCD_command
54
  
55
  rcall  LCD_wait
56
  ldi  arg, 0x01    ;clear display, cursor -> home
57
  rcall  LCD_command
58
  
59
  rcall  LCD_wait
60
  ldi  arg, 0x06    ;auto-inc cursor
61
  rcall  LCD_command
62
ret

das delay wird nur für die Init sequenz benutzt , danach abfrage des 
busy flags ( geht auch im 4bit-modus ) find ich pers. besser da keine 
Delay's mehr erforderlich .

von PillePalle (Gast)


Lesenswert?

ui ui , noch was vergessen
1
; the following source is from AVRbeginners.net .great work- well documented
2
; the advantage of read the busyflag in 4-bit mode is, no delay's needed
3
;***********************************************************************************
4
lcd_command8:  ;used for init (we need some 8-bit commands to switch to 4-bit mode!)
5
  in  temp, DDRD    ;we need to set the high nibble of DDRD while leaving
6
          ;the other bits untouched. Using temp for that.
7
  sbr  temp, 0b11110000  ;set high nibble in temp
8
  out  DDRD, temp    ;write value to DDRD again
9
  in  temp, PortD    ;then get the port value
10
  cbr  temp, 0b11110000  ;and clear the data bits
11
  cbr  arg, 0b00001111  ;then clear the low nibble of the arg
12
          ;so that no control line bits are overwritten
13
  or  temp, arg    ;then set the data bits (from the arg) in the
14
          ;Port value
15
  out  PortD, temp    ;and write the port value.
16
  sbi  PortD, LCD_E    ;now strobe E
17
  nop
18
  nop
19
  nop
20
  cbi  PortD, LCD_E
21
  in  temp, DDRD    ;get DDRD to make the data lines input again
22
  cbr  temp, 0b11110000  ;clear data line direction bits
23
  out  DDRD, temp    ;and write to DDRD
24
  ret
25
26
lcd_command:  ;same as LCD_putchar, but with RS low!
27
  push  arg
28
  in  temp, DDRD
29
  sbr  temp, 0b11110000
30
  out  DDRD, temp
31
  in  temp, PortD
32
  cbr  temp, 0b11111110
33
  cbr  arg, 0b00001111
34
  or  temp, arg
35
36
  out  PortD, temp
37
  sbi  PortD, LCD_E
38
  nop
39
  nop
40
  nop
41
  cbi  PortD, LCD_E
42
  pop  arg
43
  cbr  temp, 0b11110000
44
  swap  arg
45
  cbr  arg, 0b00001111
46
  or  temp, arg
47
  out  PortD, temp
48
  sbi  PortD, LCD_E
49
  nop
50
  nop
51
  nop
52
  cbi  PortD, LCD_E
53
  in  temp, DDRD
54
  cbr  temp, 0b11110000
55
  out  DDRD, temp
56
ret

hf

von PillePalle (Gast)


Lesenswert?

und das gehört auch noch dazu :(
1
LCD_getaddr:  ;works just like LCD_getchar, but with RS low, return.7 is the busy flag
2
  in  temp, DDRD
3
  andi  temp, 0b00001111
4
  out  DDRD, temp
5
  cbi  PortD, LCD_RS
6
  sbi  PortD, LCD_RW
7
  sbi  PortD, LCD_E
8
  nop
9
  in  temp, PinD
10
  andi  temp, 0b11110000
11
  mov  return, temp
12
  cbi  PortD, LCD_E
13
  nop
14
  nop
15
  sbi  PortD, LCD_E
16
  nop
17
  in  temp, PinD
18
  andi  temp, 0b11110000
19
  swap  temp
20
  or  return, temp
21
  cbi  PortD, LCD_E
22
  cbi  PortD, LCD_RW
23
ret

von PillePalle (Gast)


Angehängte Dateien:

Lesenswert?

so und nu als Include File für assembler (komplett) zum download..

mit Dank an AVR-beginner.net und anderen :-)

hf

von Hannes Lux (Gast)


Lesenswert?

> das delay wird nur für die Init sequenz benutzt , danach abfrage des
> busy flags ( geht auch im 4bit-modus ) find ich pers. besser da keine
> Delay's mehr erforderlich .

Busy-Flag lese ich schon lange nicht mehr ein, stattdessen opfere ich 
etwas AVR-SRAM für einen Bildschirmspeicher. Die Print-Routinen werden 
dadurch sauschnell, denn sie schreiben nur über Pointer auf SRAM.
Ein Hintergrundjob, der vom Timer auf einen Abstand von etwa 1ms 
synchronisiert wird, schaufelt dann je ein Byte aus dem 
Bildschirmspeicher an das LCD und entwirrt dabei gleich die 
DD-RAM-Adressen, der Bildschirmspeicher hat daher 
fortlaufende/durchgängige Adressen, kann also mit Fließtext beschrieben 
werden.

...

von Peter D. (peda)


Lesenswert?

Hannes Lux wrote:
> Busy-Flag lese ich schon lange nicht mehr ein, stattdessen opfere ich
> etwas AVR-SRAM für einen Bildschirmspeicher.

Außer, daß ich in C schreibe, scheinen wir wohl zu dem gleichen Schluß 
gekommen zu sein.
Es programmiert sich einfach viel angenehmer so, z.B.:

Beitrag "Formatierte Zahlenausgabe in C"


Peter

von Hannes Lux (Gast)


Lesenswert?

> Außer, daß ich in C schreibe, scheinen wir wohl zu dem gleichen Schluß
> gekommen zu sein.

Peter, ich habe sehr viel von Dir gelernt, was AVR-ASM und allgemeine 
Herangehensweise an das Programmieren betrifft. Ich habe mir auch einige 
Algorithmen von Dir abgeschaut und etliche Ratschläge angenommen, die Du 
Anderen gegeben hast.

Mit C kann ich mich aber leider nicht anfreunden, das ist mir (trotz 
vorhandenem K&R) zu kryptisch. Ich habe von Kindheit an große Probleme 
mit Sprachen und Auswendiglernen, aber nur geringe Probleme, etwas, was 
ich einmal verstanden habe, neu abzuleiten bzw. in Varianten umzusetzen. 
Dazu kommt die Tatsache, dass ich ungern unverstandenen fremden Code 
(auch in LIBs) verwende, also lieber kleinere Brötchen backe, dafür aber 
meine eigenen. Ich bin da eher der Selbermacher als der Benutzer, auch 
wenn der weg mühsamer ist und das Ergebnis etwas kleiner.

AVRASM empfinde ich als eindeutig und sehr angenehm (ich hatte mal etwas 
Kontakt zu C16-6502-ASM und MFA-8085-ASM). Und da es für mich Hobby ist, 
sehe ich auch keinen Grund mehr, mit fast 60 mühsam eine neue Sprache zu 
erlernen.

...

von Route_66 (Gast)


Lesenswert?

@Hannes
Deine Meinung teile ich voll und ganz. Die Variante mit dem gemappten 
Display im RAM ist auch immer mein Favorit. Da sind dann auch ganz 
einfach Scrollen und Full-Screen-Editing drin. Den Vorteil des 
Umsortierens der Zeilenanfänge - je nach Display und Hersteller - 
hattest Du ja bereits erwähnt.

von toni (Gast)


Lesenswert?

hmm, ich konnte das problem immernoch nicht lösen. habe nun mal 4 andere 
LCD´s versucht, keines funktioniert, alle jedoch im 8 bit modus. der 
code von der Homepage funktioniert zu meiner überraschung auch nicht. wo 
hängts da, was mache ich falsch?
achso, andere megas habe ich auch schon verwendet, ohne erfolg.

von toni (Gast)


Lesenswert?

nochmal zum besseren verständnis. im 4 bit modus funktioniert keines der 
lcd, mit keinem der beiden codes ( aus dem tutorial und der code aus dem 
ersten beitrag)
im 8 bit mlodus funktioniert jedoch alles tadellos.

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.