Forum: Mikrocontroller und Digitale Elektronik Pic18f4580 PWM Frequenz


von picPWM (Gast)


Lesenswert?

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 :/

von Rätz (Gast)


Lesenswert?

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?

von picPWM (Gast)


Lesenswert?

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.

von picPWM (Gast)


Lesenswert?

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
}

von Max H. (hartl192)


Lesenswert?

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.

von picPWM (Gast)


Lesenswert?

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

von picPWM (Gast)


Lesenswert?

An der Frequenz hat sich leider nichts geändert. Immer noch ca. 600Hz

von picPWM (Gast)


Lesenswert?

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.

von picPWM (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.