Hi, ich bin neu in der Mikrocontrollerprogrammierung und wollte jetzt mal ein LCD ansteuern. Dazu habe ich mal das Programm aus dem Tutorial zum Einsteigen "geklaut" und wollte es jetzt mal ausprobieren. Allerdings spuckt mir AVR-Studio beim Assemblieren immer eine Fehlermeldung aus (siehe Anhang). Ich bin mir aber auch nicht sicher ob ich alles richtig gemacht habe (blicke nicht ganz durch was mit Projekt und Solution jetzt eigentlich gemeint ist). Habe beim Start von AVR-Studio 5 "New Project" geklickt und dann meinen Kontroller gewählt, dann den LCD-Testprogramm Code reinkopiert. Anschliesend Rechtsklick auf AVRAssembler7 -> Add -> New Item -> Assembler file und dort den LCD-Routinen Code reinkopiert und die Datei LCD-Routinen genannt. Was mache ich falsch? Gruß, Thomas PS: wenn ich den Inhalt von LCD-Routinen.asm direkt unter mein "Hauptprogramm" kopiere geht es.
Ich habe das Programm zwar noch nie verwendet, aber setz zum testen mal bitte alle .include-Direktive an den Anfang des Programmes...
Hi, danke für den Tipp! dann lässt es sich zwar assemblieren aber läuft nicht wenn man es auf den MC programmiert. (vermute, dass er den Inhalt der Include Datei auch genau an die Stelle des .include Befehlts schreibt, also noch vor das Hauptprogramm wo sie eigentlich nicht hin gehören) Weiß sonst niemand eine Lösung?
Was ist denn konkret der Inhalt der "LCD-Routinen"? Die Fehlermeldungen besagen wohl, dass etwas mit den Sprungmarken "lcd_clear" und "lcd_data" nicht stimmt.
Auf deinem Screenshot ist das nicht erkennbar (und genau darum sind Bilder immer blöd), aber hast du die letzte Zeile, die mit dem .include mit einem Zeilenvorschub abgeschlossen? Manche Assembler sind da pingelig und werten as ansonsten nicht als vollständige Zeile. Wenns das auch nicht ist: poste deinen Source Code, damit jemand anderer das mal durch sein System durchjagen kann.
Karl Heinz Buchegger schrieb: > Auf deinem Screenshot ist das nicht erkennbar (und genau darum sind > Bilder immer blöd), aber hast du die letzte Zeile, die mit dem .include > mit einem Zeilenvorschub abgeschlossen? > Manche Assembler sind da pingelig und werten as ansonsten nicht als > vollständige Zeile. Ich flipp aus... genau das wars :) Vielen Dank! Jibbiee
Bei mir funktioniert es leider nicht. Weder mit .include, noch mit einfügen des Code nach dem Hauptprogramm. Wo liegt das Problem?
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ; Hauptprogramm ; |
3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
4 | |
5 | .include "m328Pdef.inc" |
6 | |
7 | |
8 | .def temp1 = r16 |
9 | .def temp2 = r17 |
10 | .def temp3 = r18 |
11 | |
12 | |
13 | ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse |
14 | out SPL, temp1 |
15 | ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse |
16 | out SPH, temp1 |
17 | |
18 | ldi temp1, 0xFF ;Port D = Ausgang |
19 | out DDRD, temp1 |
20 | |
21 | rcall lcd_init ;Display initialisieren |
22 | rcall lcd_clear ;Display löschen |
23 | |
24 | ldi temp1, 'T' ;Zeichen anzeigen |
25 | rcall lcd_data |
26 | |
27 | ldi temp1, 'e' ;Zeichen anzeigen |
28 | rcall lcd_data |
29 | |
30 | ldi temp1, 's' ;Zeichen anzeigen |
31 | rcall lcd_data |
32 | |
33 | ldi temp1, 't' ;Zeichen anzeigen |
34 | rcall lcd_data |
35 | |
36 | loop: |
37 | rjmp loop |
38 | |
39 | |
40 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
41 | ;; LCD-Routinen ;; |
42 | ;; ============ ;; |
43 | ;; (c)andreas-s@web.de ;; |
44 | ;; ;; |
45 | ;; 4bit-Interface ;; |
46 | ;; DB4-DB7: PD0-PD3 ;; |
47 | ;; RS: PD4 ;; |
48 | ;; E: PD5 ;; |
49 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
50 | |
51 | .def temp2 = r22 |
52 | .def temp3 = r23 |
53 | |
54 | .equ LCD_PORT = PORTD |
55 | .equ LCD_DDR = DDRD |
56 | .equ PIN_RS = 4 |
57 | .equ PIN_E = 5 |
58 | |
59 | .ifndef XTAL |
60 | .equ XTAL = 4000000 |
61 | .endif |
62 | |
63 | ;sendet ein Datenbyte an das LCD |
64 | lcd_data: |
65 | push temp2 |
66 | push temp3 |
67 | mov temp2, temp1 ; "Sicherungskopie" für |
68 | ; die Übertragung des 2.Nibbles |
69 | swap temp1 ; Vertauschen |
70 | andi temp1, 0b00001111 ; oberes Nibble auf Null setzen |
71 | sbr temp1, 1<<PIN_RS ; entspricht 0b00010000 |
72 | in temp3, LCD_PORT |
73 | andi temp3, 0x80 |
74 | or temp1, temp3 |
75 | out LCD_PORT, temp1 ; ausgeben |
76 | rcall lcd_enable ; Enable-Routine aufrufen |
77 | ; 2. Nibble, kein swap da es schon |
78 | ; an der richtigen stelle ist |
79 | andi temp2, 0b00001111 ; obere Hälfte auf Null setzen |
80 | sbr temp2, 1<<PIN_RS ; entspricht 0b00010000 |
81 | or temp2, temp3 |
82 | out LCD_PORT, temp2 ; ausgeben |
83 | rcall lcd_enable ; Enable-Routine aufrufen |
84 | rcall delay50us ; Delay-Routine aufrufen |
85 | |
86 | pop temp3 |
87 | pop temp2 |
88 | ret ; zurück zum Hauptprogramm |
89 | |
90 | ; sendet einen Befehl an das LCD |
91 | lcd_command: ; wie lcd_data, nur ohne RS zu setzen |
92 | push temp2 |
93 | push temp3 |
94 | |
95 | mov temp2, temp1 |
96 | swap temp1 |
97 | andi temp1, 0b00001111 |
98 | in temp3, LCD_PORT |
99 | andi temp3, 0x80 |
100 | or temp1, temp3 |
101 | out LCD_PORT, temp1 |
102 | rcall lcd_enable |
103 | andi temp2, 0b00001111 |
104 | or temp2, temp3 |
105 | out LCD_PORT, temp2 |
106 | rcall lcd_enable |
107 | rcall delay50us |
108 | |
109 | pop temp3 |
110 | pop temp2 |
111 | ret |
112 | |
113 | ; erzeugt den Enable-Puls |
114 | lcd_enable: |
115 | sbi LCD_PORT, PIN_E ; Enable high |
116 | nop ; 3 Taktzyklen warten |
117 | nop |
118 | nop |
119 | cbi LCD_PORT, PIN_E ; Enable wieder low |
120 | ret ; Und wieder zurück |
121 | |
122 | ; Pause nach jeder Übertragung |
123 | delay50us: ; 50us Pause |
124 | ldi temp1, ( XTAL * 50 / 3 ) / 1000000 |
125 | delay50us_: |
126 | dec temp1 |
127 | brne delay50us_ |
128 | ret ; wieder zurück |
129 | |
130 | ; Längere Pause für manche Befehle |
131 | delay5ms: ; 5ms Pause |
132 | ldi temp1, ( XTAL * 5 / 607 ) / 1000 |
133 | WGLOOP0: ldi temp2, $C9 |
134 | WGLOOP1: dec temp2 |
135 | brne WGLOOP1 |
136 | dec temp1 |
137 | brne WGLOOP0 |
138 | ret ; wieder zurück |
139 | |
140 | ; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden |
141 | lcd_init: |
142 | push temp1 |
143 | in temp1, LCD_DDR |
144 | ori temp1, (1<<PIN_E) | (1<<PIN_RS) | 0x0F |
145 | out LCD_DDR, temp1 |
146 | |
147 | ldi temp3,6 |
148 | powerupwait: |
149 | rcall delay5ms |
150 | dec temp3 |
151 | brne powerupwait |
152 | ldi temp1, 0b00000011 ; muss 3mal hintereinander gesendet |
153 | out LCD_PORT, temp1 ; werden zur Initialisierung |
154 | rcall lcd_enable ; 1 |
155 | rcall delay5ms |
156 | rcall lcd_enable ; 2 |
157 | rcall delay5ms |
158 | rcall lcd_enable ; und 3! |
159 | rcall delay5ms |
160 | ldi temp1, 0b00000010 ; 4bit-Modus einstellen |
161 | out LCD_PORT, temp1 |
162 | rcall lcd_enable |
163 | rcall delay5ms |
164 | ldi temp1, 0b00101000 ; 4 Bot, 2 Zeilen |
165 | rcall lcd_command |
166 | ldi temp1, 0b00001100 ; Display on, Cursor off |
167 | rcall lcd_command |
168 | ldi temp1, 0b00000100 ; endlich fertig |
169 | rcall lcd_command |
170 | |
171 | pop temp1 |
172 | ret |
173 | |
174 | ; Sendet den Befehl zur Löschung des Displays |
175 | lcd_clear: |
176 | push temp1 |
177 | ldi temp1, 0b00000001 ; Display löschen |
178 | rcall lcd_command |
179 | rcall delay5ms |
180 | pop temp1 |
181 | ret |
182 | |
183 | ; Cursor Home |
184 | lcd_home: |
185 | push temp1 |
186 | ldi temp1, 0b00000010 ; Cursor Home |
187 | rcall lcd_command |
188 | rcall delay5ms |
189 | pop temp1 |
190 | ret |
191 | |
192 | ; Einen konstanten Text aus dem Flash Speicher |
193 | ; ausgeben. Der Text wird mit einer 0 beendet |
194 | lcd_flash_string: |
195 | push temp1 |
196 | |
197 | lcd_flash_string_1: |
198 | lpm temp1, Z+ |
199 | cpi temp1, 0 |
200 | breq lcd_flash_string_2 |
201 | rcall lcd_data |
202 | rjmp lcd_flash_string_1 |
203 | |
204 | lcd_flash_string_2: |
205 | pop temp1 |
206 | ret |
207 | |
208 | ; Eine Zahl aus dem Register temp1 dezimal ausgeben |
209 | lcd_number: |
210 | push temp1 |
211 | push temp2 |
212 | push temp3 |
213 | |
214 | mov temp2, temp1 |
215 | ; abzählen wieviele Hunderter |
216 | ; in der Zahl enthalten sind |
217 | ldi temp1, '0' |
218 | lcd_number_1: |
219 | subi temp2, 100 |
220 | brcs lcd_number_2 |
221 | inc temp1 |
222 | rjmp lcd_number_1 |
223 | ; |
224 | ; die Hunderterstelle ausgeben |
225 | lcd_number_2: |
226 | rcall lcd_data |
227 | subi temp2, -100 ; 100 wieder dazuzählen, da die |
228 | ; vorherhgehende Schleife 100 zuviel |
229 | ; abgezogen hat |
230 | |
231 | ; abzählen wieviele Zehner in |
232 | ; der Zahl enthalten sind |
233 | ldi temp1, '0' |
234 | lcd_number_3: |
235 | subi temp2, 10 |
236 | brcs lcd_number_4 |
237 | inc temp1 |
238 | rjmp lcd_number_3 |
239 | |
240 | ; die Zehnerstelle ausgeben |
241 | lcd_number_4: |
242 | rcall lcd_data |
243 | subi temp2, -10 ; 10 wieder dazuzählen, da die |
244 | ; vorhergehende Schleife 10 zuviel |
245 | ; abgezogen hat |
246 | |
247 | ; die übrig gebliebenen Einer |
248 | ; noch ausgeben |
249 | ldi temp1, '0' |
250 | add temp1, temp2 |
251 | rcall lcd_data |
252 | |
253 | pop temp3 |
254 | pop temp2 |
255 | pop temp1 |
256 | ret |
257 | |
258 | ; eine Zahl aus dem Register temp1 hexadezimal ausgeben |
259 | lcd_number_hex: |
260 | push temp1 |
261 | |
262 | swap temp1 |
263 | andi temp1, $0F |
264 | rcall lcd_number_hex_digit |
265 | |
266 | pop temp1 |
267 | push temp1 |
268 | |
269 | andi temp1, $0F |
270 | rcall lcd_number_hex_digit |
271 | |
272 | pop temp1 |
273 | ret |
274 | |
275 | lcd_number_hex_digit: |
276 | cpi temp1, 10 |
277 | brlt lcd_number_hex_digit_1 |
278 | subi temp1, -( 'A' - '9' - 1 ) |
279 | lcd_number_hex_digit_1: |
280 | subi temp1, -'0' |
281 | rcall lcd_data |
282 | ret |
oder
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ; Hauptprogramm ; |
3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
4 | |
5 | .include "m328Pdef.inc" |
6 | |
7 | |
8 | .def temp1 = r16 |
9 | .def temp2 = r17 |
10 | .def temp3 = r18 |
11 | |
12 | |
13 | ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse |
14 | out SPL, temp1 |
15 | ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse |
16 | out SPH, temp1 |
17 | |
18 | ldi temp1, 0xFF ;Port D = Ausgang |
19 | out DDRD, temp1 |
20 | |
21 | rcall lcd_init ;Display initialisieren |
22 | rcall lcd_clear ;Display löschen |
23 | |
24 | ldi temp1, 'T' ;Zeichen anzeigen |
25 | rcall lcd_data |
26 | |
27 | ldi temp1, 'e' ;Zeichen anzeigen |
28 | rcall lcd_data |
29 | |
30 | ldi temp1, 's' ;Zeichen anzeigen |
31 | rcall lcd_data |
32 | |
33 | ldi temp1, 't' ;Zeichen anzeigen |
34 | rcall lcd_data |
35 | |
36 | loop: |
37 | rjmp loop |
38 | |
39 | .include "lcd-routines.asm" |
Hab die "lcd-routines.asm" im Solutionexplorer eingefügt und hab das selbige Problem wie oben der Thomas. Wenn ich den Code nach dem Hauptprogramm einfüge kommt auch: Warning 1 .def: 'temp2' redefinition (r17->r22) C:\Users\Ben\Documents\Atmel Studio\6.2\LCD Tests\LCD Tests\LCD Tests.asm 51 0 LCD Tests Warning 3 .def: 'temp3' redefinition (r18->r23) C:\Users\Ben\Documents\Atmel Studio\6.2\LCD Tests\LCD Tests\LCD Tests.asm 52 0 LCD Tests Message 2 previous definition of 'temp2' C:\Users\Ben\Documents\Atmel Studio\6.2\LCD Tests\LCD Tests\LCD Tests.asm 9 1 LCD Tests Message 4 previous definition of 'temp3' C:\Users\Ben\Documents\Atmel Studio\6.2\LCD Tests\LCD Tests\LCD Tests.asm 10 1 LCD Tests
In deinem Programnm werden "temp2" und "temp" 3 mal(!) definiert. Variable müssen eindeutig (einmalig) definiert werden. Wie soll der Assembler/Compiler denn wissen welches "temp2" du benutzen willst? Ausnahmen sind lokale Variablen, aber ob das dein Assembler kann weiß ich jetzt auch ncht (ich benutze andere Controller).
Der Ben schrieb: > Wo liegt das Problem? Dass du gerade einen uralten Threads gekapert hast, dessen Länge durch mißachten der Funktion für Anhänge um 500 Prozent erhöht hast und dein Problem außer "es geht nicht" überhaupt nichts mit der Fehlermeldung des to zu tun hat.
Der Code ist wohl wirklich etwas lang. Heute Nacht im halbschlaf gar nicht so realisiert. Sry! Nächstes Mal gehts in den Anhang damit. Allerdings habe ich bis auf die Variablen-Geschichte genau das gleiche Problem wie der TO.
Der Ben schrieb: > .include "lcd-routines.asm" Bin ich der Einzige der das für bedenklich hält. Wofür gibts Linker? Die sind auch etwas schlauer als der dumme Präprozessor.
Hi >Bin ich der Einzige der das für bedenklich hält. Wofür gibts Linker? Die >sind auch etwas schlauer als der dumme Präprozessor. Welchen Linker vom AVR-Assembler meinst du? 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.
