Hallo,
Ich habe ein kleines Assembler Programm geschrieben, welches alle
Farbkombinationen einer RGB-Led durchlaufen soll. Leider funktioniert
dieses nur bei ca. 1 von 10 Programmstarts , sonst werden völlig
"falsche" Farbkombinationen durchlaufen. Ich bin nun etwas ratlos, da
ich keinen Fehler finden kann und ziemlicher Anfänger bin.
Normalerweise sollte das Programm den Farbverlauf
Grün->Gelb->Rot->Lila->Blau->Türkis->Grün... darstellen
Meistens macht es aber:
Weiß-> lila->Blau->Türkis->Weiß
oder
Weiß->plötzlich Lila->Rot->plötzlich Blau->plötzlich Türkis->plötzl.
Blau->plötzl. Weiß
oder andere komische Dinge
Hier der Programmcode:
1
.include "m8def.inc"
2
3
4
5
.org 0x000
6
7
rjmp main
8
9
.org ovf0addr
10
11
rjmp pwm
12
13
.org ovf1addr
14
15
rjmp changer
16
17
18
19
20
21
22
23
24
25
.def temp= r16
26
27
.def led1 =r17
28
29
.def led2 =r18
30
31
.def led3 =r19
32
33
.def outport =r20
34
35
.def pwmcounter= r23
36
37
.def counter = r21
38
39
.def ccounter = r22
40
41
42
43
.org INT_VECTORS_SIZE
44
45
46
47
main:
48
49
50
51
52
53
ldi temp, LOW(RAMEND)
54
55
out spl, temp
56
57
ldi temp, high(ramend)
58
59
out sph, temp
60
61
62
63
ldi temp, 1<<CS01
64
65
out tccr0,temp
66
67
ldi temp, 1<<CS11
68
69
out tccr1b, temp
70
71
ldi temp, 1<<toie0 | 1<<toie1
72
73
out timsk, temp
74
75
ldi led1, 150 ; Grün an
76
77
ldi temp,0xff ; portc als Ausgang
78
79
out ddrc, temp
80
81
82
83
sei
84
85
86
87
pwmloop:
88
89
out portc, outport
90
91
rjmp pwmloop
92
93
94
95
96
97
98
99
pwm:
100
101
inc pwmcounter
102
103
104
105
ldi outport,0xff ;Alle leds an
106
107
cp pwmcounter, led1
108
109
brsh l1off
110
111
l2: ;Prüfen ob leds aus sollen
112
113
cp pwmcounter, led2
114
115
brsh l2off
116
117
l3:
118
119
cp pwmcounter, led3
120
121
brsh l3off
122
123
l4:
124
125
cpi pwmcounter, 150
126
127
brsh killpwm
128
129
rjmp end
130
131
killpwm:ldi pwmcounter,0x00
132
133
end:
134
135
reti
136
137
l1off:
138
139
cbr outport, 0x01
140
141
rjmp l2
142
143
l2off:
144
145
cbr outport, 0x02
146
147
rjmp l3
148
149
l3off:
150
151
cbr outport, 0x04
152
153
rjmp l4
154
155
156
157
changer:
158
159
160
161
cpi counter,11 ;Counter resetten?
162
163
brsh clearcounter
164
165
ldi ZL,low(faelle)
166
167
ldi ZH,high(faelle)
168
169
add ZL,counter
170
171
ldi temp,0
172
173
adc ZH,temp
174
175
ijmp
176
177
178
179
clearcounter:
180
181
clr counter
182
183
rjmp changer
184
185
186
187
faelle:
188
189
inc led2 ;Rot +
190
191
rjmp endtime
192
193
dec led1 ; Gruen -
194
195
rjmp endtime
196
197
inc led3 ; Blau+
198
199
rjmp endtime
200
201
dec led2 ; Rot -
202
203
rjmp endtime
204
205
inc led1 ; Gruen+
206
207
rjmp endtime
208
209
dec led3 ; Blau-
210
211
rjmp endtime
212
213
214
215
endtime:
216
217
inc ccounter ; Wenn ccounter 150 wird counter erhöht
218
219
cpi ccounter, 150
220
221
breq newcounter
222
223
reti
224
225
newcounter:
226
227
subi counter, -2
228
229
ldi ccounter, 0x00
230
231
reti
Die verwendete Hardware ist das Atmel Evalution Board von Pollin+
eigenbau Leistungstreiber. In meiner Werkstatt werkeln (mit Ausnahme des
PCs) keine Schaltnetzteile o.Ä. , sodass ein EMV-Problem leider eher
unwahrscheinlich ist.
Ich hoffe mir kann jemand beim finden des Fehlers helfen.
MfG David
Entweder habe ich jetzt ein Knoten im Kopf oder es ist ein wunder das es
überhaupt geht?
Hast mal mal etwas von einem Stack gehört? ISR müssen Register sichern!
Und dann sollte man auch reti und call für ISR verwenden.
Hallo,
also rjmp passt schon, und reti sehe ich auch am Ende der ISR's. Aber
wie Peter schon sagte: beim Eintritt in die ISR zuerst mal das
Statusregister sichern (in r..,SREG), und dann alle Register die von der
ISR und der Hauptschleife gemeinsam genutzt werden und getrennte
Funktionen erfüllen.
In deinem speziellen Fall scheint die Hautschleife ja nun nichts zu tun
(von dem Out mal abgesehen), und sich ISR's nicht gegenseitig
unterbrechen können müsste das Programm eigentlich laufen.
Kannst du dein Programm nicht mal als ordentlich formatierten Code und
ohen die ganzen Leerzeilen reinstellen, beim durchsehen in dem Format
bekomme ich irgendwie einen Knoten in Sehnerv.
Sascha
Hi!
>Ich bin nun etwas ratlos, da>ich keinen Fehler finden kann und ziemlicher Anfänger bin.
Dafür schreibst du aber schon recht verwirrende Programme und das fast
alles ohne Kommentar.;-)
Du könntest led1 bis led3 mal einen eindeutigen Startwert geben.
So ganz erklärt es allerdings die plötzlichen Farbwechsel nicht.
Viel Erfolg, Uwe
Könnte es sein, dass es immer läuft, wenn du den Strom neu einschaltest
oder neu flashst?
So rein funktional betrachtet sollte dein Programm eigentlich laufen,
ich hab zumindest keine groben Fehler gesehen. Der AVR setzt aber die
Register nicht einfach auf 0 beim Reset, wie du augenscheinlich
voraussetzt, daher ist es schon ratsam, diese vor Verwendung mit einem
festen Wert zu initialisieren. (clr led2, clr led3 etc. hinter main:
einfügen)
Dein Programm hier ist ein 'klassisches' Beispiel, dass ISRs weder das
SREG noch irgendwelche Register sichern MÜSSEN. Da du dich aber als
'ziehmlichen Anfänger' bezeichnest: besser zuviel sichern, sich dafür
aber an das routinemäßige Sichern gewöhnen. Spart später viele Tage
Lebenszeit für die Fehlersuche.
Mark
Hallo,
die nicht geretteten Register sind vermutlich zufällig nicht ganz so
tragisch, in der main loop gibt es keine Flag-abhägigen Befehle und auch
keine, die die Flags ändern.
Allerdings habe ich mir das pwm-Chaos nicht im Detail angeschaut.
Die ijmp gehen aber in jedem Fall die Hose.
Die Adresse ist eim Flash, also eine Word-Adresse, die Label sind
Byte-Label.
Also
ldi ZL,low(faelle*2)
ldi ZH,high(faelle*2)
Dann addierst Du counter dazu, der kann offenbar 0...11 annehmen,
soviele Fälle sehe ich garnicht.
Dazu kommt: alle Befehle des AVR sind Word lang (mindestens), Du
addierst aber z.B. 1 und der AVR fällt auf die Nase, weil ein Befehl 2
lang ist...
Ein Tabelleneintrag ist ja wohl:
inc led2 ;Rot +
rjmp endtime
inc ist 1 Word (2 Byte)
rjmp ebenfalls.
Ein Eintrag ist also 4 Byte lang und nicht nur ein Byte...
Gruß aus Berlin
Michael
Hi
>Also> ldi ZL,low(faelle*2)> ldi ZH,high(faelle*2)
Das gilt nur für lpm. ijmp und icall arbeiten mit den Wordadressen.
>Dazu kommt: alle Befehle des AVR sind Word lang (mindestens), Du>addierst aber z.B. 1 und der AVR fällt auf die Nase, weil ein Befehl 2>lang ist...
Macht er auch richtig:
subi counter, -2
MfG Spess
Michael U. schrieb:> ldi ZL,low(faelle*2)> ldi ZH,high(faelle*2)
Ist bei dem ijmp genau nicht so, da hier die word-Adresse verwendet
wird. Adresse *2 ist nur für byteweisen Datenzugriff mit lpm. 'subi
counter, -2
' berücksichtigt auch ganz richtig die 4 bytes, weshalb die Sprünge
korrekt laufen sollten. Sehr eigenwillig geschrieben aber durchaus
kreativ.
Hallo,
@Spess53:
@Mark L. (m2k10):
wo Ihr recht habt, habt Ihr recht...
Das subi counter, -2 habe ich auch übersehen...
Wohl nicht mein Tag heute.
Gruß aus Berlin
Michael
Auch wenn der Code tatsächlich recht "creativ" ist, so scheint er doch
so weit zu funktionieren, auch der IJMP.
Allerdings wird zu Beginn nur das Register für "grün" led1
initialisiert, led2 und led3 haben einen zufälligen Zustand und werden
von diesem Zustand aus weiter gezählt, inklusive möglicher Überläufe.
Initialisieren der beiden Register dürfte das Problem beheben, hatte Uwe
bereits geschrieben.
hallo,
Danke für die vielen Antworten.
Des Rätselts Lösung war:
MWS schrieb:> Allerdings wird zu Beginn nur das Register für "grün" led1> initialisiert, led2 und led3 haben einen zufälligen Zustand und werden> von diesem Zustand aus weiter gezählt, inklusive möglicher Überläufe.>> Initialisieren der beiden Register dürfte das Problem beheben, hatte Uwe> bereits geschrieben.
Nachdem ich nun alle Register beim Programmstart initialisiere
funktionierts perfekt.
Grüße David