von
Benjamin (Gast)
17.12.2012 16:58
Hallo zusammen,
ich betreibe an PORTF eines ATmega128A ein LCD im 4 Bit Modus.
Allerdings nicht an den Pins 0 - 5, sondern an den Pins 2 - 7 (ist durch
das Platinenlayout so gegeben).
An den Pins 0 - 5 funktioniert das Display (Testplatine).
Um das LCD an den Pins 2 - 7 zu betrieben war die Idee, vor der Übergabe
an den Port alles um 2 Stellen nach links zu verschieben. Und an dieser
Stelle gibt es Probleme (ebenfalls mit der Testplatine). Code lässt sich
kompilieren. Allerdings zeigt das Display nur zwei Striche im ersten
Element.
Ich benutze Code aus dem Netz und habe diesen um die Funktion portout
erweitert (siehe Anhang). Dies funktioniert auch, wenn das Display an
den Pins 0 - 5 angeschlossen ist (zurzeit auskommentiert)
Jemand eine Idee.
Danke!
Viele Grüße
Benjamin
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; LCD-Routinen ;;
3 ;; ============ ;;
4 ;; (c)andreas-s@web.de ;;
5 ;; ;;
6 ;; 4bit-Interface ;;
7 ;; DB4-DB7: PD0-PD3 ;;
8 ;; RS: PD5 ;;
9 ;; E: PD4 ;;
10 ;; ;;
11 ;; Takt: 4 MHz ;;
12 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13
14 ; .equ definiert ein Symbol und dessen Wert
15 .equ LCD_PORT = PORTF
16 .equ LCD_DDR = DDRF
17 .equ PIN_E = 4
18 .equ PIN_RS = 5
19 .equ XTAL = 4000000
20
21 ;sendet ein Datenbyte an das LCD
22 lcd_data:
23 push temp1
24 push temp2
25
26 mov temp2, temp1 ; "Sicherungskopie" für
27 ; die Übertragung des 2.Nibbles
28 swap temp1 ; Vertauschen
29 andi temp1, 0b00001111 ; oberes Nibble auf Null setzen
30 sbr temp1, 1<<PIN_RS ; entspricht 0b00010000 (Anm.1)
31 ;sts LCD_PORT, temp1 ; ausgeben
32 mov temp4, temp1
33 rcall portout
34 rcall lcd_enable ; Enable-Routine aufrufen
35 ; 2. Nibble, kein swap da es schon
36 ; an der richtigen stelle ist
37 andi temp2, 0b00001111 ; obere Hälfte auf Null setzen
38 sbr temp2, 1<<PIN_RS ; entspricht 0b00010000
39 ;sts LCD_PORT, temp2 ; ausgeben
40 mov temp4, temp2
41 rcall portout
42 rcall lcd_enable ; Enable-Routine aufrufen
43 rcall delay50us ; Delay-Routine aufrufen
44 pop temp2
45 pop temp1
46 ret ; zurück zum Hauptprogramm
47
48 ; sendet einen Befehl an das LCD
49 lcd_command: ; wie lcd_data, nur RS=0
50 push temp1
51 push temp2
52 mov temp2, temp1
53 swap temp1
54 andi temp1, 0b00001111
55 ;sts LCD_PORT, temp1
56 mov temp4, temp1
57 rcall portout
58 rcall lcd_enable
59 andi temp2, 0b00001111
60 ;sts LCD_PORT, temp2
61 mov temp4, temp2
62 rcall portout
63 rcall lcd_enable
64 rcall delay50us
65 pop temp2
66 pop temp1
67 ret
68
69 ; erzeugt den Enable-Puls
70 ;
71 ; Bei höherem Takt (>= 8 MHz) kann es notwendig sein,
72 ; vor dem Enable High 1-2 Wartetakte (nop) einzufügen.
73 ; Siehe dazu http://www.mikrocontroller.net/topic/81974#685882
74 lcd_enable:
75 lds temp4, LCD_PORT
76 sbr temp4, 1<<PIN_E ; Enable high
77 rcall portout
78 nop ; mindestens 3 Taktzyklen warten
79 nop
80 nop
81 lds temp4, LCD_PORT
82 cbr temp4, 1<<PIN_E ; Enable high
83 rcall portout
84 ret ; Und wieder zurück
85
86 ; Pause nach jeder Übertragung
87 delay50us: ; 50µs Pause (bei 4 MHz)
88 push temp1
89 ldi temp1, ( XTAL * 50 / 3 ) / 1000000
90 delay50us_:dec temp1
91 brne delay50us_
92 pop temp1
93 ret ; wieder zurück
94
95 ; Längere Pause für manche Befehle
96 delay5ms: ; 5ms Pause (bei 4 MHz)
97 push temp1
98 push temp2
99 ldi temp1, ( XTAL * 5 / 607 ) / 1000
100 WGLOOP0: ldi temp2, $C9
101 WGLOOP1: dec temp2
102 brne WGLOOP1
103 dec temp1
104 brne WGLOOP0
105 pop temp1
106 pop temp2
107 ret ; wieder zurück
108
109 ; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
110 lcd_init:
111 push temp1
112 push temp3
113 ldi temp1, 0xFF ;Port D = Ausgang
114 sts LCD_DDR, temp1
115 ldi temp3,50
116 powerupwait:
117 rcall delay5ms
118 dec temp3
119 brne powerupwait
120 ldi temp1, 0b00000011 ; muss 3mal hintereinander gesendet
121 ;sts LCD_PORT, temp1 ; werden zur Initialisierung
122 mov temp4, temp1
123 rcall portout
124 rcall lcd_enable ; 1
125 rcall delay5ms
126 rcall lcd_enable ; 2
127 rcall delay5ms
128 rcall lcd_enable ; und 3!
129 rcall delay5ms
130 ldi temp1, 0b00000010 ; 4bit-Modus einstellen
131 ;sts LCD_PORT, temp1
132 mov temp4, temp1
133 rcall portout
134 rcall lcd_enable
135 rcall delay5ms
136 ldi temp1, 0b00101000 ; 4Bit / 2 Zeilen / 5x8
137 rcall lcd_command
138 ldi temp1, 0b00001111 ; Display ein / Cursor aus / kein Blinken
139 rcall lcd_command
140 ldi temp1, 0b00000100 ; inkrement / kein Scrollen
141 rcall lcd_command
142 pop temp3
143 pop temp1
144 ret
145
146 ; Sendet den Befehl zur Löschung des Displays
147 lcd_clear:
148 push temp1
149 ldi temp1, 0b00000001 ; Display löschen
150 rcall lcd_command
151 rcall delay5ms
152 pop temp1
153 ret
154
155 ; Sendet den Befehl: Cursor Home
156 lcd_home:
157 push temp1
158 ldi temp1, 0b00000010 ; Cursor Home
159 rcall lcd_command
160 rcall delay5ms
161 pop temp1
162 ret
163
164 ; Einen konstanten Text aus dem Flash Speicher
165 ; ausgeben. Der Text wird mit einer 0 beendet
166 lcd_flash_string:
167 push temp1
168 push ZH
169 push ZL
170
171 lcd_flash_string_1:
172 lpm temp1, Z+
173 cpi temp1, 0
174 breq lcd_flash_string_2
175 rcall lcd_data
176 rjmp lcd_flash_string_1
177
178 lcd_flash_string_2:
179 pop ZL
180 pop ZH
181 pop temp1
182 ret
183
184 portout:
185 lds register, LCD_PORT
186
187 SBRC temp4, 0
188 ori register, 0b00000100
189 SBRS temp4, 0
190 andi register, 0b11111011
191
192 SBRC temp4, 1
193 ori register, 0b00001000
194 SBRS temp4, 1
195 andi register, 0b11110111
196
197 SBRC temp4, 2
198 ori register, 0b00010000
199 SBRS temp4, 2
200 andi register, 0b11101111
201
202 SBRC temp4, 3
203 ori register, 0b00100000
204 SBRS temp4, 3
205 andi register, 0b11011111
206
207 SBRC temp4, 4
208 ori register, 0b01000000
209 SBRS temp4, 4
210 andi register, 0b10111111
211
212 SBRC temp4, 5
213 ori register, 0b10000000
214 SBRS temp4, 5
215 andi register, 0b01111111
216 /*
217
218 SBRC temp4, 0
219 ori register, 1
220 SBRS temp4, 0
221 andi register, 254
222
223 SBRC temp4, 1
224 ori register, 2
225 SBRS temp4, 1
226 andi register, 253
227
228 SBRC temp4, 2
229 ori register, 4
230 SBRS temp4, 2
231 andi register, 251
232
233 SBRC temp4, 3
234 ori register, 8
235 SBRS temp4, 3
236 andi register, 247
237
238 SBRC temp4, 4
239 ori register, 16
240 SBRS temp4, 4
241 andi register, 239
242
243 SBRC temp4, 5
244 ori register, 32
245 SBRS temp4, 5
246 andi register, 223
247 */
248 clr temp4
249 sts LCD_PORT, register
250 ret
Was zum ....
... soll den das hier machen? 1 portout:
2 lds register, LCD_PORT
3
4 SBRC temp4, 0
5 ori register, 0b00000100
6 SBRS temp4, 0
7 andi register, 0b11111011
8
9 SBRC temp4, 1
10 ori register, 0b00001000
11 SBRS temp4, 1
12 andi register, 0b11110111
13
14 SBRC temp4, 2
15 ori register, 0b00010000
16 SBRS temp4, 2
17 andi register, 0b11101111
18
19 SBRC temp4, 3
20 ori register, 0b00100000
21 SBRS temp4, 3
22 andi register, 0b11011111
23
24 SBRC temp4, 4
25 ori register, 0b01000000
du brauchst doch nur den Inhalt von temp4 um 2 Stellen nach links
schieben, die beiden untersten Bits vom PORTF wieder einodern (damit du
nicht unabsichtlich etwas an den beiden änderst und das ganze an den
PORTF ausgeben. Das ganze sind grade mal überschlagsmässig 5 Anweisungen
ohne den Return. Machs doch nicht so kompliziert.
von
Benjamin (Gast)
17.12.2012 17:16
Im Grunde macht der Code dieses hier:
1 portout:
2 push temp2
3 ldi temp2, 4
4 mul temp4, temp2
5
6 sts LCD_PORT, r0
7
8 pop temp2
9 ret
Hatte es mir Schrittweise programmiert. Hilft manchmal wenn mans
Bitweise durchgeht.
Daran scheint es aber nicht zu liegen...
von
prof.dr.schlau (Gast)
17.12.2012 17:23
Ist vielleicht noch JTag o.ä. aktiv? Andere Vorbelegung der Pins (kenne
den 128 nun nicht speziell), ist aber gerne ein Stolperstein
von
Benjamin (Gast)
17.12.2012 17:26
von
prof.dr.schlau (Gast)
17.12.2012 17:32
Richtig doofe Frage: Hast du beim Verschieben diese Pins angepasst:
.equ PIN_E = 4
.equ PIN_RS = 5
??
Danke für den Hinweis.
Habe die Pins angepasst, allerdings nur bei der Ausgabe.
Bei lcd_enable wird jedoch der Inhalt von LCD_PORT gelesen. Habe diesen
jetzt nach dem Einlesen durch 4 geteilt und funktioniert es :)
Vielen Dank!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.