PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Seltsames Verhalten Timer 0 overflow interrupt



Markus87
24.08.2011, 11:54
Hi, bin gerade dabei mich in Timer und Interrupts einzuarbeiten. Habe dafür ein kleines Programm geschrieben welches nach einem Tastendruck eine LED blinken lässt.

Der Tastendruck soll dabei die globalen interrupts freischalten und das LED blinken ist mit dem Timer 0 interrupt realisiert.




NOLIST
.INCLUDE "m16def.inc" ; Headerdatei fuer Atmega 16
.LIST
;


;
; ============================================
; R E G I S T E R D E F I N I T I O N E N
; ============================================

.DEF rmp = R16 ; Vielzweckregister
;

;
; ==============================================
; R E S E T V E K T O R
; ==============================================
;
.CSEG
.ORG $0000
rjmp Main ; Reset-Vektor


; ==============================================
; INTERRUPTS
; ==============================================

.ORG OVF0addr ; Timer 0 overflow

rjmp schalten


;
; ============================================
; H A U P T P R O G R A M M I N I T
; ============================================
;
Main:
;
ldi rmp,0x02 // PORT A1 Ausgang, rest Eingang
out DDRA,rmp

ldi rmp,0x00
out PORTA,rmp // PORT A initialisieren

sbi PORTA,0 // Pull-up für PORT A0 aktivieren

//// Timer 0 konfigurieren

ldi rmp,0x05 // Prescaler 1024
out TCCR0,rmp

ldi rmp,0x01 // Interrupt bei Timer Overflow
out TIMSK,rmp

cli // Globale Interrupts deaktivieren
;
; ============================================
; P R O G R A M M - S C H L E I F E
; ============================================
;
Loop:

wdr
sbis PINA,0 // nächsten Befehl überspringen, wenn Taster nicht gedrückt ist
sei // Timer starten

rjmp loop // Zurueck nach Loop


/// -----------------------------------
/// Zum ein und ausschalten der LED
schalten:

in rmp,PINA // Zustand von LED einlesen
ldi R17, 0xFF //
eor R17,rmp // exor um LED Zustand zu wechseln

sbrc R17,1 // LED einschalten überspringen, wenn beim exor 0 rauskommt.
sbi PORTA,1 // LED einschalten

sbrs R17,1 // LED ausschalten überspringen, wenn beim exor 1 rauskommt.
cbi PORTA,1 // LED ausschalten


/// -----------------------------------






Wenn ich oben im deklarationsteil das deaktivieren der Interrupts per cli weglasse dann funktioniert alles so wie gedacht. Wenn ich jedoch cli dort stehen lasse blinkt die LED nur solange ich den Taster gedrückt lasse. Es scheint also so als ob nach ablauf der ISR Routine "Schalten" der Controller wieder beim Initialisierungsteil anfängt und dann wieder auf cli stößt. Aber normal müsste er doch nach ablauf der ISR wieder in der Loop Schleife landen, wie kommt er dann zu dem cli im Initialisierungsteil ?

PicNick
24.08.2011, 15:32
Ich kann mit freiem Auge in der ISR kein "RETI" erkennen. Der µC-Seppel lauft also durch den gesamten Speicher im Kreis, bis er wieder bei 0000 anfängt.

das sieht dann wie ein RESET aus, logo.

Markus87
24.08.2011, 16:01
oh mann das darf ja nich wahr sein so was dummes !!

Danke ;)

Markus87
24.08.2011, 16:05
das soll ma einer verstehen ich hab jetzt am ende der isr das reti stehen aber das verhalten is das gleiche !! Geht also trotzdem nich. Kann das daran liegen das der Taster nicht entprellt ist ? Wohl nicht oder weil der Taster ja nur die interrupts freischaltet.

Gruß

PicNick
24.08.2011, 16:25
mmmmh, klingt ja strange. Ich würde sicherheitshalber den Watchdog als möglichen Querschläger gleich mit den Fuses deaktivieren.

Was noch auffällt: Den Rücksprung für reti speichert er ja auf den Stack, und den hast du ja nicht initialisiert ?

Slein
24.08.2011, 19:04
Und TCNT0 sollte man afaik auch beim init und bei Tastendruck auf 0 setzen :)

Nur nicht entmutigen lassen!
Timer sind gut.

Slein
24.08.2011, 19:27
Ich hab das Alles mal (ungetestet!) zusammengetippert, probiers mal so:


NOLIST
.INCLUDE "m16def.inc" ; Headerdatei fuer Atmega 16
.LIST
;


;
; ============================================
; R E G I S T E R D E F I N I T I O N E N
; ============================================

.DEF rmp = R16 ; Vielzweckregister
;

;
; ==============================================
; R E S E T V E K T O R
; ==============================================
;
.CSEG
.ORG $0000
rjmp Main ; Reset-Vektor


; ==============================================
; INTERRUPTS
; ==============================================

.ORG OVF0addr ; Timer 0 overflow

rjmp schalten


;
; ============================================
; H A U P T P R O G R A M M I N I T
; ============================================
;
Main:
;
; --- EDIT: init stack
LDI rmp, HIGH(RAMEND) ; Oberes Byte
OUT SPH, rmp ; an Stapelzeiger
LDI rmp, LOW(RAMEND) ; Unteres Byte
OUT SPL, rmp ; an Stapelzeiger

ldi rmp,0x02 // PORT A1 Ausgang, rest Eingang
out DDRA,rmp

ldi rmp,0x00
out PORTA,rmp // PORT A initialisieren

sbi PORTA,0 // Pull-up für PORT A0 aktivieren

//// Timer 0 konfigurieren

ldi rmp,0x05 // Prescaler 1024
out TCCR0,rmp

ldi rmp,0x01 // Interrupt bei Timer Overflow
out TIMSK,rmp

cli // Globale Interrupts deaktivieren
;
; ============================================
; P R O G R A M M - S C H L E I F E
; ============================================
;
Loop:

wdr
sbic PINA,0 ; EDIT: nächsten Befehl überspringen, wenn Taster *gedrückt* ist
rjmp loop // Zurueck nach Loop

; --- EDIT: timer auf 0 und globale ints
LDI rmp, 0
OUT TCNT0, rmp
sei // Timer starten
rjmp loop // weiter im main loop

/// -----------------------------------
/// Zum ein und ausschalten der LED
schalten:

in rmp,PINA // Zustand von LED einlesen
ldi R17, 0xFF //
eor R17,rmp // exor um LED Zustand zu wechseln

sbrc R17,1 // LED einschalten überspringen, wenn beim exor 0 rauskommt.
sbi PORTA,1 // LED einschalten

sbrs R17,1 // LED ausschalten überspringen, wenn beim exor 1 rauskommt.
cbi PORTA,1 // LED ausschalten

; --- EDIT
CLI
RETI

/// -----------------------------------

Für größere Projekte solltest du aber TIMSK0 ändern, sei/cli setzt ja gleich alle ints tot.