Guten tag alle miteinander Und zwar habe ich das oben beschriebene LCD Display welches aber nix anzeigt ausser In der ersten Zeile schwarze kästchen.. angeschlossen habe ich dieses wie folgt Portd 0-3 an Db 4-7 portd 4 an Rs portd 5 an E Das Programm ist das selbe wie im Assembler Beispiel und ich benutze den Internen 4 MHz Funktioniert dieses Display überhaupt im 4bit Modus Mfg Bqube
Pierre Gnauck schrieb: > Funktioniert dieses Display überhaupt im 4bit Modus Ja das tut es. Gruß Oliver
Pierre Gnauck schrieb: > Portd 0-3 an Db 4-7 portd 4 an Rs portd 5 an E Guten Morgen, und das R/#W Pin vom LCD?
Den R/W pin vom Display habe ich auf Masse gelegt für Schreiben.. Mfg Bqube
Das Programm was ich verwende ist das hier
1 | .include "m8def.inc" |
2 | |
3 | ; .def definiert ein Synonym (Namen) für ein µC Register |
4 | .def temp1 = r16 |
5 | .def temp2 = r17 |
6 | .def temp3 = r18 |
7 | |
8 | ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse |
9 | out SPL, temp1 |
10 | ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse |
11 | out SPH, temp1 |
12 | |
13 | ldi temp1, 0xFF ; Port D = Ausgang |
14 | out DDRD, temp1 |
15 | |
16 | rcall lcd_init ; Display initialisieren |
17 | rcall lcd_clear ; Display löschen |
18 | |
19 | ldi temp1, 'T' ; Zeichen anzeigen |
20 | rcall lcd_data |
21 | |
22 | ldi temp1, 'e' ; Zeichen anzeigen |
23 | rcall lcd_data |
24 | |
25 | ldi temp1, 's' ; Zeichen anzeigen |
26 | rcall lcd_data |
27 | |
28 | ldi temp1, 't' ; Zeichen anzeigen |
29 | rcall lcd_data |
30 | |
31 | loop: |
32 | rjmp loop |
33 | |
34 | |
35 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
36 | ;; LCD-Routinen ;; |
37 | ;; ============ ;; |
38 | ;; (c)andreas-s@web.de ;; |
39 | ;; ;; |
40 | ;; 4bit-Interface ;; |
41 | ;; DB4-DB7: PD0-PD3 ;; |
42 | ;; RS: PD4 ;; |
43 | ;; E: PD5 ;; |
44 | ;; ;; |
45 | ;; Takt: 4 MHz ;; |
46 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
47 | |
48 | |
49 | |
50 | ;sendet ein Datenbyte an das LCD |
51 | lcd_data: |
52 | mov temp2, temp1 ; "Sicherungskopie" für |
53 | ; die Übertragung des 2.Nibbles |
54 | swap temp1 ; Vertauschen |
55 | andi temp1, 0b00001111 ; oberes Nibble auf Null setzen |
56 | sbr temp1, 1<<4 ; entspricht 0b00010000 (Anm.1) |
57 | out PORTD, temp1 ; ausgeben |
58 | rcall lcd_enable ; Enable-Routine aufrufen |
59 | ; 2. Nibble, kein swap da es schon |
60 | ; an der richtigen stelle ist |
61 | andi temp2, 0b00001111 ; obere Hälfte auf Null setzen |
62 | sbr temp2, 1<<4 ; entspricht 0b00010000 |
63 | out PORTD, temp2 ; ausgeben |
64 | rcall lcd_enable ; Enable-Routine aufrufen |
65 | rcall delay50us ; Delay-Routine aufrufen |
66 | ret ; zurück zum Hauptprogramm |
67 | |
68 | ; sendet einen Befehl an das LCD |
69 | lcd_command: ; wie lcd_data, nur RS=0 |
70 | mov temp2, temp1 |
71 | swap temp1 |
72 | andi temp1, 0b00001111 |
73 | out PORTD, temp1 |
74 | rcall lcd_enable |
75 | andi temp2, 0b00001111 |
76 | out PORTD, temp2 |
77 | rcall lcd_enable |
78 | rcall delay50us |
79 | ret |
80 | |
81 | ; erzeugt den Enable-Puls |
82 | ; |
83 | ; Bei höherem Takt (>= 8 MHz) kann es notwendig sein, |
84 | ; vor dem Enable High 1-2 Wartetakte (nop) einzufügen. |
85 | ; Siehe dazu http://www.mikrocontroller.net/topic/81974#685882 |
86 | lcd_enable: |
87 | sbi PORTD, 5 ; Enable high |
88 | nop ; mindestens 3 Taktzyklen warten |
89 | nop |
90 | nop |
91 | cbi PORTD, 5 ; Enable wieder low |
92 | ret ; Und wieder zurück |
93 | |
94 | ; Pause nach jeder Übertragung |
95 | delay50us: ; 50µs Pause (bei 4 MHz) |
96 | ldi temp1, $42 |
97 | delay50us_:dec temp1 |
98 | brne delay50us_ |
99 | ret ; wieder zurück |
100 | |
101 | ; Längere Pause für manche Befehle |
102 | delay5ms: ; 5ms Pause (bei 4 MHz) |
103 | ldi temp1, $21 |
104 | WGLOOP0: ldi temp2, $C9 |
105 | WGLOOP1: dec temp2 |
106 | brne WGLOOP1 |
107 | dec temp1 |
108 | brne WGLOOP0 |
109 | ret ; wieder zurück |
110 | |
111 | ; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden |
112 | lcd_init: |
113 | ldi temp3,50 |
114 | powerupwait: |
115 | rcall delay5ms |
116 | dec temp3 |
117 | brne powerupwait |
118 | ldi temp1, 0b00000011 ; muss 3mal hintereinander gesendet |
119 | out PORTD, temp1 ; werden zur Initialisierung |
120 | rcall lcd_enable ; 1 |
121 | rcall delay5ms |
122 | rcall lcd_enable ; 2 |
123 | rcall delay5ms |
124 | rcall lcd_enable ; und 3! |
125 | rcall delay5ms |
126 | ldi temp1, 0b00000010 ; 4bit-Modus einstellen |
127 | out PORTD, temp1 |
128 | rcall lcd_enable |
129 | rcall delay5ms |
130 | ldi temp1, 0b00101000 ; 4Bit / 2 Zeilen / 5x8 |
131 | rcall lcd_command |
132 | ldi temp1, 0b00001100 ; Display ein / Cursor aus / kein Blinken |
133 | rcall lcd_command |
134 | ldi temp1, 0b00000100 ; inkrement / kein Scrollen |
135 | rcall lcd_command |
136 | ret |
137 | |
138 | ; Sendet den Befehl zur Löschung des Displays |
139 | lcd_clear: |
140 | ldi temp1, 0b00000001 ; Display löschen |
141 | rcall lcd_command |
142 | rcall delay5ms |
143 | ret |
144 | |
145 | ; Sendet den Befehl: Cursor Home |
146 | lcd_home: |
147 | ldi temp1, 0b00000010 ; Cursor Home |
148 | rcall lcd_command |
149 | rcall delay5ms |
150 | ret |
Wie oben beschrieben benutze ich den internen Quarz auf 4Mhz
So ich hab nun das Program auf 8Bit umgestellt .... wurde auch im AVR Simulator von oshonsoft ohne Probleme ausgegeben ... aber könnt ihr da bitte mal drüber schauen ob das so auch auf der Hardware laufen würde ? danke schonmal Mfg Bqube
1 | .include "m8def.inc" |
2 | |
3 | ;PORTB5 = E |
4 | ;PORTB4 = RS |
5 | ;PORTB3 = RW |
6 | ;PORTD 0-7 Datenleitungen |
7 | |
8 | |
9 | |
10 | |
11 | ldi R16, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse |
12 | out SPL, R16 |
13 | ldi R16, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse |
14 | out SPH, R16 |
15 | |
16 | ldi R21, 0xFF ; Port D = Ausgang |
17 | out DDRD, R21 |
18 | |
19 | ldi R21, 0xFF ; Port B = Ausgang |
20 | out DDRB, R21 |
21 | |
22 | |
23 | rcall lcd_init ; Display initialisieren |
24 | rcall LCDCLS ; Display löschen |
25 | |
26 | ldi R20, 'T' ; Zeichen anzeigen |
27 | rcall LCDDATA |
28 | |
29 | |
30 | ldi R20, 'e' ; Zeichen anzeigen |
31 | rcall LCDDATA |
32 | |
33 | ldi R20, 's' ; Zeichen anzeigen |
34 | rcall LCDDATA |
35 | |
36 | ldi R20, 't' ; Zeichen anzeigen |
37 | rcall LCDDATA |
38 | |
39 | loop: |
40 | rjmp loop |
41 | |
42 | |
43 | |
44 | |
45 | lcd_init: ;8Bit MODUS |
46 | rcall WARTENG |
47 | LDI R20,0b00110000 |
48 | OUT PORTD,R20 |
49 | rcall LCDOP |
50 | rcall WARTENK |
51 | rcall LCDOP |
52 | rcall WARTENK |
53 | rcall LCDOP |
54 | rcall WARTENK |
55 | rcall LCDOP |
56 | rcall WARTENK |
57 | LDI R20,0b00111000 ;2 ZEILEN |
58 | OUT PORTD,R20 |
59 | rcall LCDOP |
60 | rcall WARTENK |
61 | LDI R20,0b00001000 ;LCD AUS |
62 | OUT PORTD,R20 |
63 | rcall LCDOP |
64 | rcall WARTENK |
65 | LDI R20,0b00000001 ;LCD LÖSCHEN |
66 | OUT PORTD,R20 |
67 | rcall LCDOP |
68 | rcall WARTENK |
69 | LDI R20,0b00000110 ;Kursor nach rechts wandernd, kein Display shift |
70 | OUT PORTD,R20 |
71 | rcall LCDOP |
72 | rcall WARTENK |
73 | LDI R20,0b00001100 ;LCD EIN |
74 | OUT PORTD,R20 |
75 | rcall LCDOP |
76 | rcall WARTENK |
77 | LDI R20,0b00000000 |
78 | OUT PORTD,R20 |
79 | ret |
80 | |
81 | LCDDATA: |
82 | OUT PORTD,R20 |
83 | SBI PORTB,4 |
84 | CBI PORTB,3 |
85 | NOP |
86 | NOP |
87 | SBI PORTB,5 |
88 | NOP |
89 | NOP |
90 | NOP |
91 | NOP |
92 | CBI PORTB,5 |
93 | NOP |
94 | NOP |
95 | LDI R20,0b00000000 |
96 | OUT PORTD,R20 |
97 | rcall WARTENK |
98 | ret |
99 | |
100 | LCDOP: ;SENDEN DER EINSTELLUNGEN |
101 | CBI PORTB,4 |
102 | CBI PORTB,3 |
103 | NOP |
104 | NOP |
105 | SBI PORTB,5 |
106 | NOP |
107 | NOP |
108 | NOP |
109 | NOP |
110 | CBI PORTB,5 |
111 | NOP |
112 | NOP |
113 | ret |
114 | |
115 | LCDCLS: ;LCD LÖSCHEN |
116 | LDI R20,0b00000001 |
117 | OUT PORTD,R20 |
118 | rcall LCDOP |
119 | rcall WARTENK |
120 | LDI R20,0b00000000 |
121 | OUT PORTD,R20 |
122 | ret |
123 | |
124 | LCDHOME: |
125 | LDI R20,0b00000010 |
126 | OUT PORTD,R20 |
127 | rcall LCDOP |
128 | rcall WARTENK |
129 | LDI R20,0b00000000 |
130 | OUT PORTD,R20 |
131 | ret |
132 | |
133 | |
134 | |
135 | WARTENK: ;5ms SCHLEIFE |
136 | |
137 | ldi R17, 0x06 |
138 | WGLOOP0: ldi R18, 0x37 |
139 | WGLOOP1: ldi R19, 0xC9 |
140 | WGLOOP2: dec R19 |
141 | brne WGLOOP2 |
142 | dec R18 |
143 | brne WGLOOP1 |
144 | dec R17 |
145 | brne WGLOOP0 |
146 | nop |
147 | nop |
148 | ret |
149 | |
150 | WARTENG: ;20ms SCLHLEIFE |
151 | |
152 | WGLOOP11: ldi R19, 0x79 |
153 | WGLOOP22: dec R19 |
154 | brne WGLOOP22 |
155 | dec R18 |
156 | brne WGLOOP11 |
157 | dec R17 |
158 | brne WGLOOP0 |
159 | ldi R17, 0x01 |
160 | WGLOOP33: dec R17 |
161 | brne WGLOOP33 |
162 | nop |
163 | nop |
164 | ret |
Den 8-Bit Modus benutze ich nicht, weil der mir zu viele Portpins wegfuttert. Aber bei deinem 4-bit Programm ist vermutlich der Fehler, das du den ganzen Port beschreibst und damit auch die Kontrollleitungen unabsichtlich verwurschtelst: Pierre Gnauck schrieb: > ldi temp1, 0b00000011 ; muss 3mal hintereinander gesendet > out PORTD, temp1 ; werden zur Initialisierung Warum eigentlich das Rad immer neu erfinden? Da gibt es tonnenweise Beispiele - selbst in Assembler. Ich würde dir auch empfehlen, Portpins und Ports in Definitionen zu packen, damit du die Routinen auch mal in einer anderen Hardware Konfiguration benutzen kannst. z.B.:
1 | .equ LCD_RS_PORT PORTD |
2 | .equ LCD_RS_PIN 4 |
3 | ; und dann kannst du schreiben |
4 | sbi LCD_RS_PORT,LCD_RS_PIN ; RS Pin high |
Gehe also schrittweise vor: Fang an mit einer Routine, die ein Nibble (Halbbyte) aufs LCD schreibt. Brauchst du zur Initialisierung eh. Mach eine Routine die unter Benutzung der ersten ein Kommando Byte schreibt. Mach eine Routine, die ein Datenbyte schreibt, usw.
Danke für die hilfe ich überarbeite dann mal meinen 4bit code.... Warum ich das Rad neu erfinde einfach nur damit ich genau versteh wie alles funtioniert das init , die daten auf das Display zu bekommen... ich will nicht nur kopieren und einfügen sonder verstehn.. :) Mfg Bqube
So da bin ich wieder also im 8Bit modus hat alles funktioniert aber mit dem 4bit Modus komm ich nicht zu recht ..... Ich schicke drei mal diesen wert 0000-0011 dann schicke ich für den 4Bit Modus 0000-0011 So ab jetzt müsste ich alles im 4Bit modus senden seh ich das richtig so ??? Also muss ich wenn ich z.b 2 Zeilen 5*8 Punkte einstellen will also 0010-1000 Muss ich das Obere Nibble zu erst senden .... da ich vom PORTD die Ports 3 2 1 0 verwende müsste ich meinen 8Bit wert vertauschen mit swap dann wird doch aus 0010-1000 = 1000-0010 und dann schicke ich die ersten 4Bit 1000 und dann die letzten 0010 oder seh ich das falsch ?? Mfg Bqube
Ja, erst wird das obere Nibble auf die 4 Datenleitungen gelegt (aber ohne die anderen Portpins zu ändern!), E auf high und wieder auf low, dann das untere Nibble ( und wieder E high->low). Während der ganzen Operation müssen RS und RW low sein und da auch bleiben, da es Kommandos sind. Zum Daten schreiben dann wie oben, aber mit RS high.
Ist zwar nich schön aber schau es dir mal bitte an ich finde den fehler nicht warum das Display den 4Bit modus nicht will... danke schonmal Mfg Bqube
1 | .include "m8def.inc" |
2 | |
3 | ;-------------------------I |
4 | ; Port D (7654:3210:) I |
5 | ; Db LCD (:7654:3210) I |
6 | ; I |
7 | ; PORTD 0 = DB4 I |
8 | ; PORTD 1 = DB5 I |
9 | ; PORTD 2 = DB6 I |
10 | ; PORTD 3 = DB7 I |
11 | ; I |
12 | ; PORTB 5 = E I |
13 | ; PORTB 4 = RS I |
14 | ; PORTB 3 = RW I |
15 | ; I |
16 | ;-------------------------I |
17 | |
18 | LDI R16,0xFF |
19 | OUT DDRB,R16 |
20 | OUT DDRD,R16 |
21 | LDI R16,0x00 |
22 | |
23 | ldi R16, LOW(RAMEND) |
24 | out SPL, R16 |
25 | ldi R16, HIGH(RAMEND) |
26 | out SPH, R16 |
27 | |
28 | rcall lcd_load |
29 | |
30 | ldi r17,'T' |
31 | rcall daten_4bit_routine |
32 | |
33 | ldi r17,'E' |
34 | rcall daten_4bit_routine |
35 | |
36 | ldi r17,'S' |
37 | rcall daten_4bit_routine |
38 | |
39 | ldi r17,'t' |
40 | rcall daten_4bit_routine |
41 | |
42 | a: |
43 | rjmp a |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | pause20: |
51 | WGLOOP11: |
52 | ldi R19, 0x79 |
53 | WGLOOP22: |
54 | dec R19 |
55 | brne WGLOOP22 |
56 | dec R18 |
57 | brne WGLOOP11 |
58 | dec R17 |
59 | brne WGLOOP0 |
60 | ldi R17, 0x01 |
61 | WGLOOP33: |
62 | dec R17 |
63 | brne WGLOOP33 |
64 | nop |
65 | nop |
66 | ret |
67 | |
68 | pause5: |
69 | ldi R17, 0x06 |
70 | WGLOOP0: |
71 | ldi R18, 0x37 |
72 | WGLOOP1: |
73 | ldi R19, 0xC9 |
74 | WGLOOP2: |
75 | dec R19 |
76 | brne WGLOOP2 |
77 | dec R18 |
78 | brne WGLOOP1 |
79 | dec R17 |
80 | brne WGLOOP0 |
81 | nop |
82 | nop |
83 | ret |
84 | |
85 | |
86 | daten_4bit_routine: |
87 | swap r17 |
88 | out portd,r17 |
89 | rcall daten_routine |
90 | rcall pause5 |
91 | swap r17 |
92 | out portd,r17 |
93 | rcall daten_routine |
94 | rcall pause5 |
95 | ret |
96 | |
97 | adress_4bit_routine: |
98 | swap r17 |
99 | out portd,r17 |
100 | rcall adress_routine |
101 | rcall pause5 |
102 | swap r17 |
103 | out portd,r17 |
104 | rcall adress_routine |
105 | rcall pause5 |
106 | ret |
107 | |
108 | daten_routine: |
109 | cbi portb,3 |
110 | sbi portb,4 |
111 | nop |
112 | nop |
113 | nop |
114 | sbi portb,5 |
115 | nop |
116 | nop |
117 | nop |
118 | nop |
119 | nop |
120 | nop |
121 | cbi portb,5 |
122 | nop |
123 | nop |
124 | nop |
125 | ret |
126 | |
127 | adress_routine: |
128 | cbi portb,3 |
129 | cbi portb,4 |
130 | nop |
131 | nop |
132 | nop |
133 | sbi portb,5 |
134 | nop |
135 | nop |
136 | nop |
137 | nop |
138 | nop |
139 | nop |
140 | cbi portb,5 |
141 | nop |
142 | nop |
143 | nop |
144 | ret |
145 | |
146 | lcd_load: |
147 | rcall pause20 |
148 | LDI r17,0b00000011 |
149 | out Portd,r17 |
150 | rcall adress_routine |
151 | rcall pause5 |
152 | rcall adress_routine |
153 | rcall pause5 |
154 | rcall adress_routine |
155 | rcall pause5 |
156 | ldi r17,0b00000010 |
157 | out portd,r17 |
158 | rcall adress_routine |
159 | rcall pause5 |
160 | ldi r17,0b00101000 |
161 | adress_4bit_routine |
162 | ldi r17,0b00001000 |
163 | adress_4bit_routine |
164 | ldi r17,0b00000001 |
165 | adress_4bit_routine |
166 | ldi r17,0b00000110 |
167 | adress_4bit_routine |
168 | ldi r17,0b00001100 |
169 | adress_4bit_routine |
170 | ret |
Das sieht nicht nur nicht schön aus, sondern sogar so, das ich keine Lust habe, mich da durchzuwühlen. Pierre Gnauck schrieb: > rcall pause20 > LDI r17,0b00000011 > out Portd,r17 > rcall adress_routine > rcall pause5 > rcall adress_routine > rcall pause5 > rcall adress_routine > rcall pause5 Klar ist aber schon mal, das du nach dem ersten Setzen lange warten musst, min. 4,1 mS . Lies mal bitte das Datenblatt des KS0066 oder HD44780. Bild 24 im Original Hitachi Datenblatt. Und bitte, lies auch mal, wie es die andeen machen. Ausserdem zermanschst du immer noch die obere Hälfte von PortD mit deinen outs.
Gut werd ich mir mal anschauen ich hab auch schon gedacht es könnte am timing liegen aber in den anderen Beiträgen liest man immer nur von er muss minimal so und so lang warten dann kann es doch nicht schlimm sein wenn der LCD uc was länger wartet oder etwa doch ?.. Mfg Bqube
So hab nun den Fehler gefunden es klappt auf jeden fall schonmal im Simulator mit dem 4Bit Modus :) Danke für Hilfe Mfg Bqube
Denke dran, der Simulator läuft im Moment mit 4MHz. Wenn dein realer Mega auch auf 4MHz gefused ist, kein Problem, bei 8 MHz sind alle Warteschleifen natürlich nur halb so lang. Übrigens ist nur der originale HD44780 so eine richtige Schnarchnase, die neueren Klone, wie z.B. der KS0066 sind da schon schneller. Hier als kleines Präsent noch eine sehr universelle Warteroutine, im Orignal von Steve Wozniak aus dem Apple II ROM. Ein kleines Meisterwerk und ermöglicht einen weiten Bereich von Delays:
1 | .def del = r20 ; delay counter |
2 | .equ MS10 = 0x34 ; 10 mSecs |
3 | .equ MS30 = 0x60 ; 30 mSecs |
4 | .equ MS100 = 0x72 ; roughly 100mS with wozwait @ 8Mhz |
5 | .equ second = 0xe6 ; roughly a second with wozwait @ 8Mhz |
6 | ; steve wozniak's wait routine - this time for AVR |
7 | ; this is the routine with del^2 |
8 | ; this wait routine is ingenious and handles wide ranges of delay |
9 | ; as a hommage to steve i port it to all my embedded systems. |
10 | ; some presets |
11 | w1sec: ldi del,second |
12 | rjmp wozwait |
13 | w10ms: ldi del,MS10 |
14 | rjmp wozwait |
15 | w30ms: ldi del,MS30 |
16 | rjmp wozwait |
17 | w100ms: ldi del,MS100 |
18 | ;
|
19 | wozwait: push del |
20 | wwait2: push del |
21 | wwait1: subi del,1 |
22 | brne wwait1 |
23 | pop del |
24 | subi del,1 |
25 | brne wwait2 |
26 | pop del |
27 | subi del,1 |
28 | brne wozwait |
29 | ret
|
Im Simulator kannst du auch noch andere Werte für del(r20) ausprobieren um dir jede beliebige Verzögerung zu basteln.
Also müssen meine Wartezeiten bei den neueren nich al zu lang sein wie bei dem HD44780 .... mein Problem war das ich zwischen den Nibble eine pause von 5ms drinn hatte adress_4bit_routine: swap r17 out portd,r17 rcall adress_routine rcall pause5 <------------- Die hier swap r17 out portd,r17 rcall adress_routine rcall pause5 ret und aus diesem grun hat das ganze nich funtioniert weil der HD44780 nach dem ersten Nibble zu lange warten musste ... deswegen hat er diesen nich angenommen ..... Ich schreib grad an einer routine die mit hilfe von sbi und cbi die Port's setz und löscht so das ich die anderen 4Bit von dem Port nicht mit belege. Mfg Bqube
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.