Forum: Mikrocontroller und Digitale Elektronik Avr assmebler Programm funktioniert nur sporadisch


von David (Gast)


Lesenswert?

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

von Peter (Gast)


Lesenswert?

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.

von Sascha W. (sascha-w)


Lesenswert?

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

von Uwe (Gast)


Lesenswert?

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

von Mark L. (m2k10) Benutzerseite


Lesenswert?

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

von Michael U. (amiga)


Lesenswert?

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

von Spess53 (Gast)


Lesenswert?

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

von gtf (Gast)


Lesenswert?

Hallo David,
 im AVR PWM Tutorial ist ein Beispiel vorhanden dass kaum noch zu toppen 
ist.
http://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM

Und Push,Pop nicht vergessen. Wie das geht siehe
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Stack

Gruß gtf

von Mark L. (m2k10) Benutzerseite


Lesenswert?

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.

von MWS (Gast)


Lesenswert?

Wenn counter = 0 und dann  2 abgezogen wird, dann ist counter = 254, das 
als Index für den ijmp gibt ein interessantes Ergenis :D

von MWS (Gast)


Lesenswert?

Ooops, minus übersehen...

von Michael U. (amiga)


Lesenswert?

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

von Spess53 (Gast)


Lesenswert?

Hi

>Wohl nicht mein Tag heute.

Kenne ich.

MfG Spess

von MWS (Gast)


Lesenswert?

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.

von David (Gast)


Lesenswert?

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

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.