Nur ein Interrupt beim PIC12F629?

Gast #776284
Lesenswert?

Hab im C-Compiler für den PIC folgendes gelesen:

As there is a maximum of one interrupt vector in the midrange PIC 
series, only one interrupt
function may be defined. The interrupt vector will automatically be set 
to point to this function.


Heisst das ich kann nur eine C-Funktion per Interrupt aufrufen? Weiss 
jemand wo ich die jeweiligen Interrupt-Nummern finde (diejenige für die 
C-Funktion)
Gast #776324
Lesenswert?

Danke!

Will einen Interrupt von Timer 0 Overflow auslösen lassen, geht einfach 
nicht:

Hab folgendes initialisiert:
1
//Timer 0 Init
2
T0SE = 0;  //Rising Edge
3
T0CS = 0;  //Clk Source
4
PSA = 0;  //Prescaler assigned to T0
5
PS0 = 1;  //Prescaler = 256
6
PS1 = 1;
7
PS2 = 1;
8
TMR0 = 128;  //Timer value
9
T0IF = 0;  //Clearing Interrupt
10
T0IE = 1;  //Interrupt Mask
11
GIE  = 1;  //Global Interrupt Enable


Dies ist meine Interrupt Routine:
1
  void interrupt t0_int(void){
2
    GPIO2 ^= 1;
3
    T0IF=0;
4
    TMR0=0;    //Laden
5
  }
Gast #776423
Lesenswert?

Zitat :

Die PIC16 verfügen nur über einen einzigen Interrupt-Vektor (Adresse 
0x04). Jeder aktivierte und ausgelöste Interrupt führt dazu, daß der PIC 
an diese Adresse springt. Beim Hi-Tech sorgt das Keyword interrupt 
dafür, daß die Funktion zu einer Interrupt-Funktion wird (steht an der 
richtigen Adresse und sichert alle relevanten Register).

Da es nur einen Interrupt-Vektor gibt, kann es prinzipiell auch nur eine 
Interrupt-Funktion geben. Wenn Du mehrere Interrupts benötigst, mußt Du 
in dieser Funktion die entsprechenden Interrupt-Flags und eventuell auch 
die Enable-Bits abfragen:

Code:

void interrupt name_ist_egal (void)
{
    if (TMR1IE && TMR1IF)
    {
        ...  // Code für TMR1-Interrupt
    }

    if (TMR2IE && TMR1IF)
    {

        ...  // Code für TMR2-Interrupt
    }
}


Die Abfrage des Enable-Bits ist nur dann nötig, wenn der entsprechende 
Interrupt zeitweise im Programm deaktiviert wird. Der Grund für die 
Abfrage ist, daß das Interrupt-Flag auch bei deaktiviertem Interrupt 
gesetzt wird und der Interrupt-Code des deaktivierten Interrrups beim 
Auftreten eines anderen Interrupts fälschlicherweise ausgeführt wird.
Gast #776436
Lesenswert?

Ja, grundsätzlich läuft der. Ich kann ein Schalter einlesen und an 
diesem Port wieder ausgeben.

Wenn ich mir die Timervariable TMR0 anschaue, bleibt die immer auf dem 
geladenen Wert. Das Programm wird auch nicht durch einen Breakpoint in 
der ISR unterbrochen.
Gast #776481
Lesenswert?

Ich check das nicht ganz... Ich will ja nur den Timer 0 benutzen, den 
Watchdog nicht. Jetzt kommt natürlich ständig

CORE-W0003: Watchdog Timer event occurred. Break in execution requested

Ich brauch den Watchdog doch gar nicht grr
Persönliche Seite #776525
Lesenswert?

Braucht er auch nicht für den Timer0. Der wird im INTCON-Register 
gesetzt und abgefragt. Es muss also nur GIE und T0IE eingeschaltet 
werden, dann sollte er eigentlich in den Interrupt springen.

Für mich klingt das eher danach, als ob der Timer0 nicht auf internen 
Takt geschaltet ist. Dazu muss T0CS=0 sein. Steht das Bit auf 1 wartet 
der Timer0 auf einen Takt am externen PIN RA4.

Der WDT und der Timer0 benutzen beide den Prescaler! Wenn du beides 
einschaltest, werden die Ergebnisse unvorhersehbar sein, da der Timer0 
immer mal einen Interrupt auslöst und der WDT ein Reset (siehe Bild).

Ciao
Sven
Angehängte Dateien:
Gast #776539
Lesenswert?

Das hab ich auch alles so gemacht. Das Bild hab ich auch schon 
tausendmal angeschaut... langsam krieg ich ne Kriese.

Hier nochmal meine Konfiguration:

Oscillator: Internal RC No Clock
Watchdog Timer: Off
Power Up Timer: Off
Master Clear Enable: Internal
Brown Out Detect: On
Code Protection: Off
Data EE Read Protect: Off


Hier mein gesamter Code:
1
#include <htc.h>
2

3
main()
4
{
5
//Init
6
//static bit input,inputneu;
7

8

9
//Port Init
10
TRIS2 = 0; //Output
11
CMCON = 0x07;
12
GPPU = 0;
13
GPIO2 = 0;
14

15
//Timer 0 Init
16
T0SE = 0;  //Rising Edge
17
T0CS = 0;  //Clk Source
18
PSA = 0;  //Prescaler assigned to T0
19
PS0 = 1;  //Prescaler = 256
20
PS1 = 1;
21
PS2 = 1;
22
T0IF = 0;  //Clearing Interrupt
23
T0IE = 1;  //Interrupt Mask
24
GIE  = 1;  //Global Interrupt Enable
25
TMR0 = 128;  //Timer value
26

27
}
28

29
   void interrupt timer0_isr(void) {
30
    GPIO2 ^= 1;
31
    T0IF=0;
32
    TMR0=128;    //Laden
33
  }
Persönliche Seite #776541
Lesenswert?

Zum Auslösen des Timer0-Interrupts muss T0IE und GIE auf 1 gesetzt sein.

Wenn der Interrupt ausgelöst wird, setzt der PIC T0IF auf 1. Das ist für 
dein Programm die Stelle wo du schaust, welcher Interrupt ausgelöst hat. 
Da es nur einen Interruptvektor gibt musst du in der ISR die gesetzten 
Interruptbits auswerten (natürlich nur von den Interrupts, welche du 
eingeschaltet hast) um entscheiden zu können, in welche Routine du 
springst. In der ISR muss das entsprechende Interruptbit (also das 
xxxIF-Bit) wieder zurückgesetzt werden bevor du aus der ISR springst. 
Sonst wird gleich wieder ein Interrupt ausgelöst. Das ist aber alles nur 
auf Assembler bezogen, da ich C nicht kann. Mag sein, dass einiges davon 
der C-Compiler selbst macht.

Also TOIE und GIE auf 1. Wenn Interrupt auftritt, T0IF ggf. auswerten 
und zurücksetzen.

Sven
Persönliche Seite #776550
Lesenswert?

Dann fällt mir eigentlich nur noch ein, dass du bedenken musst, dass das 
Timer0-Register nur alle 256 Takte (also 256 Assemblerbefehle) um eins 
weiterzählt. Falls du also zum Testen des Proggs eine Simulation benutzt 
und das Prog in Einzelschritten durch gehst, wirst du erst nach 256 
Befehlen eine Veränderung des Timer0 Registers bemerken. Das 
Prescalerregister kann man nicht sehen. Oder mal einen anderen PIC 
probieren. Welchen benutzt du eigentlich?

Sven

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren