Forum: Mikrocontroller und Digitale Elektronik AVR ASM Pin schaltet einfach so


von Anonymous U. (gastt)


Lesenswert?

Hallo liebes Forum!

Ich bin ein wenig am verzweifeln, hab schon den halben Tag gesucht und 
nix gefunden: An meinem Attiny13 hängt ein Schieberegister. Mein 
Programm funktioniert wie es soll. Nun habe ich das Problem, dass nach 
(zufälliger?) Zeit die Pins beim SIPO kurz anschalten.

Was ich schon versucht habe:
-im Programm nur Sipo angesteuert: funktioniert, deswegen muss auch SIPO 
funktionieren

-Widerstand an Strobe von SIPO gehalten: funktioniert nicht, AVR-Pins 
gehen also nicht in tristate.

-Bei rcall AUSGABE die Ausgabe ans SIPO auf einen bestimmten Wert 
gezwungen: funktioniert nicht: der Fehler kann nicht bei meinem 
Unterprogramm rcall AUSGABE liegen.

-Es werden aber sonst keine Portpins geschalten!?!?

-Es tritt auch kein Reset auf.

Ich würde mich freuen wenn noch jemand eine Idee hat!!!

von Anonymous U. (gastt)


Lesenswert?

oh, und der code natürlich:
1
/*
2
 * Garagentoranzeige.asm
3
 *
4
 *  Created: 28.04.2013 09:48:12
5
 *   Author: Meister x.
6
 *  128kHz, Div: 0
7
 *
8
 *
9
 */ 
10
11
12
;Konstanten
13
.equ kErinnerung = 10    ;2ms
14
.equ kAnzeigemodus = 100    ;1s
15
16
17
;Definitionsdatei für Attiny13 Einbinden
18
.include "tn13def.inc"
19
20
21
.CSEG    ;ab hier beginnt Programm => Flash
22
23
24
;Interruptvektoren setzen
25
.org 0x0000      ;Reset Handler
26
  rjmp RESET
27
.org 0x0002      ;PCINT (Taster)
28
  rjmp TESTMODUS
29
.org 0x0003      ;Timer0 overflow für Clock
30
  rjmp CLOCK
31
.org 0x0008      ;WD interrupt
32
  rjmp MESSUNG
33
.org 0x0009      ;ADC Conversion Complete
34
  //rjmp ADC_READY
35
36
   
37
;Variablen deklarieren
38
.def rClock2ms = r1
39
.def rClock100ms = r2
40
.def rClock1s = r3
41
42
.def rTemp1 = r16
43
.def rTemp2 = r17
44
.def rTemp3 = r18
45
.def rTemp4 = r19
46
.def rTemp5 = r20
47
.def rTemp6 = r21
48
.def rSIPO = r22
49
.def rZustand = r23
50
51
RESET:
52
  
53
  cli ;Global Interrupt disable
54
55
56
  ;Ein- und Ausgänge festlegen (0=EIN, 1=AUS)
57
  ldi rTemp1, 0b00000111
58
  out DDRB, rTemp1
59
  ;Ausgänge aus- und Pullups einschalten
60
  ldi rTemp1, 0b00001000
61
  out PORTB, rTemp1
62
63
64
  ;Stackpointer ans Ende von SRAM setzen
65
  ldi rTemp1, LOW(RAMEND)
66
  out SPL, rTemp1
67
68
69
  ;Variablen rücksetzen
70
  clr rClock2ms
71
  clr rClock100ms
72
  clr rClock1s
73
  ldi rZustand, 0b10001111
74
  wdr
75
76
77
  ;Sleepmode einstellen (Power Down)
78
  ldi rTemp1, (1<<SE)|(1<<SM1)
79
  out MCUCR, rTemp1
80
  
81
  ;Timer0 (für Clock 8bit) konfigurieren
82
  ldi rTemp1, (1<<CS00)        ;Vorteiler /1
