Forum: Mikrocontroller und Digitale Elektronik PIC18 - 10bit vs. 8bit PWM


von Martin (Gast)


Lesenswert?

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!

von Frank (Gast)


Lesenswert?

Ich nehme mal an deine temp Variable ist zwischen 0x000 und 0x3FF 
definiert?
Also werden Bit 0-1 in das DC1Bn Register geschrieben.

von Martin (Gast)


Lesenswert?

>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?

von holger (Gast)


Lesenswert?

>Also ist das jetzt richtig definiert oder ist das falsch?

Schau doch einfach mit dem Multimeter oder dem Osci nach.

von Sunny (Gast)


Lesenswert?

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.

von Sunny (Gast)


Lesenswert?

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.

von Sunny (Gast)


Lesenswert?

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.

von Sunny (Gast)


Lesenswert?

Sunny schrieb:
> Hier wird die CCPR1L um zwei stellen nach links verschoben

Ich meine nach rechts

von Sunny (Gast)


Lesenswert?

Manchmal habe ich echt gute Ideen. Mein Algorithmus arbeitet perfekt.

von Sunny (Gast)


Lesenswert?

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.

von Sunny (Gast)


Lesenswert?

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);

von Martin (Gast)


Lesenswert?

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...

von Sunny (Gast)


Lesenswert?

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.

von Martin (Gast)


Lesenswert?

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!

von dummy (Gast)


Lesenswert?

@ 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.

von Sunny (Gast)


Lesenswert?

Was soll diese Anmache?
Erstens bin ich kein Schwachkopf und zweitens bist du einer.
Das sind keine unteren zwei Bits.

von Sunny (Gast)


Lesenswert?

Ehrlich gesagt weiss ich nicht ob das die oberen oder unteren zwei Bits 
sind.

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

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

von Sunny (Gast)


Lesenswert?

Und läufts jetzt, oder nicht?

von Martin (Gast)


Lesenswert?

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