PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Wieder ein LED-Blinker



shemazai
09.12.2004, 00:58
Hallo !

Habe mich durch zig andere Varianten von "LED-Blinker-mit-Timer-Interrupts" gelesen und kann den Fehler in meiner nicht entdecken... hat jemand ein Stichwort für mich ?

Das Problem: Statt dem erwarteten Verhalten (LED für ca. 1 Sek. ein, dann für ca. 1 Sek. aus), blitzt die LED in Abständen von ca. 1 Sek kurz auf. Warum ??



.include "m8def.inc"

.org 0x000
rjmp main
.org 0x008
rjmp TimerHandler

main: ldi r16,0xFF ; PortB ist Output
out DDRB, r16

ldi r16,0b00000100 ; Overflow Interrupt Enable
out TIMSK, r16

ldi r16,0b00000011 ; Timer div. 1/64
out TCCR1B, r16

ldi r16,0b00000000
out PORTB, r16

sei

loop: rjmp loop

TimerHandler: in r16,PORTB; Aktuellen Zustand von PORTB einlesen
sbrc r16,0; sind die LEDs gerade aus ?Dann Einschalten, sonst...
rjmp Ausschalten; ausschalten...

ldi r16,0b00000111
out PORTB,r16
rjmp Ende

Ausschalten: ldi r16,0b00000000
out PORTB,r16

Ende: reti




[/code]

09.12.2004, 07:26
Hallo,
ich schätze das Problem liegt in der Anweisung
"in r16, PORTB"
hier liest du nicht den Ausgangs-Portzustand,
sondern den Pegel der Pins am Chip.
Je nachdem, wie die externe Beschaltung mit der LED ist,
kann der Pegel dort nicht mehr eindeutig 1 oder 0 sein,
so wie du es ausgegeben hast.
Wenn z.B eine LED direkt am Port-Pin nach GND angeschlossen ist.
So leuchtet diese bei PORT=1,
aber die Spannnung am PIN bricht zusammen,
und der Pegel ist nur ca. 1-2 je nach LED.
Wenn man das per IN-Anweisung liest, ist das 0 und nicht 1.
Versuche mal, den Zustand in einem Register festzuhalten.

Gruß Jan

shemazai
09.12.2004, 19:37
Hallo !

Danke erstmal für die Antwort!

Hab' deinen Vorschlag entsprechend umgesetzt und das Programm dabei etwas vereinfacht, sieht jetzt so aus:


.include "m8def.inc"

.org 0x000
rjmp main
.org 0x008
rjmp TimerHandler

main: ldi r16,0xFF ; PortB ist Output
out DDRB, r16

ldi r16,0b00000011 ; Timer div. 1/64
out TCCR1B, r16


ldi r16,0b00000100 ; Overflow Interrupt Enable
out TIMSK, r16


ldi r16,0b00000000 ; Alle LEDs aus.
out PORTB, r16

sei

loop: rjmp loop

TimerHandler: com r16
out PORTB,r16
Ende: reti

Interessanterweise zeigt die Schaltung exakt dasselbe Verhalten wie vorher.

(Habe auch Varianten ausprobiert, bei denen der Zustand in einem anderen Register verwaltet wird, ebenfalls das gleiche Verhalten.)

An Pin 14 hängt ein 100 Ohm - Widerstand, daran die LED an Masse. Den Pin einfach nur eingeschaltet lassen funktioniert.

Ich vermute fast, daß schlicht *zwei* Interrupts kurz hintereinander generiert werden, könnte das sein ?

Grüße!
Alex

shemazai
09.12.2004, 20:40
Lösung gefunden !

Das Problem war schlicht, daß kein Stack initialisiert, jedoch (bei den Interrupts) benutzt wurde.

Fertiges Programm läuft und sieht so aus:



.include "m8def.inc"

.org 0x000
rjmp main
reti
reti
reti
reti
reti
reti
reti
.org 0x008
rjmp TimerHandler

main: ldi r16, LOW(RAMEND)
out SPL, r16
ldi r16, HIGH(RAMEND)
out SPH, r16

ldi r16,0xFF ; PortB ist Output
out DDRC, r16

ldi r16,0b00000011 ; Timer div. 1/64
out TCCR1B, r16


ldi r16,0b00000100 ; Overflow Interrupt Enable
out TIMSK, r16


ldi r16,0b00000000 ; Alle LEDs aus.
out PORTC, r16

sei

loop: rjmp loop

TimerHandler: com r16
out PORTC,r16
Ende: reti

JanB
09.12.2004, 20:55
Hi Alex,
Ich vermute fast, daß schlicht *zwei* Interrupts kurz hintereinander generiert werden, könnte das sein ?
Ja, könnte sein, zumal ich in deinem Code
das Setzen des eigentlichen Timerregisters vermisse.

bei mir sieht das so aus:



Ausschnitt aus einem Programm für ATTiny15L

.DEF mp = R16
.DEF timeval = R12

init: ...
ldi mp,0-30 ;0- weil der timer vorwärts zählt
mov timeval,mp ;timerwert (ca. 25 us)
ldi mp,1 ;timer0 Vorteiler auf 1
out tccr0,mp ;timer0 control
ldi mp,2 ;timer0 int enable
out timsk,mp ;timer int mask
out tcnt0,timeval ;timer setzen
...

;Timer0 interrupthandler
Timer0Int:
out tcnt0,timeval ;timer wieder setzen
...
reti





Das timerregister tcnt0 zählt vorwärts (!) bis zum Überlauf,
der dann den Interrupt auslöst.
In der Interruptroutine muss dann sofort das Timerregister
wieder besetzt werden, damit das Timing stimmt.
Aber eigentlich müsste es bei dir auch funktionieren,
da müsste das Timeregister eben einmal "ganz rum" zählen.
Deshalb hab ich das bisher nicht erwähnt.

Aber probier halt mal...

Gruß Jan

JanB
09.12.2004, 21:01
Ahh. ich sehe gerade, du hast es schon gelöst.
Da haben wir uns "überschnitten"

Also dann Viel Spaß noch....

Jan