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)
ich bin nicht sicher, aber ich glaube du hast nur einen handler. In diesem musst Du per If-Abfrage alles managen.
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 | }
|
Nein, ich kanns kompilieren. Die Interruptroutine wird aber nie aufgerufen. Hab ich da noch ein Flag vergessen zu initialisieren?
>Die Interruptroutine wird aber nie aufgerufen.
Wenn GPIO2 nicht toggelt:
TRIS richtig gesetzt ?
CMCON auf 0x07 gesetzt ?
probier mal anstatt interrupt timer0_int doch lieber interrupt timer0_isr
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.
Aber wie du ja gesagt hast ist der Name nach "interrupt" egal...
achso lad mal TMR0 wieder mit 128 in der ISR so läuft der nicht wieder weiter
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.
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.
Probier mal diese Einstellung T0CS = 0; // select internal clock T0IE = 0; // enable timer interrupt GIE = 1; // enable global interrupts
Muss T0IE nicht 1 sein? Ist doch das Enable bit für den Timer0 Interrupt.
Ich hatte bei den Konfigurationsbit den Watchdog Timer auf Off geschaltet. Mit On gehts!! Wusst nicht das der direkt mit dem Timer0 zusammenhängt?
das stimmt hab ich verbaselt. Aber ich sehe gerade das Du den PIE1 gar nicht gesetzt hast
Was jetzt ? Timer0 dann muss T0IE gecleared werden, steht im Datenblatt.
@ 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 ?
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
Kann mir jemand sagen was ihr bei der Configuration konkret einstellt? Und muss das T0IE jetzt 1 oder 0 sein?
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
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 | }
|
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
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
Ach ja, deine Routine hat keine Hauptschleife. Eventuell liegt es ja auch daran ?!?
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.