83
  out TCCR0B, rTemp1
84
  ldi rTemp1, (1<<TOIE0)        ;Interupt bei overflow erlauben
85
  out TIMSK0, rTemp1
86
  
87
  ; ADC konfigurieren: Vcc als Referenz, Single Conversion
88
    ldi rTemp1, (1<<MUX1)                  ; Kanal PB3, Referenzspannung Vcc
89
    out ADMUX, rTemp1
90
    ldi rTemp1, (1<<ADPS2)      ; VT /16
91
    out ADCSRA, rTemp1      
92
  ldi rTemp1, (1<<ADC2D)|(1<<ADC1D)            ;Disable DigPIN bei adc01
93
  out DIDR0, rTemp1
94
95
  ;Watchdog konfigurieren
96
  ldi rTemp1, (1<<WDTIE)|(1<<WDP2)|(1<<WDP0)        ;Interrupt mode, WD bei 0,5s
97
  out WDTCR, rTemp1
98
99
  ;PCINT konfigurieren
100
  ldi rTemp1, (1<<PCIE)                  ;PC Interrupt enable
101
  out GIMSK, rTemp1
102
  ldi rTemp1, (1<<PCINT3)                  ;PCINT3: PB3
103
  out PCMSK, rTemp1
104
  
105
106
  sei  ;Global interupt enable
107
  wdr
108
  ldi rSIPO, 0b00100000  ;SV erstmal an
109
  rcall AUSGABE
110
  
111
;------------------------------------------------------------------------------------------------------------------------------------------------------
112
113
114
MAIN:
115
116
117
;Modus-Flags abfragen
118
sbrc rZustand, 6  ;Sleep?
119
  rjmp SLEEPP
120
sbrs rZustand, 7  ;Anzeige/Erinnerung?
121
  rjmp ERINNERUNG
122
123
ANZEIGE:
124
  ;Timer rücksetzen
125
  clr rClock100ms
126
  clr rClock1s
127
  ANZ_LOOP:
128
    ;Zustand ausgeben
129
    mov rSIPO, rZustand
130
    cbr rSIPO, 0b11000000  ;flags aus SIPO entfernen
131
    sbr rSIPO, 0b00100000  ;SV an lassen
132
    rcall AUSGABE
133
    ;prüfe ob Anzeigemodus zuende
134
    mov rTemp1, rClock1s
135
    cpi rTemp1, kAnzeigemodus
136
    brlo ANZ_LOOP
137
  rjmp SLEEPP
138
139
ERINNERUNG:
140
  ;Zustand ausgeben
141
  mov rSIPO, rZustand
142
  cbr rSIPO, 0b11000000  ;flags aus SIPO entfernen
143
  sbr rSIPO, 0b00100000  ;SV an lassen
144
  rcall AUSGABE
145
  ;Timer rücksetzen
146
  clr rClock2ms
147
  ERI_LOOP:
148
    ;prüfe ob Erinnerung zuende
149
    mov rTemp1, rClock2ms
150
    cpi rTemp1, kErinnerung
151
    brlo ERI_LOOP
152
    ;LEDs erst aus
153
    ldi rSIPO, 0b00100000
154
    rcall AUSGABE
155
156
SLEEPP:
157
  ;Sleepflag
158
  sbr rZustand, 0b01000000
159
  cbr rZustand, 0b10000000
160
  ;SV und LEDs Aus
161
  ldi rSIPO, 0b00000000
162
  rcall AUSGABE
163
  sleep
164
rjmp MAIN
165
166
;------------------------------------------------------------------------------------------------------------------------------------------------------
167
168
169
CLOCK:
170
  push rTemp1      ;SREG und rTemp1 sichern
171
  in rTemp1, SREG
172
  push rTemp1
173
174
  inc rClock2ms
175
  ldi rTemp1, 50
176
  cp rClock2ms, rTemp1
177
    brsh INCR100ms
178
    rjmp CLOCKENDE
