Forum: Mikrocontroller und Digitale Elektronik PIC18f23q43 PWM klappt nicht


von Jakob N. (jakob_leeeee)


Lesenswert?

Moin moin,

ich gehöre zu den Arduino "kiddys". Möchte bzw. muss mich auf "richtige" 
µC fokussieren. Habe dazu aufgrund Lieferbarkeit etc. den PIC18F23Q46 
gewälht..in der Hoffnung das sich in der Programmierung die PICs in der 
18er Serie nicht so wild unterscheiden. I/Os funktionieren auch alle 
sehr schön, ist ja auch halb so wild. Ich möchte nun allerdings 10bit 
PWM realisieren und habe dazu folgendes Tutorial benutzt.

https://openlabpro.com/guide/pulse-width-modulation-using-pic18f4550/

Der Code generiert auch keine Fehler, bloß...es passiert nüchts. Ok die 
LED geht an auf 100% das wars aber auch schon. :(

Kann mir da jemand weiterhelfen was ich falsch gemacht habe ?

Ich bin echt nicht so drinnen im Register lesen und schreiben. Habe vor 
ner Zeit Atmegas programmiert, aber ich wollte mal PICs probieren..;S

1
#include <xc.h>
2
#define _XTAL_FREQ 20000000 //define crystal frequency to 20MHz
3
4
#pragma config FEXTOSC = HS
5
#pragma config WDTE = OFF       // WDT operating mode (WDT Disabled; SWDTEN is ignored)
6
#pragma config MCLRE = EXTMCLR
7
#pragma config XINST = OFF
8
#pragma config BOREN = OFF
9
10
void PWM1_Init(unsigned char period){
11
    TRISCbits.TRISC2 = 0          //  Set RC2 as output
12
    
13
    /* CCP PWM mode */
14
    CCP1CON &= 0xCF;        //  5,4 bits zeroed (DC1B1:DC1B0 = 00)
15
    CCP1CON |= 0x0C;        //  PWM mode ( CCP1M3:CCP1M0 = 1100)
16
    
17
    /* Timer2 configuration */
18
    PR2 = period;           //  configure timer2 period
19
    T2CON = 0x02;           //  Set prescalar 16   
20
    TMR2ON = 1;             //  timer2 on
21
    
22
}
23
24
void PWM1_setDC(unsigned int dutycycle){
25
    
26
    CCPR1L = dutycycle>>2;  //  PWM duty cycle - first 8-bits (MSb)
27
    CCP1CON &= 0xCF;        //  5,4 bits zeroed (DC1B1:DC1B0 = 00)
28
    CCP1CON |= ((dutycycle<<4)&0x30);  //  PWM duty cycle - last 2-bits (LSb) in CCP1CON 5,4 bits   
29
}
30
31
void main(void) 
32
{
33
34
 PWM1_Init(0x270);
35
36
 
37
while(1)
38
{
39
  
40
  PWM1_setDC(20);
41
  
42
}
43
return;
44
}

von Franko P. (sgssn)


Lesenswert?

Servus
arbeitest du mit MPLAB X + XC8? Dann solltest du vielleicht noch den MCC 
installieren. Lass dir von MCC dein PWM erzeugen. Möglciherweise kommt 
dein Signal nicht da raus, wo du vermutest:

28.4.2 Setup for PWM Operation
The following steps illustrate how to configure the CCP module for 
standard PWM operation:
1. Select the desired output pin with the RxyPPS control to select CCPx 
as the source. Disable the selected pin
output driver by setting the associated TRIS bit. The output will be 
enabled later at the end of the PWM setup.
2. Load the selected timer TxPR period register with the PWM period 
value.
3. Configure the CCP module for the PWM mode by loading the CCPxCON 
register with the appropriate values.
4. Load the CCPRx register with the PWM duty cycle value and configure 
the FMT bit to set the proper register
alignment.
5. Configure and start the selected timer:
– Clear the TMRxIF Interrupt Flag bit of the PIRx register. See the Note 
below.
– Select the timer clock source to be as FOSC/4. This is required for 
correct operation of the PWM module.
– Configure the TxCKPS bits of the TxCON register with the desired timer 
prescale value.
– Enable the timer by setting the TxON bit.
6. Enable the PWM output:
– Wait until the timer overflows and the TMRxIF bit of the PIRx register 
is set. See the Note below.
– Enable the CCPx pin output driver by clearing the associated TRIS bit.


Gruß

von Jakob N. (jakob_leeeee)


Angehängte Dateien:

Lesenswert?

Franko P. schrieb:
> Servus
> arbeitest du mit MPLAB X + XC8? Dann solltest du vielleicht noch den MCC
> installieren. Lass dir von MCC dein PWM erzeugen. Möglciherweise kommt
> dein Signal nicht da raus, wo du vermutest:

So sieht es bei mir aus. Sollte ja dann theoretisch 10bit PWM mit 10kHz 
sein ?

Output RC1 ?


Edit: Hab mal mein Fluke 99B dran gehangen, 50% DC = 2,42V..naja evtl. 
noch ein RC-Glied. Versorgung wird der PIC mit 5.0V genau, allerdings 
aufn Steckboard. Aber mir wird 20kHz angezeigt ? was ist dann genau mit 
Request Frequency gemeint, auch weiß ich grade nicht wie ich den DC in 
meiner Main ändern kann.

: Bearbeitet durch User
von Jakob N. (jakob_leeeee)


Lesenswert?

Jakob N. schrieb:
> 0% DC = 2,42V..naja evtl.
> noch ein RC-Glied

...PWM Outputs sind ja nicht so belastbar. LM358 Kommt noch dran :S

von Jakob N. (jakob_leeeee)


Lesenswert?

Nun benötige ich dank dem MCC nur noch die möglichkeit den Duty Cycle in 
meiner Main zu verändern. Bspw. LED dimmern und das am besten mit 
Eingabe von 0 - 1023. Ich finde nirgends wo ich den DC einstellen kann. 
Bzw. ich finde keine erstellte Funktion dafür, aber das müsste doch wo 
stehen, weil es wird an sich ja nur ein Code erstellt.

von Franko P. (sgssn)


Lesenswert?

siehe oben:

2. Load the selected timer TxPR period register with the PWM period
value.

4. Load the CCPRx register with the PWM duty cycle value and configure
the FMT bit to set the proper register

Duty cycle also in CCPR1.

Gruß

von Jakob N. (jakob_leeeee)


Lesenswert?

Franko P. schrieb:
> Duty cycle also in CCPR1.


So hab ich es indirekt gefunden. Aber über das Register wird der DC hier 
eingestellt: Seite 7

http://ww1.microchip.com/downloads/en/Appnotes/Getting-Started-with-PWM-Using-CCP-on-PIC18-DS90003270A.pdf

Allerdings tut sich nüchts :( Ist leider das erste mal das ich mit 
Registern etc. auseinander setze, deswegen tue ich mich schwer das in 
meinen Schädel zu bekommen
1
int main(void)
2
{
3
    SYSTEM_Initialize();
4
5
   while(1)
6
    {
7
     CCPR1 = 100 << 6; // 100 von 1023
8
    }    
9
}

: Bearbeitet durch User
von Toxic (Gast)


Lesenswert?

Den "PIC18F23Q46" gibt es nicht.Zumindest kann Google damit nichts 
anfangen

von Jakob N. (jakob_leeeee)


Lesenswert?

Toxic schrieb:
> Den "PIC18F23Q46" gibt es nicht.Zumindest kann Google damit nichts
> anfangen

Schreibfehler PIC18F26q43 :S

von Bernd (Gast)


Lesenswert?

Hallo,
ohne dass ich jetzt ein Datenblatt angeschaut hab: du schreibst in 
deiner while(1)-Schleife ununterbrochen in das Register - normalerweise 
macht man das einmal zum Konfigurieren und den Rest macht dann die 
Hardware. Soll das wirklich so sein?

Bernd

von Franko P. (sgssn)


Lesenswert?

Ich bin mir nicht sicher, ob das so geht:
CCPR1 = 100 << 6;

Die PIC18 sind ja 8 Bitter.
Versuch das mal besser mit

CCPR1L = xx;
CCPR1H = yy;

Gruß

von Jakob N. (jakob_leeeee)


Lesenswert?

Bernd schrieb:
> Soll das wirklich so sein?

Ich möchte halt nur einen Wert im 10bit Bereich ändern und somit die 
Ausgangsspannung steuern. Irgendwelche Bits muss ich ja schreiben oder 
nicht um den µC zu sagen, was jetzt der DC ist ?

von Jakob N. (jakob_leeeee)


Angehängte Dateien:

Lesenswert?

Hab jetzt was gefunden...damit lässt sich die Spannung einstellen. Aber 
das stimmt alles nicht so..wenn ich zB. 512 eingebe liegt der Wert schon 
bei 3,XYV und die 5V sind viel früher als die 1023 erreicht. Hab 
schonmal probiert das alles um 6 bits zu verschieben, was dann ja 
eigentlich 10but entsprechen sollte. Ich vermute der Code generator mach 
bei mir nicht so ganz was ich wollte :(

von Toxic (Gast)


Lesenswert?

Franko P. schrieb:
> Die PIC18 sind ja 8 Bitter.

Der verwendete PIC hat offensichtlich drei 16bit PWMs

Jakob N. schrieb:
> Schreibfehler PIC18F26q43 :S

Datenblatt page 489:
Hier sind alle Register aufgefuehrt die mit PWM zu tun haben.

von Daniel E. (everyday_fun69)


Lesenswert?

Mir half dies hier:

https://microchipdeveloper.com/8bit:mccpwm

Oder dies hier ganz gut immer weiter

https://m.youtube.com/watch?v=pBRrUyOORwQ

In der Main Loop oder falls du einen Timer hast brauchst du das PWM 
immer nur ++ hoch zählen und wenn du das Limit erreicht hast, zählst du 
wieder — runter.

10 Bit heißt aber nicht unbedingt bis 1023, im MCC kann man 100 % 
vorgeben, da kam bei mir 999 raus anstatt 1023.

Wenn Du nach mir hier suchst findest Du auch Programme/ Beispiele zum 
PIC18F45K80, wo ich Probleme hatte

von Max M. (Gast)


Lesenswert?

Jakob N. schrieb:
> Irgendwelche Bits muss ich ja schreiben

Der grobe Ablauf bei eigentlich jeder PWM Hardware ist folgender:
Taktquelle und Taktteiler für den Timer wählen
Timer in PWM mode versetzen.
Ggf noch Art des PWM modes wählen (up, down, up/down)
Timer Rückladewert ins Register schreiben.

Bei jedem Timerüberlauf wird der Timer automatisch resettet und der von 
dir gewählte Timer Rückladewert in den Timer geladen.
Von da an zählt der dann weiter bis zum nächsten Überlauf.
Aus Taktquelle, Taktteiler und Timer Rückladewert ergibt sich die PWM 
Wiederholfrequenz.

In das Capture Compare register schreibst Du den Wert für den Duty 
cycle.
Erreicht der Timer diesen Wert führt ein positiver vergleich beider 
register zu einem wechsel des PWm Pins (high / low, je nachdem was Du 
gewählt hast)

Solange Du nichts neues in die Register schreibst, macht die PWM 
hardware endlos weiter. Das ist ja der Sinn einer PWM Hardware.

Willst Du den Duty cycle verändern kannst Du Dir selbst aussuchen in 
welcher Geschwindigkeit. Das kannst Du mit einer separaten Timer IRQ 
machen, immer wenn es einen Timer Überlauf gegeben hat, oder was auch 
immer Dir dazu einfällt.
Wenn Du allerdings ständig in dem Register rummachst, bevor der Zyklus 
abgelaufen ist, kann die PWM Hardware ihren Job nicht machen.

Jakob N. schrieb:
> Ist leider das erste mal das ich mit
> Registern etc. auseinander setze
DB + Family reference Datasheet aufmerksam lesen
Les alles zu dem Timer und den PWM Registern, schau dir jedes Register 
an und beachte auch die logig Bildchen die es teilweise zur 
Verdeutlichung der Hardware gibt.
Du hast die Arduino Welt verlassen und bist bare metal unterwegs.
Das ist garnicht so schwer, nur ungewohnt.
Dafür kannst Du damit Sachen anstellen für die es keine Lib gibt.
Ist nämlich meistens nicht die Hälfte davon in einer Lib umgesetzt was 
die MCUs können, wenn man ihre HW flexibel verwendet.

Bei den PICs:
Immer explizit auf digital io stellen, sonst hat die ADC HW immer einen 
Fuss in der Tür auch wenn Du den ADC nicht benutzt.
Führt zu merkwürdigen Ergebnissen.

Lerne den Debugger zu benutzen, breakpoints zu setzen und wie man sich 
mit Debugger die CPU Register oder Code Variablen ansieht.
Die Zeiten des Arduino Pin friggel debugings oder mühseeligem Uart 
debugging sind damit vorbei.
Man muss Code nicht blind laufen lassen und dann wild raten was da wohl 
passiert.
Mit Debugger hättest Du z.B. den Timer Überlauf IRQ aktivieren können 
und einen Breakpoint in die IRQ Routine gesetzt.
Da hättest Du sofort bemerkt wenn der Überlauf nicht kommt.

Bevor Du einen Pin verwenden kannst must Du entscheiden was der ist und 
was der kann. Ist das ein ADC Eingang, ein digital IO, ist der open 
Kollektor oder push pull, invertiert, ist der Pull up aktiv oder nicht.
Hat der Pic eine IO matrix musst du auch festlegen welche interne HW an 
welchen Pin gelegt wird.
Was Du nicht machst, wird nicht gemacht.
Kein Arduino Gefriggel im Hintergrund, das dutzende verschiedene MCUs 
auf den kleinsten gemeinsamen Nenner kastriert und einem vieles abnimmt.

Aber wenn Du Dir die Mühe machst, kannst Du geile Sachen mit der HW 
anstellen.
Statt dem Aufruf einer Routine die Du nicht verstehst, der du x 
Parameter mitgibts, damit die dann erstmal auseinanderklamüstert was Du 
eigentlich willst, setzt Du nur eine handvoll Register.
Ist m.E. oft einfacher als den Funktionsaufruf zu verstehen und dann 
rauszufinden das die das eine Ding nicht kann, das Du willst und das die 
HW auch könnte.

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.