Forum: Mikrocontroller und Digitale Elektronik Nur ein Interrupt beim PIC12F629?


von Jürgen (Gast)


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)

von Analog (Gast)


Lesenswert?

ich bin nicht sicher, aber ich glaube du hast nur einen handler. In 
diesem musst Du per If-Abfrage alles managen.

von Jürgen (Gast)


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
  }

von Analog (Gast)


Lesenswert?

mehr details

kommt ne fehlermeldung ? Was passiert ?

von Jürgen (Gast)


Lesenswert?

Nein, ich kanns kompilieren.

Die Interruptroutine wird aber nie aufgerufen.

Hab ich da noch ein Flag vergessen zu initialisieren?

von Jürgen (Gast)


Lesenswert?

Oder muss ich noch was einbinden um Interrupts zu benutzen?

von holger (Gast)


Lesenswert?

>Die Interruptroutine wird aber nie aufgerufen.

Wenn GPIO2 nicht toggelt:
TRIS richtig gesetzt ?
CMCON auf 0x07 gesetzt ?

von Jürgen (Gast)


Lesenswert?

Ja hab ich

TRIS2 = 0; //Output
CMCON = 0x07;

von Analog (Gast)


Lesenswert?

void interrupt timer0_isr(void)
{



  T0IF = 0;
}

von Analog (Gast)


Lesenswert?

probier mal anstatt interrupt timer0_int doch lieber interrupt 
timer0_isr

von Analog (Gast)


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.

von Jürgen (Gast)


Lesenswert?

Aber wie du ja gesagt hast ist der Name nach "interrupt" egal...

von holger (Gast)


Lesenswert?

Läuft der PIC überhaupt ?
Wie sieht dein Configurationword aus ?

von Analog (Gast)


Lesenswert?

achso lad mal TMR0 wieder mit 128 in der ISR so läuft der nicht wieder 
weiter

von Jürgen (Gast)


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.

von Analog (Gast)


Lesenswert?

Toggle mal den GPIO nicht, sondern setze in nur auf High und miß mal mit 
dem Oszi oder dem Multimeter. Dann weißt Du ob er wirklich nicht 
reingesprungen ist.

von Analog (Gast)


Lesenswert?

Probier mal diese Einstellung

  T0CS = 0;      // select internal clock
  T0IE = 0;      // enable timer interrupt
  GIE = 1;      // enable global interrupts

von Jürgen (Gast)


Lesenswert?

Hab ich gemacht, der wird nie 1!

von Analog (Gast)


Lesenswert?

T0IE = 0;      // enable timer interrupt

von Jürgen (Gast)


Lesenswert?

Muss T0IE nicht 1 sein? Ist doch das Enable bit für den Timer0 
Interrupt.

von Jürgen (Gast)


Lesenswert?

Ich hatte bei den Konfigurationsbit den Watchdog Timer auf Off 
geschaltet. Mit On gehts!! Wusst nicht das der direkt mit dem Timer0 
zusammenhängt?

von Analog (Gast)


Lesenswert?

das stimmt hab ich verbaselt. Aber ich sehe gerade das Du den PIE1 gar 
nicht gesetzt hast

von Analog (Gast)


Lesenswert?

Datasheet Seite 31

von Jürgen (Gast)


Lesenswert?

PIE1 ist doch nur für Timer 1

von Analog (Gast)


Lesenswert?

Was jetzt ? Timer0 dann muss T0IE gecleared werden, steht im Datenblatt.

von Analog (Gast)


Lesenswert?

bit clear = 0

von holger (Gast)


Lesenswert?

@ Jürgen
Hör nicht auf Analog.

Das einzige was TMR0 anhalten könnte ist ein Sleep
Befehl. Der WDT startet den Timer dann wieder.
Steht irgendwo ein Sleep in deinem Code ?

von Jürgen (Gast)


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

von Jürgen (Gast)


Lesenswert?

Nö kein Sleep (noch nicht)

von Jürgen (Gast)


Lesenswert?

Kann mir jemand sagen was ihr bei der Configuration konkret einstellt?

Und muss das T0IE jetzt 1 oder 0 sein?

von Analog (Gast)


Lesenswert?

0. probieres doch einfach aus.

von Sven S. (stepp64) Benutzerseite


Angehängte Dateien:

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

von Jürgen (Gast)


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
  }

von Sven S. (stepp64) Benutzerseite


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

von Sven S. (stepp64) Benutzerseite


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

von Sven S. (stepp64) Benutzerseite


Lesenswert?

Ach ja, deine Routine hat keine Hauptschleife. Eventuell liegt es ja 
auch daran ?!?

von Jürgen (Gast)


Lesenswert?

Hab's auch mit dem KO angeschaut. Benutze den PIC12F629.

von Hugo (Gast)


Lesenswert?

Wie wärs denn am Ende Deiner Main mit einem

while (1)

{


}

was passiert denn da eigentlich ? Nach der Initialisierung beendet der 
Controller seine Arbeit

von Jürgen (Gast)


Lesenswert?

Ach du SCHEISSE!

Tatsächlich, ein while(1) eingefügt und es geht.

Sorry leute, hab ich überhaupt nicht dran gedacht dass das nötig ist!

Vielen Dank an alle!!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.