179
  INCR100ms:
180
    clr rClock2ms
181
    inc rClock100ms
182
    ldi rTemp1, 10
183
    cp rClock100ms, rTemp1
184
      brsh INCR1s
185
    rjmp CLOCKENDE
186
  INCR1s:
187
    clr rClock100ms
188
    inc rClock1s
189
    ldi rTemp1, 60
190
    cp rClock1s, rTemp1    ;max Anzahl s erreicht?
191
      brlo CLOCKENDE
192
      clr rClock1s
193
  CLOCKENDE:
194
195
  pop rTemp1      ;SREG und rTemp1 widerherstellen
196
  out SREG, rTemp1
197
  pop rTemp1
198
reti
199
200
201
AUSGABE:  ;(rSIPO=Data)
202
  push rTemp1      ;SREG und rTemp sichern
203
  in rTemp1, SREG
204
  push rTemp1
205
  push rTemp2
206
    
207
    mov rTemp2, rSIPO
208
    ldi rTemp2, 0b00100000
209
    ldi rTemp1, 8
210
    AUSGABE_NEXT:
211
      cbi PORTB, 0
212
      cbi PORTB, 1
213
      rol rTemp2
214
      brcc AUSGABE_0
215
      sbi PORTB, 1
216
      AUSGABE_0:
217
      sbi PORTB, 0
218
      dec rTemp1
219
      brne AUSGABE_NEXT
220
    sbi PORTB, 2
221
    cbi PORTB, 2
222
223
  pop rTemp2
224
  pop rTemp1      ;SREG und rTemp wiederherstellen
225
  out SREG, rTemp1
226
  pop rTemp1
227
ret
228
229
230
TESTMODUS:
231
  push rTemp1      ;SREG und rTemp sichern
232
  in rTemp1, SREG
233
  push rTemp1
234
235
ldi rSIPO, 0b00101111  ;SV und LEDs ein
236
rcall AUSGABE
237
TES_LOOP:
238
  wdr
239
  sbis PINB, 3    ;Taster noch gedrückt?
240
    rjmp TES_LOOP
241
242
  pop rTemp1      ;SREG und rTemp wiederherstellen
243
  out SREG, rTemp1
244
  pop rTemp1
245
reti
246
247
248
MESSUNG:
249
sbr rSIPO, 0b00110000  ;SV und Messstrom ein
250
rcall AUSGABE
251
  push rTemp1      ;SREG und rTemp sichern
252
  in rTemp1, SREG
253
  push rTemp1
254
  push rTemp2
255
  push rTemp3
256
  push rTemp4
257
  push rTemp5
258
  push rTemp6
259
260
    wdr
261
    //evtl. warten
262
    ldi rTemp1, (1<<ADEN)|(1<<ADSC)  ;ADC aktivieren und starten
263
    out ADCSRA, rTemp1
264
    MES_NFERTIG:
265
      in rTemp1, ADCSRA
266
      sbrc rTemp1, ADSC    ;fertig?
267
      rjmp MES_NFERTIG
268
    cbr rSIPO, 0b00010000  ;Messtrom aus
269
    rcall AUSGABE
270
    in rTemp2, ADCL
271
    in rTemp3, ADCH
272
    ldi rTemp1, (0<<ADEN)  ;ADC deaktivieren
273
    out ADCSRA, rTemp1
274
275
    ;LOOKUP ergebnis in rTemp6
276
    clr rTemp6        ;erster Torwert
277
    ldi ZL, low(LOOKUP*2)    ;laden des ersten Vergleichwertes
278
    ldi ZH, high(LOOKUP*2)
279
    MES_NEXTVAL:
280
      inc rTemp6      ;nächster Torwert
281
      lpm rTemp4, Z+    ;Vergleichwert Low
282
      lpm rTemp5, Z+    ;Vergleichwert High
283
      cp rTemp2, rTemp4  ;prüfe ob drunter
