PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : TIMER/Counter aktivierung beim ATtiny2313



LotharK
23.02.2007, 17:06
Hallo,

ich versuche vergeblich den Timer-Interrupt des ATtiny2313 zu aktivieren.

Hier der NICHT FUNKTIONIERENDE Code.
Ich beschäftige mich erst sehr kurze Zeit mit Assembler. Die Daten der Interrupts habe ich aus dem Datenblatt.

Irgendwo beim Aktivieren des Interrupts steckt ein Fehler - nur wo?

.NOLIST
.INCLUDE "tn2313def.inc"
.LIST
;
; Definition der Register
;
.DEF mp=R16
.DEF ri = R1

; Beginn des Codes, Init I/O-Ports

rjmp main ; Springe zum Anfang

; Die Interrupt-Vektoren zu je 1 Byte:
reti ; Int0-Interrupt
reti ; Int1-Interrupt
reti ; TC1-Capture
reti ; TC1-Compare A
reti ; TC1-Overvlow
rjmp tc0i; TC0-Overvlow
reti ; UART0 RX
reti ; UART0 UDRE
reti ; UART Tx
reti ; Analog COMP
reti ; PCINT
reti ; Timer/Counter1 Compare Match B
reti ; Timer/Counter0 Compare Match A
reti ; Timer/Counter0 Compare Match B
reti ; USI Start
reti ; USI Overflow
reti ; EEReady
reti ; WDT Overflow

; Interrupt-Service-Routine für den Zähler
tc0i:
in ri,SREG ; Rette den Inhalt des Flag-Registers
LDI mp, 0x0F
OUT PortB, mp ; Hintere LEDs zur Kontrolle einschalten
out SREG,ri ; Stelle Flag-Register wieder her
reti ; Kehre vom Interrupt zurück

; Hauptprogramm beginnt hier

main:
ldi mp,LOW(RAMEND) ;Initiate Stackpointer
out SPL,mp ; wegen Interrupts und Unterprogr.

; Vorteiler des Zählers = 256, 4 MHz/256 = 15625 Hz = $3D09
ldi mp,0x04 ;Initiate Timer/Counter 0 Vorteiler
out TCCR0,mp ; an Timer 0 Control Register
LDI mp,0x0C ; PORTD 2 und 3 als Ausgang (INT0 und INT1)
out DDRD,mp ; in Datenrichtungsregister

; Interrupts bei Timer 0 einschalten
ldi mp,2; Bit 1 setzen
out TIMSK,mp ; in Timer Interupt Mask Register
LDI mp, 0x00
OUT PortB, mp

; Alle Interrupts allgemein freigeben
sei ; Gib Interrupts im Status-Register frei

loop:
NOP ; tue nichts
rjmp loop

wkrug
23.02.2007, 22:41
Ich hab da zwei Unschönheiten und einen Fehler entdeckt.

Die Unschönheit:
Du sicherst deine benutzten Register nicht in der Interruptroutine.
Das kann man machen, allerdings dürfen dan die Register nicht mehr im Hauptprogramm verwendet werden, aber das hast Du ja vermutlich vor.
Die zweite Sache - ich würd die Interruptroutinen hinter dem Main Programm ansiedeln.
Wenn der Code mal größer wird willst Du ja nicht erst die Interrupts durchwühlen bis Du das Hauptprogramm siehst.

Der Fehler:
Du lässt das DDRB Register auf 0x00 stehen, also auf Eingang.
Somit kann deine LED nicht leuchten.
Die Interruptroutine funktioniert anscheinend, habs aber nur mit dem Simulator getestet.

Ich hab Dir mal den geänderten Code angehängt, schau mal obs mit dem geht.

.NOLIST
.INCLUDE "tn2313def.inc"
.LIST
;
; Definition der Register
;
.DEF mp=R16
.DEF ri = R1

; Beginn des Codes, Init I/O-Ports

rjmp main ; Springe zum Anfang

; Die Interrupt-Vektoren zu je 1 Byte:
reti ; Int0-Interrupt
reti ; Int1-Interrupt
reti ; TC1-Capture
reti ; TC1-Compare A
reti ; TC1-Overvlow
rjmp tc0i; TC0-Overvlow
reti ; UART0 RX
reti ; UART0 UDRE
reti ; UART Tx
reti ; Analog COMP
reti ; PCINT
reti ; Timer/Counter1 Compare Match B
reti ; Timer/Counter0 Compare Match A
reti ; Timer/Counter0 Compare Match B
reti ; USI Start
reti ; USI Overflow
reti ; EEReady
reti ; WDT Overflow

; Interrupt-Service-Routine für den Zähler
tc0i:
push mp
push ri
in ri,SREG ; Rette den Inhalt des Flag-Registers
push ri
LDI mp, 0x0F
OUT PortB, mp ; Hintere LEDs zur Kontrolle einschalten
; Stelle Flag-Register wieder her
pop ri
out SREG,ri
pop ri
pop mp
reti ; Kehre vom Interrupt zurück

; Hauptprogramm beginnt hier

main:
ldi mp,LOW(RAMEND) ;Initiate Stackpointer
out SPL,mp ; wegen Interrupts und Unterprogr.

; Vorteiler des Zählers = 256, 4 MHz/256 = 15625 Hz = $3D09
ldi mp,0x04 ;Initiate Timer/Counter 0 Vorteiler
out TCCR0,mp ; an Timer 0 Control Register
LDI mp,0x0C ; PORTD 2 und 3 als Ausgang (INT0 und INT1)
out DDRD,mp ; in Datenrichtungsregister

; Interrupts bei Timer 0 einschalten
ldi mp,2; Bit 1 setzen
out TIMSK,mp ; in Timer Interupt Mask Register
LDI mp, 0x00
OUT PortB, mp
LDI mp,0x0F
OUT DDRB,mp

; Alle Interrupts allgemein freigeben
sei ; Gib Interrupts im Status-Register frei

loop:
NOP ; tue nichts
rjmp loop

LotharK
24.02.2007, 07:37
Danke, es funktioniert jetzt wie gewünscht. Natürlich war das mein Fehler. Das DDR-Register hatte ich vergessen. *g*

Deinen Rat werde ich in Zukunft beherzigen.
Für das Retten der Registerinhalte sah ich beim sample keine Veranlassung.

Hier verstehe ich was noch nicht. (Auszug aus Deinem Posting)

pop ri
out SREG,ri
pop ri
pop mp
reti ; Kehre vom Interrupt zurück


Warum das 2. pop ri?

Danke, für Deine Mühe - LotharK

SprinterSB
24.02.2007, 09:07
Es werden ja 3 Werte aufm Stack gesichert:

SREG
ri
mp

Um das SREG vom Stack zu holen, wird ri verwendet, weil man nicht direkt vom SFR-Bereich aus pushen/poppen kann, sondern über ein Register gehen muss.

LotharK
24.02.2007, 09:34
Jetzt hab ich es verstanden - Danke

MfG LotharK