Hallo Forum, Für einen Drehzahlmesser habe ich eine Schaltung entworfen bei der ich den PORTC2 als PWM-Ausgang nutze und den PORTD4 für den Capture-Modus um die Periode der Frequenz zu ermitteln.Zum programmieren nutze ich C18 von Microchip. (PIC18F448) Sind die Einstellungen für diesen Modus denn so richitg? es scheint als wird kein Interrupt ausgelöst. OpenTimer3( TIMER_INT_OFF & T3_SOURCE_INT ); OpenECapture1( CAPTURE_INT_ON & EC1_EVERY_FALL_EDGE); TRISD = 0x10; //PD4:Frequenzzähler vorrübergehend habe ich einen Taster zum erzeugen der Flanken in Betrieb. Bei der Interrupt-routine bin ich mir nicht sicher ob die so auszusehen hat. Woher weiß ich welche Priorität der Capture-Interrupt hat. in C und mit C18 habe ich leider noch keine Interrupts programmiert, nur in Assambler , gibt es eine möglichkeit die Konfiguration des Capture-Modus in Assambler zu schreiben? /** I N T E R R U P T S *******************************************/ #pragma interruptlow InterruptHandlerlow void InterruptHandlerlow (void) { LED_Toggle(); } #pragma code _HIGH_INTERRUPT_VECTOR = 0x000008 void _high_ISR (void) { _asm goto InterruptHandlerlow // Sprung zur Interruptroutine _endasm } #pragma code _LOW_INTERRUPT_VECTOR = 0x000018 void _low_ISR (void) { _asm goto InterruptHandlerlow // Sprung zur Interruptroutine _endasm } vielen Dank für jede Hilfe
Hi, ich bin mir gerade nicht sicher aber muss das GIE eventuell separat eingestellt werden? Die Priorität kannst Du einstellen (im IPR Register) aber spielt bei dir keine Rolle, da beide Interrupts zum selben Ziel führen:
1 | goto InterruptHandlerlow // Sprung zur Interruptroutine |
Hier zur Priorität:
1 | IPR1bits.CCP1IP = 1; //High priority |
Und dann evtl. nochmal das:
1 | INTCONbits.GIE = 1; //Interrupts enable |
ich hab diese Konfiguration jetzt. Kann das hinhauen? void main(void) { INTCONbits.GIE = 1; // Interrupts erlaubt INTCONbits.PEIE = 1; // Peripheral Interrupts erlaubt INTCONbits.INT0IE = 1; //INT0 Interr.. PIE2bits.ECCP1IE = 1; // Interrupt on ECCP1 aktiv RCONbits.IPEN = 1; // high/low Prioritäten aktiv ECCP1CONbits.ECCP1M3 = 0;// Capture-Modi, fallende Flanke ECCP1CONbits.ECCP1M2 = 1; ECCP1CONbits.ECCP1M1 = 0; ECCP1CONbits.ECCP1M0 = 0; dazu diese Interrupt-routine, aber irgendwie kommt wieder kein interrupt:-(( #pragma interruptlow InterruptHandlerlow void InterruptHandlerlow (void) { Schaltblitz_Toggle(); } #pragma code _HIGH_INTERRUPT_VECTOR = 0x000008 void _high_ISR (void) { _asm goto InterruptHandlerlow // Sprung zur Interruptroutine _endasm } #pragma code _LOW_INTERRUPT_VECTOR = 0x000018 void _low_ISR (void) { _asm goto InterruptHandlerlow // Sprung zur Interruptroutine _endasm } die Prioritäten spielen später eine Rolle, da kommt noch bissel was dazu. aber erstmal soll der interrupt funktionieren...:-(
Poste bitte mal den gesamten Code und zwar in die Klammern dafür [ c ] Code [ / c ] (Dann natürlich ohne Leerzeichen) Gruß Nico
hier ist der gesamte Code. hoffe das hilft mir zu helfen:-)
1 | /** I N C L U D E S **********************************************************/
|
2 | #include "p18cxxx.h" |
3 | #include "delays.h" // für die Warteschleife |
4 | #include "adc.h" |
5 | #include "pwm.h" |
6 | #include "timers.h" |
7 | #include "capture.h" |
8 | #include "stdio.h" |
9 | #include "portb.h" |
10 | |
11 | #define Schaltblitz LATBbits.LATB7 // reine Erleichterung im Codê
|
12 | #define R_4 LATEbits.LATE2
|
13 | #define R_3 LATEbits.LATE1 // reine Erleichterung im Codê
|
14 | #define R_2 LATEbits.LATE0
|
15 | #define R_1 LATAbits.LATA5
|
16 | #define Ge_4 LATAbits.LATA3
|
17 | #define Ge_3 LATAbits.LATA2
|
18 | #define Ge_2 LATAbits.LATA1
|
19 | #define Ge_1 LATCbits.LATC0
|
20 | #define G_17 LATCbits.LATC1
|
21 | #define G_16 LATCbits.LATC3
|
22 | #define G_15 LATDbits.LATD0
|
23 | #define G_14 LATDbits.LATD1
|
24 | #define G_13 LATDbits.LATD2
|
25 | #define G_12 LATCbits.LATC4
|
26 | #define G_11 LATCbits.LATC5
|
27 | #define G_10 LATBbits.LATB5
|
28 | #define G_9 LATBbits.LATB4
|
29 | #define G_8 LATBbits.LATB1
|
30 | #define G_7 LATDbits.LATD7
|
31 | #define G_6 LATDbits.LATD6
|
32 | #define G_5 LATDbits.LATD5
|
33 | #define G_4 LATAbits.LATA4
|
34 | #define G_3 LATCbits.LATC7
|
35 | #define G_2 LATCbits.LATC6
|
36 | #define G_1 LATBbits.LATB6
|
37 | #define Zuendunterbrecher LATDbits.LATD3 // reine Erleichterung im Codê
|
38 | #define Schaltblitz_Toggle() Schaltblitz = !Schaltblitz; // reine Erleichterung im Codê
|
39 | |
40 | |
41 | void main (void); |
42 | void InterruptHandlerhigh (void); |
43 | void InterruptHandlerlow (void); |
44 | |
45 | |
46 | /** Configuration ********************************************************/
|
47 | #pragma config OSC = HS //CPU=20 MHz
|
48 | #pragma config PWRT = ON
|
49 | #pragma config BOR = OFF
|
50 | #pragma config WDT = OFF //Watchdog Timer
|
51 | #pragma config LVP = OFF //
|
52 | |
53 | |
54 | /** I N T E R R U P T S *******************************************/
|
55 | |
56 | #pragma interruptlow InterruptHandlerlow
|
57 | void InterruptHandlerlow (void) |
58 | {
|
59 | |
60 | Schaltblitz_Toggle(); |
61 | }
|
62 | |
63 | #pragma code _HIGH_INTERRUPT_VECTOR = 0x000008
|
64 | void _high_ISR (void) |
65 | {
|
66 | _asm
|
67 | goto InterruptHandlerlow // Sprung zur Interruptroutine |
68 | _endasm
|
69 | }
|
70 | |
71 | #pragma code _LOW_INTERRUPT_VECTOR = 0x000018
|
72 | void _low_ISR (void) |
73 | {
|
74 | _asm
|
75 | goto InterruptHandlerlow // Sprung zur Interruptroutine |
76 | _endasm
|
77 | }
|
78 | |
79 | |
80 | /** D E C L A R A T I O N S **************************************************/
|
81 | #pragma code
|
82 | |
83 | |
84 | |
85 | |
86 | void main(void) |
87 | {
|
88 | INTCONbits.GIE = 1; // Interrupts erlaubt |
89 | INTCONbits.PEIE = 1; // Peripheral Interrupts erlaubt |
90 | INTCONbits.INT0IE = 1; //INT0 External Interrupt erlaubt |
91 | PIE2bits.ECCP1IE = 1; // Interrupt on ECCP1 aktiv |
92 | RCONbits.IPEN = 1; // high/low Prioritäten aktiv |
93 | |
94 | ECCP1CONbits.ECCP1M3 = 0; |
95 | ECCP1CONbits.ECCP1M2 = 1; |
96 | ECCP1CONbits.ECCP1M1 = 0; |
97 | ECCP1CONbits.ECCP1M0 = 0; |
98 | |
99 | |
100 | |
101 | OpenTimer1( TIMER_INT_OFF & |
102 | T1_SOURCE_EXT & |
103 | T1_PS_1_8 & |
104 | T1_OSC1EN_OFF & |
105 | T1_SYNC_EXT_OFF & |
106 | T1_CCP1_T3_CCP2); |
107 | |
108 | OpenPWM1 (0xff); |
109 | SetDCPWM1(0x0200); |
110 | |
111 | OpenTimer3( TIMER_INT_OFF & |
112 | T3_SOURCE_INT ); |
113 | |
114 | |
115 | |
116 | |
117 | TRISA = 0x41; //RA0:Öltemp RA6:Ozillator |
118 | TRISB = 0x0D; //PB1:Fussschalter RB2/RB3:Can-Bus |
119 | TRISC = 0x00; //RC2:PWM |
120 | TRISD = 0x10; //PD4:Frequenzzähler PD3:Zündunterbrecher |
121 | TRISE = 0x00; // |
122 | |
123 | |
124 | while(1) |
125 | {
|
126 | Delay10KTCYx(100); |
127 | G_1 = !G_1; |
128 | }//while(1)-Schleife |
129 | }// Main-Schleife |
Also in der ISR fehlt, dass Du das IF-Flag, welches den Interrupt auslöst wieder löschst. Deine Version:
1 | void InterruptHandlerlow (void) |
2 | {
|
3 | |
4 | Schaltblitz_Toggle(); |
5 | }
|
Ich würde es so schreiben:
1 | void InterruptHandlerlow (void) |
2 | {
|
3 | if(INTCONbits.INTCON)INTCONbits.INTCON=0; |
4 | |
5 | |
6 | if(PIR2bits.ECCP1IF) |
7 | {
|
8 | Schaltblitz^=Schaltblitz; |
9 | PIR2bits.ECCP1IF=0; |
10 | }
|
11 | }
|
Sonst hast Du das Problem, dass wenn der Interrupt vorbei ist, das Flag ja immer noch anzeigt, dass es einen Interrupt gibt und somit kommt das Programm nicht mehr aus der ISR heraus. Probiere das erst mal, wenn es dann immer noch nicht klappt, sehen wir weiter. PS: Warum ist der INT0 erlaubt? Für später, wenn ja hat er dann einen definierten Zustand z.Z - sprich pull up/down? Gruß Nico
Ups hab da einen Tippfehler, muss so heißen:
1 | if(INTCONbits.INT0IF)INTCONbits.INT0IF=0; |
Ist das hier so gewollt?:
1 | TRISB = 0x0D; //PB1:Fussschalter RB2/RB3:Can-Bus |
Denn Eingänge sind hier B2,B3 und B0 nicht B1 Außerdem fällt mir gerade noch auf, dass Du für den Timer1 die externe Quelle gewählt hast, dann musst du an C0 und C1 einen Takt anschließen und außerdem die entsprechenden Tris Bits auf 1 setzten (input). Das stimmt bei dir nicht überein. Gruß Nico
also endlich funktioniert der interrupt:-) vielen dank dafür. aber er funzt nich immer:-( bzw. ich glaube es liegt vielleicht an dem nichtentprellten Taster. das werd ich später im motorrad genau sehen. wegen dem PORTB, falsches Kommentar von mir, RB0 ist der fussschalter die Sache mit dem Timer muss ich natürlich berichtigen. und für die die es Interresiert: INT0 ist für später schon mal aktiviert.Ziel: ein Schaltautomat> Hochschalten ohne Kumpeln und Gas wegnehmen, einfach den nächsten gang "reinziehen". das ermöglicht schaltzeiten jenseits von gut und böse:-)) Eine verständisfrage drängt sich mir dann doch aber noch auf. ich möchte die Zeit zwischen zwei Flanken messen. Das heißt doch: eine Flanke kommt> Interrupt wird ausgelöst>Zeit beginnt zu zählen> nächster Interrupt>??wo ist das ergebnis jetzt zu finden. muss ich den Timer auslesen oder das Register vom ECCP? das hab ich leider noch nich ganz verstanden?
Das Programm läuft danke eurer Hilfe jetzt fast. setzt sich der Timer von allein wieder auf null oder sollte ich das direkt als ersten schritt im Interrupt machen? kann ich mir irgendwie in c18 anschauen wie viel befehle in welcher zeit abgearbeitet werden. scheinbar gibts da irgendwo probleme, denn bei gleichbleibender Drehzahl schwankt meine Anzeige über den kompletten Bereich.ich dacht erst das der PIC dann von einem Interrupt zum nächsten nicht hinterher kommt aber ich hab mindestens 25000 Befehle Zeit das sollte doch genügen? Interrupt-Service-Routine
1 | #pragma interruptlow InterruptHandlerlow
|
2 | void InterruptHandlerlow (void) |
3 | {
|
4 | if(INTCONbits.INT0IF) |
5 | {
|
6 | INTCONbits.INT0IF=0; // Externer Interrrupt an INT0 |
7 | }
|
8 | |
9 | |
10 | if(PIR2bits.ECCP1IF) // Externer Interrupt an ECCP1 |
11 | {
|
12 | |
13 | WriteTimer3(0x0000); |
14 | Ergebnis = (ECCPR1H << 8) + ECCPR1L; |
15 | |
16 | Merker = 1; |
17 | |
18 | PIR2bits.ECCP1IF=0; |
19 | }
|
20 | |
21 | }
|
der Teil der einmal nach dem Interrupt ausgeführt wird.
1 | while(Merker) |
2 | {
|
3 | |
4 | Zahl = -150000/Ergebnis + 33; |
5 | if (Zahl<0) |
6 | {
|
7 | Zahl= 0; |
8 | }
|
9 | if (Zahl>25) |
10 | {
|
11 | Zahl = 25; |
12 | }
|
13 | |
14 | LATA = 0x01; |
15 | LATB = 0x0D; |
16 | LATC = 0x00; |
17 | LATD = 0x00; |
18 | LATE = 0x00; |
19 | |
20 | switch(Zahl) |
21 | {
|
22 | case 1: R_4 =1; |
23 | case 2: R_3 =1; |
24 | case 3: R_2 =1; |
25 | case 4: R_1 =1; |
26 | case 5: Ge_4=1; |
27 | case 6: Ge_3=1; |
28 | case 7: Ge_2=1; |
29 | case 8: Ge_1=1; |
30 | case 9: G_17=1; |
31 | case 10:G_16=1; |
32 | case 11:G_15=1; |
33 | case 12:G_14=1; |
34 | case 13:G_13=1; |
35 | case 14:G_12=1; |
36 | case 15:G_11=1; |
37 | case 16:G_10=1; |
38 | case 17:G_9 =1; |
39 | case 18:G_8 =1; |
40 | case 19:G_7 =1; |
41 | case 20:G_6 =1; |
42 | case 21:G_5 =1; |
43 | case 22:G_4 =1; |
44 | case 23:G_3 =1; |
45 | case 24:G_2 =1; |
46 | case 25:G_1 =1; |
47 | }
|
48 | Merker = 0; |
49 | } // while(Merker) |
Hi Christoph, mich irritieren jetzt noch zwei Dinge. Erstens: Ich bin mir nicht sicher ob das richtig funktioniert:
1 | Ergebnis = (ECCPR1H << 8) + ECCPR1L; |
Mach das mal zum Testen lieber so:
1 | Ergebnis = ECCPR1H; |
2 | Ergebnis = Ergebnis<<8; |
3 | Ergebnis = Ergebnis + ECCPR1L; |
Zweitens: Wieso setzt Du hier den Timer3 zurück?
1 | WriteTimer3(0x0000); |
...denn Du verwendest den Timer1 als Zähler für das CCP:
1 | OpenTimer1( TIMER_INT_OFF & |
2 | T1_SOURCE_EXT & |
3 | T1_PS_1_8 & |
4 | T1_OSC1EN_OFF & |
5 | T1_SYNC_EXT_OFF & |
6 | T1_CCP1_T3_CCP2); |
Durch T1_CCP1_T3_CCP2 wird Timer1 die Quelle für das CCP1 Modul. Viele Grüße Nico
Nachtrag: Der Timer wird automatisch zurück gesetzt. (siehe: http://www.pic-projekte.de/Bilder/PIC_Tutorial/Timer_CCP_Reset.PNG)
ich benutzte für den Capture-Modus doch ECCP1 werd die vorschläge gleich mal ausprobieren danke
Christoph Herzog schrieb: > ich benutzte für den Capture-Modus doch ECCP1 Ja genau und deshalb fragte ich mich warum Du den Timer3 zurück setzt, denn der Timer1 ist die Quelle für das ECCP1 Modul bei Dir, siehe: >> T1_CCP1_T3_CCP2 Gruß Nico
das Zurücksetzten ist jetzt beseitigt und an sich funktioniert auch alles. Nur das Auslesen der beiden ECCP1-Register ist noch nich richtig.
1 | long short Ergebnis; |
2 | unsigned int Zahl; |
3 | unsigned char Merker; |
4 | |
5 | /** I N T E R R U P T S *******************************************/
|
6 | |
7 | #pragma interruptlow InterruptHandlerlow
|
8 | void InterruptHandlerlow (void) |
9 | {
|
10 | |
11 | if(PIR2bits.ECCP1IF) // Externer Interrupt an ECCP1 |
12 | {
|
13 | Ergebnis = 0; |
14 | Ergebnis = ECCPR1H; |
15 | Ergebnis = Ergebnis<<8; |
16 | Ergebnis = Ergebnis + ECCPR1L; |
17 | if ( Ergebnis > 30000) |
18 | Schaltblitz = 1; |
19 | else
|
20 | Schaltblitz = 0; |
21 | |
22 | |
23 | Zahl = 150000/Ergebnis ; |
24 | Merker = 1; |
25 | |
26 | PIR2bits.ECCP1IF=0; |
27 | }
|
28 | |
29 | }
|
die if(Ergebnis >30000)-Schleife soll nur eine Kontrolle sein. Das ankommende Signal ist konstant und der zähler müsste immer etwa auf 32500 kommen. Aber der Schaltblitz flackert. Das heißt also das die Zahl andauert kleiner ist. ich kann mir aber noch nicht erklären warum. Ich glaube es gibt dafür nur noch zwei gründe. Entweder übertrage ich das Ergebnis falsch aus dem ECCP1modul in meine Variable oder der Timer läuft ständig über und hat dadurch auch mal werte unter 30000. Die Rechnung und Anzeige funzt<<getestet...
kann der Fehler vielleicht daran liegen das ich CCP1 für eine Pulsweitenmodulation nehme und gleichzeitig ECCP1 für den Capture modus?
Hi Christoph, also das Auslesen des ECCPR1L/H Register ist auf jeden Fall korrekt. Was mir gerade ein bisschen Kopfschmerzen bereitet ist folgendes: 1. Versuche doch mal wirklich in der ISR, den Timer1 zu resetten. Ich glaube meine Aussage zum autom. Reset gilt nur beim Special Event Trigger (ist bei dir nicht so konfiguriert). Also in die ISR nochmal den Code einbauen und zwar als erstes in die if Schleife:
1 | TMR1L = TMR1H = 0; // Timer1 Reset |
2. Schau mal:
1 | OpenTimer1( TIMER_INT_OFF & |
2 | T1_SOURCE_EXT & |
3 | T1_PS_1_8 & |
4 | T1_OSC1EN_OFF & |
5 | T1_SYNC_EXT_OFF & |
6 | T1_CCP1_T3_CCP2); // <----- 2xCCP und kein ECCP? |
Im Prinzip ist das ja wunderbar aber Du hast ja ein CCP und ein ECCP Modul in deinem PIC. Vielleicht geht die Verwendung der C18 Librarie ja nur wenn man zwei CCP Module hat, denn hier steht nur 2xCCP und nicht ECCP:
1 | T1_CCP1_T3_CCP2
|
Aber das ist nur eine Vermutung. 3.Und wenn das auch nicht hilft, vermute ich, dass Du ne Null in Mathe bist ;) Spaß... Kannst du messen in Welchen Abständen (genau) ein Signal (Tacho..) am Pin ankommt? Gruß Nico
die Abstände betragen 50ms. das heißt bei 20Mhz /4 = 5Mhz> vorteiler 8 dann sind wir bei 1,6µs Pro Digit. und bei 50ms/1,6µ sind das für den Timer 31250. Die Sache mit der Librarie werd ich gleich mal unter die Lupe nehmen, danke für die tips:-)
Okay die Rechnung stimmt, wenn wirklich alle 50ms ein Impuls kommt. Wie gesagt versuch zuerst mal den Timer1 zu resetten.. Nachtrag: Man muss den TMR1 wirklich zurück setzten!!
scheinbar funzt die ganze geschichte jetzt. leider kann ich das eingangssignal nicht wirklich ändern. also werde ich mich morgen aufs fahrrad schwingen die 15km bis zu meinem motorrad in angriff nehmen und die ganze schaltung am lebenden objekt ausprobieren. sollte die geschichte funktionieren stell ich den Code für ähnliche grünschnäbel wie mich hier bereit.
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.