PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PIC 16f628 -> Timer2 Interrupt



EGSLER
25.05.2007, 09:52
Hi

Der Timer2 soll nach dem erreichen des gewünschten Wertes einen Interrupt auslösen.

Wie kann ich PEIE setzten? :-s

Wie löse ich einen Interrupt aus? :-s

Vielen Dank schon mal

MFG

EGSLER

kalledom
25.05.2007, 13:58
Das Ein- / Ausschalten des peripheren und globalen Interrupts kann per DEFINE
#DEFINE D_GlobIntEin bsf INTCON,GIE ; Globaler Interrupt Ein
#DEFINE D_GlobIntAus bcf INTCON,GIE ; Globaler Interrupt Aus
#DEFINE D_PeriIntEin bsf INTCON,PEIE ; Peripherer Interrupt Ein
#DEFINE D_PeriIntAus bcf INTCON,PEIE ; Peripherer Interrupt Aus oder durch die Befehle
bsf INTCON,GIE ; Globaler Interrupt Ein
bcf INTCON,GIE ; Globaler Interrupt Aus
bsf INTCON,PEIE ; Peripherer Interrupt Ein
bcf INTCON,PEIE ; Peripherer Interrupt Aus erfolgen.

Timer werden incrementiert / um 1 erhöht und setzen bei jedem Überlauf von 255 / 0xFF nach 0 das Interrupt-Flag T?IF. Diese Flags müssen per Software zurück gesetzt werden.
Wieviel Zeit zwischen jedem Timer-Increment vergeht, wird durch die Quarz-Frequenz und die Initialisierung der Prescaler bestimmt,
wie lange es bis zum Auslösen eines Interrupts dauert = 256 - Timer-Wert mal Increment-Zeit.

Zum Auslösen eines Interrupts / Aufruf der ISR (Interrupt-Service-Routine) muß das entsprechende IE-Flag und die globale Int-Freigabe GIE gesetzt sein. Für einige Timer muß zusätzlich die periphere Int-Freigabe PEIE gesetzt sein (im Datenblatt nachlesen).
In der ISR muß abgefragt werden, wer den Int ausgelöst hat.

EGSLER
30.05.2007, 08:46
Vielen Dank erstmal für die Antwort O:) . Ich habe das Programm schon mal soweit aufgebaut, aber es scheint irgendwie nen Fehler zu haben, da es nicht aus der Schleife rausspringt :( . Vieleicht kannst du mir ja helfen den Fehler zu finden. :-b MFG Nils (EGSLER)

;config
list p=16f628
#include <P16f628.INC>
__CONFIG _PWRTE_ON & _WDT_OFF & _HS_OSC & _LVP_OFF
;************************************************* *******
; Variablennamen vergeben

w_copy Equ 0x20 ; Backup für Akkuregister
s_copy Equ 0x21 ; Backup für Statusregister

;************************************************* *************
; los gehts mit dem Programm

org 0
goto Init

;************************************************* *************
; die Interruptserviceroutine

org 4
intvec bcf INTCON, GIE ; disable Interrupt

movwf w_copy ; w retten
swapf STATUS, w ; STATUS retten
movwf s_copy ;

movlw D'131' ; 256-125=131 ((1MHz : 32 ): 125 = 250 Hz)
movwf TMR2

; Intrrupt servic routine
Int_serv

incf PORTA, f


;hier folgt die eigentliche Interrupt-Routine,
;die 250 mal pro Sekunde aufgerufen wird


Int_end swapf s_copy, w ; STATUS zurück
movwf STATUS
swapf w_copy, f ; w zurück mit flags
swapf w_copy, w

bcf INTCON, PEIE ; Interrupt-Flag löschen
bsf INTCON, GIE ; enable Interrupt

retfie

;************************************************* *************

;Initialisierung am Anfang des Programms

Init

bsf STATUS, RP0 ; auf Bank 1 umschalten
movlw B'11110000' ; PortA RA0 output
movwf TRISA
bcf STATUS, RP0 ; auf Bank 0 zurückschalten
BSF CMCON, CM0 ;

Comparatoreingang auf Digital umschalten
BSF CMCON, CM1
BSF CMCON, CM2

; Vorteiler 16:1 und Timer2 einschalten
BSF T2CON,T2CKPS1 ; Vorteiler 16:1
BSF T2CON,TMR2ON ; Timer2 ein

; Frequenz auf 10 kHz einstellen
BSF STATUS,RP0 ; Bank1
MOVLW D'124'
MOVWF PR2 ; 2,5 kHz
BCF STATUS,RP0 ; Bank1


bsf INTCON, PEIE ;
bsf INTCON, GIE ; Interrupt erlauben
loop goto loop ; eine Endlosschleife

;************************************************* *********


end

kalledom
31.05.2007, 09:47
Das GIE-Flag wird bei Auslösung eines Interrupts automatisch auf 0 und bei Verlassen durch RETI wieder auf 1 gesetzt; es sollte deshalb in der ISR nicht verändert werden.
Die xxIE-Flags (IE=Int-Enable) sollten auch nicht verändert werden.
bcf INTCON, PEIE ; Interrupt-Flag löschen
schaltet die peripheren Int's (dazu gehört vermutlich auch der benutzte Timer) am Ende der ISR aus !!!
Die xxIF-Flags (IF=Int-Flag) müssen in der ISR geprüft (wer hat ausgelöst) und vom Programm zurückgesetzt werden: bcf xxxxxxx, xxIF ; Interrupt-Flag löschen

PICture
02.06.2007, 14:26
Hallo EGSLER!

Dein Fehler ist im "Init" das mit endlose Schleife endet. Ein ASM Programm mit Interrupts, in dem ISR ein Hauptprogramm darstellt, sieht generell so aus:

org 0x0000
call Init
goto Main
org 0x0004
ISR...
retfie
Main goto Main
Init...
return
end

Siehe dazu "Interrupts" im "PIC Assembler" in Wiki.

MfG :)

kalledom
03.06.2007, 01:11
@PICture
Was ist bei einem "goto Init" und abschließender Endlosschleife falsch ?
Nach der Interrupt-Freigabe wird alles in der InterruptServiceRoutine erledigt.
Init muß nicht zwingend als SubRoutine ausgeführt werden.
"Main" ist ein beliebiger LabelName, genau wie "loop".
Ich finde daran nichts falsch.

PICture
03.06.2007, 02:55
Hallo kalledom!

Sorry, es ist nichts falsch, ich habe bloss einen Fehler gesucht und nicht gefunden. Du hast recht, dass es egal ist, wo das Programm auf Interrupt wartet. Man weiss ja nicht was die eigentliche ISR machen sollte, die wurde leider nicht gepostet. Vielleicht tritt ein Interrupt ein und unterbricht die endlose Schleife, aber das ist nicht einfach festzustellen, wenn man nicht weiss, was geschiehen sollte. Ich gebe auf. :)

Schöne Grüsse!

kalledom
03.06.2007, 12:39
Der Fehler wurde doch schon gefunden; EGSLER hat als vorletzten Befehl (vor reti) in der ISR:
bcf INTCON, PEIE ; Interrupt-Flag löschen Damit wird aber nicht das Interrupt-Flag, sondern der Interrupt-Enabe für periphere Int's abgeschaltet.
Da der Timer 2 beim PIC16F877 zu den peripheren Int's gehört, beim PIC16F628 sicherlich ebenso, wird nur 1 mal ein Int ausgelöst, weil dabei PEIE disabled wird .... dann kehrt Ruhe ein.