Hallo Mikrocontroller-Nutzer Mit dem PIC24F Starter Kit 1 möchte ich in C folgendes implementieren: Der secondary oscillator (32768 kHZ Quarz) soll jede Sekunde einen Interrupt auslösen und die LED umschalten. Grundlegend habe ich noch nicht verstanden, wie man eine ISR in C schreiben kann. Im web habe ich gelesen, dass dies so gehen soll: #define _ISR__attribute__((interrupt)) #define _ISRFAST__attribute__((interrupt, shadow)) void _ISR _T1Interrupt (void); Doch die zwei define statements geben nur eine Fehlermeldung. Ohne diese macht wohl auch die Funktion keinen Sinn, doch ich habe den Code, so wie er im Moment aussieht, gepostet: #include <stdio.h> #include <stdlib.h> #include <p24Fxxxx.h> void _ISR _T1Interrupt (void); _CONFIG1( JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx2) _CONFIG2( FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMOD_XT & FNOSC_PRI) int a = 0; void _ISR _T1Interrupt (void){ a++; if(a%2==0){ PORTF=0xffff; PORTG=0xffff; } else{ PORTF=0x0000; PORTG=0x0000; } } int main(int argc, char** argv) { //Set all Ports in G and F as outputs. TRISG=0x0000; TRISF=0x0000; //set timer1 as interrupt generator T1CONbits.TON=1; //prescale ratio 1:1 T1CONbits.TCKPS=00; //ext. clock from pin T1CK (SOSCO) T1CONbits.TCS=1; //set interrupt priority high IPC0bits.T1IP2=1; IPC0bits.T1IP1=1; IPC0bits.T1IP0=1; // enable interrupt IEC0bits.T1IE=1; while(1){ } return (EXIT_SUCCESS); } Als vollkommener Anfänger bin ich um jeden Beitrag froh! Grüsse Davis
Das Wichtigste in der Interruptroutine fehlt - nämlich das Rücksetzen des Interruptflags mit < IFS0bits.T1IF = 0; > (möglich das bei deinem Controller das T1IF-Bit in einem anderen IFS-Register liegt -> siehe Datenblatt). Ansonst wird nämlich der Interrupt permanent aufgerufen d.h. das Programm bleibt in der ISR hängen. > Grundlegend habe ich noch nicht verstanden, wie man eine ISR in C > schreiben kann. Im web habe ich gelesen, dass dies so gehen soll: > > #define _ISR__attribute__((interrupt)) > #define _ISRFAST__attribute__((interrupt, shadow)) > void _ISR _T1Interrupt (void); Jaaa im Web wird viel geschrieben und es mögen einige dieser Schreibweisen auch richtig sein, ABER: die einzige verläßliche Quelle ist das User Manual deines Compilers!! Ein Variante ist z.B: void __attribute__((_interrupt_, _auto_psv_)) _T1Interrupt(void) ....für den XC16 Compiler, ob es der C30 "fressen" würde? keine Ahnung!
Hier mein Code für den PIC24F16KA102 geschrieben habe um das Timerinterrupt auszuprobieren, geschrieben für den XC16
1 | #include <xc.h> |
2 | |
3 | #define FOSC 32000000
|
4 | #define FCY (FOSC/2)
|
5 | |
6 | #include <libpic30.h> |
7 | |
8 | _FBS(BWRP_OFF) //Boot segment may be written |
9 | _FGS(GWRP_OFF & GCP_OFF) //General segment may be written & No protection |
10 | _FOSCSEL(FNOSC_PRIPLL & IESO_OFF) //Primary oscillator with PLL module (HS+PLL, EC+PLL) & Internal External Switchover mode disabled |
11 | _FOSC(POSCMOD_HS) //HS oscillator mode selected |
12 | _FWDT(FWDTEN_OFF) //WDT disabled (control is placed on the SWDTEN bit) |
13 | |
14 | unsigned int i,j; |
15 | unsigned char data=0x00; |
16 | int main( void) |
17 | {
|
18 | TRISB=0x0000; |
19 | LATB=0x0001; |
20 | AD1PCFG=0xFFFF; //All inputs digital |
21 | |
22 | //T1 init
|
23 | T1CONbits.TCS=0; //Internal clock (FOSC/2) |
24 | T1CONbits.TCKPS=0b11; //Prescaler 1:256 |
25 | T1CONbits.TON=1; //Starts 16-bit Timer1 |
26 | PR1=31249; //Peiod=315249 --> 500ms |
27 | //Init interrupt
|
28 | SRbits.IPL=0x00; //CPU interrupt priority level is 0 |
29 | IPC0bits.T1IP=0b111; //Interrupt is Priority 7 (highest priority interrupt) |
30 | IFS0bits.T1IF=0; //Clear T1 interrupt flag |
31 | IEC0bits.T1IE=1; //Enable T1 Interrupt |
32 | |
33 | while(1); |
34 | }
|
35 | void _ISRFAST _T1Interrupt(void) //Timer 1 ISR |
36 | {
|
37 | IFS0bits.T1IF=0; //Clear T1 interrupt flag |
38 | LATB++; |
39 | }
|
Hoffe, er kilft dir weiter.
:
Bearbeitet durch User
Vielen Dank für die schnellen Antworten! Chris B. schrieb: > Ein Variante ist z.B: > void __attribute__((interrupt, auto_psv)) _T1Interrupt(void) > ....für den XC16 Compiler, ob es der C30 "fressen" würde? keine Ahnung! Ich benütze ebenfalls den XC16 Compiler. Dessen Handbuch besagt: void __interrupt(auto_psv,(irq(3))) myIsr(void) {} da der Timer1 die Interrupt Vektornummer 3 hat. Doch es kommt der error "expected ')' before '(' token". Woran liegt das? Max H. schrieb: > #include <xc.h> > #include <libpic30.h> Wieso brauchst du diese h-Files? Max H. schrieb: > PR1=31249; //Peiod=315249 --> 500ms > //Init interrupt > SRbits.IPL=0x00; //CPU interrupt priority level is 0 Was bedeutet CPU interrupt priority? Was bedeutet PR1? Sehe ich das richtig, dass dein Timer 32000000/2/256=62500 Mal pro Sekunde einen Interrupt auslöst? Danke für euer Hilfe! Grüsse davis
Davis schrieb: > Max H. schrieb: >> #include <xc.h> >> #include <libpic30.h> > > Wieso brauchst du diese h-Files? xc.h ist ist das includefile von XC16 libpic30.h habe ich für die Delays integriert, die ich anscheinen irgendwann wieder gelöscht habe. > Was bedeutet CPU interrupt priority? Im dem IRP bits steht welche Priorität von Interrupts der PIC ausführen soll, alle Interrupts mit niedriger Priorität werde nicht ausgeführt. > Was bedeutet PR1? Wenn der Timer diesen Wert erreicht, wird er auf null gesetzt und löst das Interrupt aus. > Sehe ich das richtig, dass dein Timer 32000000/2/256=62500 Mal pro > Sekunde einen Interrupt auslöst? Nein, 2 mal pro Sekunden: 32000000/(2*256*(31249+1))=2
:
Bearbeitet durch User
@Max H. Vielen Dank für deine Geduld und die schnellen Antworten! @Chris B. Merci für diesen Link, der war sehr hilfreich. Grüsse Davis
Hallo miteinander Das selbe Unterfangen wie oben beschrieben möchte ich nun auf einem PIC24f04ka201 implementieren. Zuerst möchte ich, dass mit drei Knöpfen jeweils ein Interrupt ausgelöst werden kann. RB0,RB1 und RB2 habe ich also extern mit einem Knopf auf VCC gezogen. Der Code sieht so aus: #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <p24Fxxxx.h> _FOSCSEL (FNOSC_SOSC&IESO_OFF) _FOSC (POSCMOD_NONE&OSCIOFNC_ON) _FPOR(MCLRE_ON) _FICD (ICS_PGx2) int main(int argc, char** argv) { TRISB=0x0007; TRISA=0x0000; CNEN1=0x0070; CNEN2=0x0000; CNPU1=0; CNPU2=0; CNPD1=0x0070; CNPD2=0x0000; IEC1bits.CNIE=1; IFS1bits.CNIF=0; while(1){} return (EXIT_SUCCESS); } void __attribute__((_interrupt_, _shadow_, auto_psv)) _CNInterrupt(void) { IFS1bits.CNIF=0; if(PORTBbits.RB2) led1(2000); if(PORTBbits.RB1) led2(2000); if(PORTBbits.RB0) led3(2000); } Je nach Knopf sollte ein anderes LED leuchten. Bei RB2 funktioniert es wie gewünscht, aber bei den anderen beiden nicht. Hat jemand eine Idee, wo der Fehler liegen könnte? Müssen RB0 und RB1 zuerst auf digital geschaltet werden, da die AN inputs diese Ports teilen? Grüsse Davis
Davis schrieb: > Müssen RB0 und RB1 > zuerst auf digital geschaltet werden, da die AN inputs diese Ports > teilen? Ja, die Analog Pins sind nach dem Reset analog.
> Ja, die Analog Pins sind nach dem Reset analog.
Danke für diese schnelle Antwort. Welches Register beinhaltet diese
Information?
Grüsse Davis
AD1PCFG = 0xffff; // alles Digital Weiss nicht auswendig auf welchen Pin die Comperatoren liegen, aber zur Sicherheit auch abschalten: CM1CON = 0; CM2CON = 0;
Danke Chris B. und Max H.! Könnt ihr mir vielleicht auch beim Timer Interrupt helfen? int main(int argc, char** argv) { T1CON=0x00; T1CONbits.TON=1; T1CONbits.TCKPS=00; T1CONbits.TCS=1; T1CONbits.TSYNC=1; PR1=32767; IFS0bits.T1IF=0; IEC0bits.T1IE=1; IPC0bits.T1IP=111; TMR1=0x00; while(1){} return (EXIT_SUCCESS); } void __attribute__((_interrupt_, _shadow_, auto_psv)) _T1Interrupt(void) { IFS0bits.T1IF=0; LATBbits.LATB13=~LATBbits.LATB13; } Alle Configuration Bits sind dieselben wie oben. Am SOSC liegt ein Quartz mit 32768 Hz Frequenz an. Das LED über RB13 sollte jede Sekunde toggeln, unabhängig von den CN Interrupts. Leider passiert nichts... Grüsse Davis
Davis schrieb: > Am SOSC liegt ein Quartz mit 32768 Hz Frequenz an. Hoffentlich nicht nur der Quarz sondern auch die beiden Kondensatoren!? Bei den meisten (aber nicht allen) PIC24 muss der SOSC für die Peripherie (Timer 1 z.B.) noch freigeschaltet werden mit: OSCCONbits.SOSCEN = 1;
Chris B. schrieb: > Davis schrieb: >> Am SOSC liegt ein Quartz mit 32768 Hz Frequenz an. > > Hoffentlich nicht nur der Quarz sondern auch die beiden Kondensatoren!? > Ja, die liegen auch dran. Der Quarz sollte eigentlich soweit funktionieren, da der ganze Mikrocontroller mit diesem getaktet wird, sofern ich das richtig verstehe. > Bei den meisten (aber nicht allen) PIC24 muss der SOSC für die > Peripherie (Timer 1 z.B.) noch freigeschaltet werden mit: > OSCCONbits.SOSCEN = 1; Danke für diesen Hinweis, doch es geschieht noch immer nichts. Ist das PR1 Register richtig gesetzt oder muss man das binär oder hexadezimal setzen? Grüsse Davis
Watchdog abschalten sonst kommt immer ein Reset bevor 1 Sekunde abgelaufen ist (vermute ich, habe die WDT-Default Enstellung jetzt nicht nachgesehen). _FWDT (FWDTEN_OFF) Die Schreibweise beim PR-Register ist egal solange es der Compiler versteht...
Danke Chris B. für den Hinweis. Doch auch damit funktioniert es noch nicht (Default Einstellung war: WDT Postscale 1:32,768 WDT prescaler 1:128 windowed WDT disabled) Was könnte ich noch übersehen / falsch eingestellt haben? Danke für alle Antworten und Anregungen. Beste Grüsse Davis
> Was könnte ich noch übersehen / falsch eingestellt haben?
T1CONbits.TCS=1;
Dies war der springende Punkt.
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.