Guten Tag, zur Zeit versuche ich mit einem PIC18f4580 eine PWM Frequenz zu erzeugen. Soweit eigentlich nicht schwer, allerdings stimmen meine Rechnungen nicht mit meinen Messungen auf dem Oszilloskop überein, obwohl ich mir sehr sicher bin, dass ich mich nicht verreichnet habe. Bei einer berechneten PWM Frequenz (Duty cycle 50%) von 400Hz bekomme ich am Ausgang laut Oszilloskop 600Hz. Bei 1000Hz habe ich noch 70Hz Abweichung. Ich verstehe alerdings nicht warum. - 10Mhz Pic 18f4580 - Timer 1 : Prescaler 1:1 und Vorteiler 4 - Compare Modus. Timer 1 wird inkrementiert und bei einem Interrupt erzeugt dieser einen Interrupt, in dem von High nach Low bzw. umgekehrt gewechselt wird. Meine Rechnung : Bei einem Takt von 10Mhz und einem Vorteiler von 4 wird der Timer1 alle 0.0000004s um eine Stelle erhöht. Um mit dem Compare Modul auf 400Hz zu kommen habe ich folgendermaßen gerechnet: 1/400Hz = 0.0025s Periode. Für einen Duty cycle von 50% sind das dann 0.00125s High und 0.00125s Low. Also muss mein Timer1 alle 0.00125s einen Interrupt erzeugen. Das wären dann 0.00125 : 0.0000004 = 3125 Schritte. Diesen Wert habe ich als Hexzahl in das Vergleichsregister geschrieben. Also oxC35. Soweit müsste eigentlich alles passen aber anstatt 400Hz habe ich am Ausgang mit meinem Oszi 600Hz gemessen. Mit der gleichen Rechnung komme ich bei ox4E2 für 1000Hz auf eine Frequenz von 930Hz. Dafür habe ich aber keine Erklärung :/
Poste mal deinen Code. Nicht das du da nch irgendwas drinnenhast, das Rechenleistung kostet. Das das Laden de Timers usw. auch min 12 Takte in Anspruch nimmt, ist dir klar?
Rätz schrieb: > Poste mal deinen Code. > Nicht das du da nch irgendwas drinnenhast, das Rechenleistung kostet. > Das das Laden de Timers usw. auch min 12 Takte in Anspruch nimmt, ist > dir klar? Mache ich gerne. Nur noch kurz etwas übersichtlicher gestalten.
1 | #pragma config OSC=HS //HighSpeed Quarz 10MHz without PLL
|
2 | #pragma config FCMEN = OFF //FailSafe aus (schaut ob quarz tut)
|
3 | #pragma config IESO = OFF //Oscillator Switchover mode disabled
|
4 | #pragma config PWRT = OFF //PowerUp Timer disabled
|
5 | #pragma config BOREN = BOACTIVE //BrownOut ist hardwaremäßig an und im sleep deaktiviert
|
6 | #pragma config BORV = 1 //VBOR set to 4.3V
|
7 | #pragma config WDT = OFF //Watchdog aus
|
8 | #pragma config MCLRE = ON //MCLR ist an; RE3 ist deaktiviert
|
9 | #pragma config LVP = OFF //AUSSCHALTEN!!!!! wichtig!!!! sonst geht PORTB.RB5 nicht richtig (floatet)
|
10 | #pragma config PBADEN = OFF //PORTB als digital i/o bei reset
|
11 | #pragma config CPD = OFF //WriteProtection aus
|
12 | #pragma config WRTD = OFF //WriteProtection aus
|
13 | #pragma config WRTC = OFF
|
14 | |
15 | |
16 | #pragma interrupt InterruptHandlerHigh
|
17 | void InterruptHandlerHigh (void) |
18 | {
|
19 | |
20 | if(PIR1bits.CCP1IF){ //Check if Timer1 Compare IR |
21 | |
22 | |
23 | if(CCP1CON == 0b1000){ // wechsle von low nach high |
24 | CCP1CON = 0b1001; |
25 | }
|
26 | |
27 | else{ // wechsle von high nach low |
28 | |
29 | CCP1CON = 0b1000; |
30 | }
|
31 | |
32 | TMR1H = 0x00; |
33 | TMR1L = 0x00; // High-Low Register gleichzeitig auf 0 gesetzt |
34 | |
35 | PIR1bits.CCP1IF = 0; // Interupt Flag CCP1 reset |
36 | }
|
37 | |
38 | #pragma code _HIGH_INTERRUPT_VECTOR = 0x000008
|
39 | void _high_ISR (void) |
40 | {
|
41 | _asm
|
42 | goto InterruptHandlerHigh // Sprung zur Interruptroutine |
43 | _endasm
|
44 | }
|
45 | |
46 | |
47 | void main(void){ |
48 | |
49 | int x; |
50 | |
51 | CCP1CONbits.CCP1M0 = 1; // Compare Modus mit Wechsel von H - L |
52 | CCP1CONbits.CCP1M1 = 0; |
53 | CCP1CONbits.CCP1M2 = 0; |
54 | CCP1CONbits.CCP1M3 = 1; |
55 | CCPR1 = 0xc35; // 0xC35 für 400Hz |
56 | TRISCbits.RC2 = 0; // PWM Ausgang |
57 | |
58 | INTCONbits.GIE_GIEH = 1;// Enable all High Priority Interupt |
59 | INTCONbits.PEIE_GIEL = 1; |
60 | RCONbits.IPEN = 1; // Enable Priority Interupts |
61 | IPR1bits.CCP1IP = 1; // Compare Interupt = High Priority |
62 | PIE1bits.CCP1IE = 1; // Interupt enabled |
63 | |
64 | |
65 | |
66 | // Ab hier Timer3 und ECCP-Modul
|
67 | |
68 | ECCP1CONbits.ECCP1M0 = 0; |
69 | ECCP1CONbits.ECCP1M1 = 1; |
70 | ECCP1CONbits.ECCP1M2 = 0; |
71 | ECCP1CONbits.ECCP1M3 = 1; |
72 | |
73 | ECCPR1 = 0x805; |
74 | |
75 | IPR2bits.ECCP1IP = 0; //Low Priority |
76 | PIE2bits.ECCP1IE = 1; // Enable IR |
77 | |
78 | |
79 | |
80 | |
81 | // T3CON = 0b10111001;
|
82 | T1CON = 0b10000001; |
83 | while(1){ |
84 | |
85 | x++; |
86 | }
|
87 | |
88 | }
|
picPWM schrieb: > if(CCP1CON == 0b1000){ // wechsle von low nach high > CCP1CON = 0b1001; > } > else{ // wechsle von high nach low > CCP1CON = 0b1000; > } Das könnte man schneller nachen indem man CCP1CON ^= 0x01; schreibt. Den Timer auf null setzten würde ich als erstes nach dem if in der ISR machen. Wieso nutzt du das CCP Modul im Compare Modus um ein PWM Signal zu erzeugen. Es hat ja auch einen PWM Modus und der ist wie der Name schon sagt genau dazu gemacht.
Wolte ich auch zuerst aber mit dem Compare Modul kann ich meine PWM Frequenz sehr genau einstellen und auch jede ganzzahlige Frequenz im Bereich von 400Hz - 2000 Hz erzeugen. Die einzelnen Frequenzen kann ich dann ganz einfach durchwechseln, indem ich einfach den einen Registerwert abändere. Mit dem PWM Modul kommt mir das viel komplizierter vor und ich bin mir auch nicht sicher, ob ich damit jede beliebige Frequenz erreichen kann, indem ich einfach nur einen Registerwert ändere. Ich werde schnell deine Empfehlungen umsetzen. Danke schonmal
Nachdem ich folgenden Codeteil auskommentiert habe, werden die 400Hz richtig erzeugt.
1 | // Ab hier Timer3 und ECCP-Modul
|
2 | |
3 | ECCP1CONbits.ECCP1M0 = 0; |
4 | ECCP1CONbits.ECCP1M1 = 1; |
5 | ECCP1CONbits.ECCP1M2 = 0; |
6 | ECCP1CONbits.ECCP1M3 = 1; |
7 | |
8 | ECCPR1 = 0x9897; |
9 | ECCPR1 = 0x16E3; |
10 | ECCPR1 = 0x805; |
11 | |
12 | IPR2bits.ECCP1IP = 0; //Low Priority |
13 | PIE2bits.ECCP1IE = 1; // Enable IR |
Warum genau verstehe ich noch nicht ganz.
Habe den Fehler gefunden. Hat sich somit erledigt. T3CON = 0b10111001; legt fest, dass Timer1 das CCP1 Modul steuert und Timer3 das ECCP1 Modul. Diese Zeile hatte ich auskommentiert, da ich zunächst nur die CCP1 Frequenz überprüfen wollte. Habe aber vergessen folgende zeilen ebenfalls auszukommentieren. ECCP1CONbits.ECCP1M0 = 0; ECCP1CONbits.ECCP1M1 = 1; ECCP1CONbits.ECCP1M2 = 0; ECCP1CONbits.ECCP1M3 = 1; Dadurch wurde das ECCP1 Modul ebenfalls von Timer1 gesteuert und hat einen zusätzlichen Interrupt ausgelöst.
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.