Hallo, ich habe ein kleines Verständnissproblem zum PWM. Ein Codeschnipsel: /* MCU: PIC18F2525 * EC-Clock: 40.000 MHz * Compiler: MikroC PRO for PIC v.5.6.1 * LCD: HD44780 4x20 Zeichen */ CCP1CON = 0x0C; // PWM Register 0b00xy0000 wobei x,y <=> DC1B1,DC1B0 T2CON = 0b101; // Timer ON, Prescaler 4 PR2 = 0xFF; . . . int temp = 0b 0000 0000 0000 0000; CCPR1L = (temp >> 2); CCP1CON.DC1B1 = (temp & 1); CCP1CON.DC1B0 = (temp & 2); Ist das nun ein 10bit wertiges PWM-Signal oder nicht? Wenn nicht wie müsste es aussehen? Vielen Dank schonmal!
Ich nehme mal an deine temp Variable ist zwischen 0x000 und 0x3FF definiert? Also werden Bit 0-1 in das DC1Bn Register geschrieben.
>int temp = 0b 0000 0000 0000 0000;
Ja das stimmt natürlich, der Wert kann zwischen 0 und 1023 liegen,
also 0b0000 0011 1111 1111 als maximum.
Ich habe nur so im Beispiel nullen gewählt..
Also ist das jetzt richtig definiert oder ist das falsch?
>Also ist das jetzt richtig definiert oder ist das falsch?
Schau doch einfach mit dem Multimeter oder dem Osci nach.
Martin schrieb: > Ist das nun ein 10bit wertiges PWM-Signal oder nicht? Ich glaube nicht, weil ein 10bit Wert aus zwei 8 bit oder einem 16bit register besteht.
Also wenn der Wert "rightjustified vorliegt", dann hat der CCPR1L die 8 bits und der CCPR1H hat 2 bits. Und um sie zu verbinden muss man int temp=(CCPR1H<<8) + CCPR1L; machen. Aber der PIC18F2525 hat sowieso nur 8bit register, also wird das irgendwie wieder vom Compiler zerteilt. Also praktisch hat es keinen Nutzen.
Martin schrieb: > CCPR1L = (temp >> 2); > > CCP1CON.DC1B1 = (temp & 1); > > CCP1CON.DC1B0 = (temp & 2); Hier wird die CCPR1L um zwei stellen nach links verschoben.Dadurch fallen die zwei niedriegsten bits aus und dann wollte jemand die CCP1CON.DC1B1 und CCP1CON.DC1B0 bits an die leeren Stellen kopieren. Aber was hat CCP1CON.DC1B1 und CCP1CON.DC1B0 damit zu tun? Das ist falsch.Die zwei Bits müssen von CCPR1H kommen. Ich würde das so machen: CCPR1L = (CCPR1L >> 2); temp = (CCPR1H << 6) + CCPR1L; Dann sind es immer noch nicht volle 10bit aber nah dran.
Manchmal habe ich echt gute Ideen. Mein Algorithmus arbeitet perfekt.
Pulsweitenmodulation (PWM) PWM SignalJeder PIC18 und teilweise auch manche PIC16 besitzen das Capture, Compare, PWM (CCP) Modul mit dem man zusammen mit dem Timer2 ein Pulsweitenmoduliertes Signal (kurz PWM) erzeugen kann. Ich möchte Euch hier kurz erklären wie Ihr mit dem Modul umzugehen habt. Der Timer2 wird mit 1/4 des am PIC angeschlossenen Quarz Taktes gespeist und kann zusätzlich noch über einen Vorteiler des Timer2 in drei Stufen geteilt werden (1, 4, 16). Im Prinzip sind für den PWM Mode nur zwei Register von "Bedeutung": Das Register CCPR1L und PR2. Während der Timer2 immer bei 0 beginnt zu zählen wird der aktuelle Zählerstand (TMR2) immer mit dem Wert in PR2 und CCPR1L verglichen. Wenn der Zählstand des Timers dem Wert in CCPR1L entspricht, dann wird der CCP1 Ausgang (Pin) gelöscht, also auf Low (0V) gesetzt. Wenn der Wert dem in PR2 entspricht, dann wird der Ausgang auf High (=5V) gesetzt und der Timer2 beginnt wieder von 0 an zu zählen. Hier eine kleine Grafik zur Veranschaulichung (siehe rechts). Da man "10 Bit PWM" sagt aber der Timer2 und das PR2/CCPR1L Register ja eigentlich nur 8 Bit groß sind, bekommt das CCPR1L Register zwei zusätzliche Bits spendiert, welche im CCPCON Register übrig sind. Also lässt sich die Periode trotzdem nur mit 8 Bit einstellen (Timer2 und PR2) aber das Tastverhältnis kann in 10 Bit eingestellt werden. Vorgehensweise zum Nutzen des CCP Moduls zur PWM Erzeugung Timer2 einstellen Periode einstellen Tastverhältnis einstellen PWM aktivieren Beispiel am PIC18F4550 Nicht vergessen das CCP Pin zum Ausgang zu machen (TRISx=0) void PWM_Einstellung(void) { PR2=0xFF; // Größt mögliche Periodendauer CCPR1L=0xFF; // Hier wird das Tastverhältnis eingestellt CCP1CON=0x0C; // PWM Mode ausgewählt T2CON=0x79; // 1:16 Postscale, Timer2 aus, Prescale=4 T2CONbits.TMR2ON=1; // Timer2 an } Formel zum Errechnen der Periodendauer: PWM Period = [(PR2) + 1] 4 TOSC * (TMR2 Prescale Value) Formel zum Errechnen von PR2: PR2 = [ PWM_Periode / (4 x Tocs x TM2PS) ] -1 Formel zum Errechnen des Tastverhältnissis: CCPR1L / PR2 Anwendung: Jetzt könnte man das CCPR1L Register verändern und somit das Tastverhältnis beeinflussen. Ich benutze dies gerne um bei LCD Displays die Hintergrund Beleuchtung der Helligkeit im Raum anzupassen.
14.5.2 PWM DUTY CYCLE The PWM duty cycle is specified by writing to the CCPR1L register and to the CCP1CON<5:4> bits. Up to 10-bit resolution is available. The CCPR1L contains the eight MSbs and the CCP1CON<5:4> contains the two LSbs. This 10-bit value is represented by CCPR1L:CCP1CON<5:4>. The following equation is used to calculate the PWM duty cycle in time: PWM duty cycle = (CCPR1L:CCP1CON<5:4>) TOSC (TMR2 prescale value) CCPR1L and CCP1CON<5:4> can be written to at any time, but the duty cycle value is not latched into CCPR1H until after a match between PR2 and TMR2 occurs (i.e., the period is complete). In PWM mode, CCPR1H is a read only register. 14.5.3 SETUP FOR PWM OPERATION The following steps should be taken when configuring the CCP module for PWM operation: 1. Set the PWM period by writing to the PR2 register. 2. Set the PWM duty cycle by writing to the CCPR1L register and CCP1CON<5:4> bits. 3. Make the CCP1 pin an output by clearing the TRISC<2> bit. 4. Set the TMR2 prescale value and enable Timer2 by writing to T2CON. 5. Configure the CCP1 module for PWM operation. Das bedeutet, dass dieses Code teilweise richtig ist.Da wird auf CCPR1L und CCP1CON<5:4> bits geschrieben.Aber was da geschrieben wird ist mir nicht ganz klar. CCPR1L = (temp >> 2); CCP1CON.DC1B1 = (temp & 1); CCP1CON.DC1B0 = (temp & 2);
Hallo, danke schonmal für die bisherige Hilfe! Mal angenommen ich setze CCPR1L = 0xFF; dann hat mein PWM 100% Jetzt habe ich zum spaß einfach mal die beiden bits: CCP1CON.DC1B1 = 1; CCP1CON.DC1B0 = 1; oder auch mal 0;1 oder 0;0 gesetzt. Aber eine änderung am ausgang habe ich nie. Da stimmt doch irgendwo was nicht...
Wenn du rechnen kannst, dann versuch doch zu verstehen was für Werd dabei rauskommt. 0xFF ist binär 11111111.Die zwei bits kommen am Anfang dazu. Draus wird 1111111111 = 1023. 0111111111 = 511 1011111111 = 767 0011111111 = 255 Eigentlich müsste sich was ändern.Aber vielleicht ist der Rest des Codes nicht richtig.
Ja das ist mir klar! Aber dann weiß ich jetzt das ich schonmal nicht all zu falsch liege. Wenn ich es am laufen habe schreibe ich euch wo das Problem lag!
@ sunny >Wenn du rechnen kannst, dann versuch doch zu verstehen was für Werd >dabei rauskommt. >Die zwei bits kommen am Anfang dazu. Nein, am Ende du Schwachkopf. Das sind die unteren zwei Bits.
Was soll diese Anmache? Erstens bin ich kein Schwachkopf und zweitens bist du einer. Das sind keine unteren zwei Bits.
Ehrlich gesagt weiss ich nicht ob das die oberen oder unteren zwei Bits sind.
Hi, sowas gehört sich nicht andere zu beschümpfen.. Ich habe es nun genau wie hier: http://www.mikroe.com/forum/viewtopic.php?t=17449
Ja, endlich! Also um 10bit Auflösung zu erreichen muss man folgendes tun: int duty_ratio // from 0 to 1023; also 0b0000 00nn nnnn nnnn CCPR1L = duty_ratio >> 2; // also 0b0000 0000 xxxx xxxx CCP1CON.F4 = duty_ratio; // also 0b0000 00nn nnnn nnnx CCP1CON.F5 = duty_ratio >> 1; // also 0b0000 00nn nnnn nnxn Um die frequenz einzustellen: 1/Clock * (PR2+1) 4 T2CON(prescaler) = 1/Hz Das habe ich mit dem Oszi überprüft und validiert!
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.