284
      cpc rTemp3, rTemp5
285
      brlo MES_NEXTVAL
286
    dec rTemp6    ;wieder eins zurück
287
    cbr rTemp6, 0b11110000
288
289
    ldi rTemp6, 0b00001001
290
291
    ;Alle Tore aus?
292
    cpi rTemp6, 0b00000000
293
    breq MES_SLEEPMODUS    ;Ja
294
    ;Nein:
295
296
    ;Anderungen?
297
    mov rTemp2, rZustand
298
    cbr rTemp2, 0b11000000  ;evtl Flags entfernen
299
    cp rTemp6, rTemp2
300
    brne MES_ANZEIGEMODUS  ;Ja
301
    ;Nein:
302
303
    ;war Anzeigemodus aktiv?
304
    sbrs rZustand, 7
305
    rjmp MES_ERINNERMODUS  ;Nein
306
    ;Ja
307
308
    rjmp MES_ENDE
309
310
    MES_SLEEPMODUS:
311
      ;Sleepflag, Zustand 0000
312
      ldi rZustand, 0b01000000
313
      rjmp MES_ENDE
314
315
    MES_ANZEIGEMODUS:
316
      ;Zustand übernehmen
317
      mov rZustand, rTemp6
318
      ;Anzeigeflag
319
      sbr rZustand, 0b10000000  ;Anzeigemodusflag setzen
320
      cbr rZustand, 0b01000000  ;Sleepflag aus
321
      rjmp MES_ENDE
322
323
    MES_ERINNERMODUS:
324
      ;Erinnerungsflag
325
      cbr rZustand, 0b11000000
326
327
MES_ENDE:
328
  pop rTemp6
329
  pop rTemp5
330
  pop rTemp4
331
  pop rTemp3
332
  pop rTemp2
333
  pop rTemp1      ;SREG und rTemp wiederherstellen
334
  out SREG, rTemp1
335
  pop rTemp1
336
  reti
337
338
339
  
340
;------------------------------------------------------------------------------------------------------------------------------------------------------
341
342
343
LOOKUP:
344
  .dw 978
345
  .dw 891
346
  .dw 818
347
  .dw 751
348
  .dw 694
349
  .dw 652
350
  .dw 616
351
  .dw 568
352
  .dw 526
353
  .dw 504
354
  .dw 484
355
  .dw 464
356
  .dw 445
357
  .dw 430
358
  .dw 417
359
  .dw 0

von Anonymous U. (gastt)


Lesenswert?

Was ich noch weiß:

Attiny ist im sleep. Er wird durch WD-Timer geweckt (ca. 0,5s). Bei 
wecken (WD-interrupt) wird was mit adc gemessen... Danach wird Flag für 
Anzeigemodus gesetzt. Danach reti. Jetzt springt er ins Hauptprogramm 
Main. Dort wird Flag ausgewertet und er springt wieder zum Anzeigemodus.
Diese falsche SIPO-Ausgabe muss zwischen dem Flag setzen und dem 
Anzeigemodus passieren.

von Anonymous U. (gastt)


Lesenswert?

Ich hab noch was rausgefunden: Es muss mit den Interrupts 
zusammenhängen: wenn ich in meinem Unterprogramm Interrupts verbiete 
(cli und zum schluss sei), so hab ich diese Probleme nicht.

Wo liegt die Ursache? ich hab doch alle register schön gesichert?!?!

von chris (Gast)


Lesenswert?

na denn simuliere es doch mal richtig wenn du es schon auf die 
INTroutine eingrenzen konntest

von Helmut H. (helmuth)


Lesenswert?

Hi
1
.org 0x0008      ;WD interrupt
2
  rjmp MESSUNG
3
.org 0x0009      ;ADC Conversion Complete
4
  //rjmp ADC_READY

Was passiert wenn der ADC Conversion Complete Interrupt auftritt?
würde das auskommentierte mal durch ein RETI ersetzen.

von Anonymous U. (gastt)


Lesenswert?

Das Problem ist, dass es zufällig passiert.

von Anonymous U. (gastt)


Lesenswert?

Helmut H. schrieb:
> Was passiert wenn der ADC Conversion Complete Interrupt auftritt?
> würde das auskommentierte mal durch ein RETI ersetzen.

dieser Interrupt ist disabled. Und ich hab auch schon mal das ganze 
adc-Zeugs auskommentiert: hilft leider nichts.

von Karl H. (kbuchegg)


Lesenswert?

GLeich vorweg.
Dein Code ist zu umfangreich, als das ich ihn hier im Kopf auf alle 
Eventualitäten abklopfen könnte.

Aber hier ist mir, im Zusammenhang  mit deinem letzten Posting, etwas 
aufgefallen

Du rufst
1
TESTMODUS:
2
  push rTemp1      ;SREG und rTemp sichern
3
  in rTemp1, SREG
4
  push rTemp1
5
6
ldi rSIPO, 0b00101111  ;SV und LEDs ein
7
rcall AUSGABE
8
TES_LOOP:
9
  wdr
10
  sbis PINB, 3    ;Taster noch gedrückt?
11
    rjmp TES_LOOP
12
13
  pop rTemp1      ;SREG und rTemp wiederherstellen
14
  out SREG, rTemp1
15
  pop rTemp1
16
reti

die Funktion AUSGABE aus dem Interrupt heraus auf.
Was, wenn die Funktion Ausgabe gerade läuft, die ersten Bits 
rausgetaktet hat, dann kommt der Interrupt und leiert seinerseits wieder 
die Ausgabe an.

Dann kommt alles durcheinander.
Stell sicher, dass du für Shared Resources (also alles was es nur ein 
einziges mal gibt, so wie das Schieberegister) immer einen einzigen 
gesicherten Pfad hast, der einzig und ausschliesslich benutzt wird. 
Nicht so wie hier, dass eine Ausgabe durch einen Interrupt unterbrochen 
werden kann, der dann selbst wieder eine Ausgabe macht. Das ist ein 
Garant für Ärger.

von Karl H. (kbuchegg)


Lesenswert?

Selbiges hier
1
MESSUNG:
2
sbr rSIPO, 0b00110000  ;SV und Messstrom ein
3
rcall AUSGABE
4
...

Tus nicht. Du öffnest die Büchse der Pandora.
Es gibt nur eine Stelle, an der Aufrufe an AUSGABE gemacht werden 
dürfen. Und das ist die Hauptschleife. Oder alternativ: es gibt nur und 
ausschliesslich Aufrufe dieser Funktion in ISR-Routinen.
Aber auf keinen Fall in beidem: Hauptschleife und ISR.

von Anonymous U. (gastt)


Lesenswert?

Karl Heinz schrieb:
> die Funktion AUSGABE aus dem Interrupt heraus auf.
> Was, wenn die Funktion Ausgabe gerade läuft, die ersten Bits
> rausgetaktet hat, dann kommt der Interrupt und leiert seinerseits wieder
> die Ausgabe an.

Ja klaaar! Ich bin ja ein Depp! Der halbe Tag fürn A... :-D Das passiert 
mir mit sicherheit nicht nochmal!

Karl Heinz schrieb:
> Tus nicht. Du öffnest die Büchse der Pandora.
> Es gibt nur eine Stelle, an der Aufrufe an AUSGABE gemacht werden
> dürfen. Und das ist die Hauptschleife. Oder alternativ: es gibt nur und
> ausschliesslich Aufrufe dieser Funktion in ISR-Routinen.
> Aber auf keinen Fall in beidem: Hauptschleife und ISR.

Ok, du hast absolut recht. Ich denke ich machs hier mal quick and dirty 
und disable die Interrupts am Anfang der Ausgabe und enable sie am ende 
wieder.

Ein herzliches Dankeschön!

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.