Forum: Mikrocontroller und Digitale Elektronik PWM mit PIC12F1501


von Klaus B. (klaus_b307)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich steh völlig an...

Auch werd ich aus dem Datenblatt nicht schlau oder ich übersehe etwas.
Ich möchte den Hardware PWM Ausgang von 1% bis 99% ansteigen lassen 
(vorerst nur zum testen).

Fast alles passt: PWM Frequenz stimmt mit der Berechnung (512µs)
Aus irgendeinem Grund wird mein PWM Signal nie länger als ca. 100µs !!

Wenn ich einen fixen Wert einstelle passt alles (also ohne den duty zu 
erhöhen oder zu verändern). Da sind von 1% bis 99% konstant möglich.

Irgendwie nimmt er immer den ersten Startwert - inkrementiert und nach 
100µS startet er wieder bei 512 (Hab es mit mehreren Weren getestet - 
immer gleiches Verhalten)

Ich hab keine Ahnung mehr...

Ich hoffe es kann mir jemand helfen, will es eher nicht mit SW PWM 
lösen.
Danke und Grüße, Klaus

Hier der Code:

#include <xc.h>

#define _XTAL_FREQ 8000000

unsigned int duty = 512;

void init(void);

void main(void) {
    init();
    while (1) {
        duty++;
        __delay_ms(10);
        if (duty > 1023)duty = 0;
        PWM1DCH = duty >> 2;
        PWM1DCL = (duty & 0x03) << 6;
    }
}

void init(void) {
    OSCCON = 0b01110010; //Intern 8Mhz
    T2CON = 0b00000101; //T2 on, Prescaler = 1:4
    PR2 = 0xFF; //

    TRISAbits.TRISA2 = 0;
    PWM1CON = 0b11000000;
    PWM1DCH = duty >> 2;
    PWM1DCL = (duty & 0x03) << 6;
    T2CONbits.TMR2ON = 1;
}

: Bearbeitet durch User
von Andras H. (andras_h)


Lesenswert?

Bin keine Experte, aber:
- versuche mal High and Low zu vertauschen. Bei manchen PICs waren 
Timers so, dass man die reihenfolge richtig machen musste. Wobei das war 
eher bei lesen. Meine ich.
- Versuche nur den High zu schreiben. Lass den low auf 0. Funktioniert 
es so? Schreibe mal da nur feste werte und probiere aus was passiert.

von Andras H. (andras_h)


Lesenswert?

Könnte noch etwas mit den PIN interagieren? ADC eingang abgeschaltet? 
War bei anderen PICs immer nerfig.

Guck mal in den Datasheet, da steht welche features noch auf dem PIN 
liegen. Gucke mal durch ob nicht manchen davon ab reset by default 
enabled sind.

RA2 5 AN2 DACOUT2 C1OUT T0CKI CWG1A CWG1FLT CLC1

von Sebastian R. (sebastian_r569)


Lesenswert?

Andras H. schrieb:
> Guck mal in den Datasheet, da steht welche features noch auf dem PIN
> liegen. Gucke mal durch ob nicht manchen davon ab reset by default
> enabled sind.

Wichtig ist auch das RxyPPS (also RA2PPS) Register, bei dem man den 
Timer-Ausgang auf einen Pin legen muss:

https://onlinedocs.microchip.com/oxy/GUID-20DC4AC0-78C3-43D4-B405-15D8B752B254-en-US-3/GUID-B6C0BEDD-12B4-491C-B6CE-052CF7FF2360.html#GUID-B6C0BEDD-12B4-491C-B6CE-052CF7FF2360__SECTION_FYC_S52_DHB

von Klaus B. (klaus_b307)


Lesenswert?

Danke für die raschen Antworten.

Hab die zwei Vorschläge umgesetzt - leider keine Änderung.

Interessant ist, dass er das gleiche Verhalten auch bei anderen PWM 
Frequenzen hat. Also wenn ich auf den PS auf 16 konfiguriere (122Hz) 
startet er nach 2 ms neu.

Wichtig ist auch das RxyPPS (also RA2PPS) Register, bei dem man den
Timer-Ausgang auf einen Pin legen muss:

Gibt es dies auch für den 12F1501?

Aktueller Code (PS TMD2 noch auf 1:4):
#include <xc.h>

#define _XTAL_FREQ 8000000

unsigned int duty = 100;

void init(void);

void main(void) {
    init();
    while (1) {
        duty++;
        __delay_ms(10);
        if (duty > 1023)duty = 0;
        PWM1DCH = duty >> 2;
        PWM1DCL = (duty & 0x03) << 6;
    }
}

void init(void) {
    OSCCON = 0b01110010; //Intern 8Mhz
    T2CON = 0b00000101; //T2 on, Prescaler = 1:4
    PR2 = 0xFF; //

    TRISAbits.TRISA2 = 0;
    ANSELAbits.ANSA2 = 0;
    PWM1CON = 0b11001000;
    PWM1DCH = duty >> 2;
    PWM1DCL = (duty & 0x0C) << 6;
    T2CONbits.TMR2ON = 1;
}

: Bearbeitet durch User
von Klaus B. (klaus_b307)


Lesenswert?

ich verstehe nicht warum es mit einem fixen Wert funktioniert:

Exakt 50%

unsigned int duty = 512;

void init(void);

void main(void) {
    init();
    while (1) {
    }
}

void init(void) {
    OSCCON = 0b01110010; //Intern 8Mhz
    T2CON = 0b00000101; //T2 on, Prescaler = 1:4
    PR2 = 0xFF; //

    TRISAbits.TRISA2 = 0;
    ANSELAbits.ANSA2 = 0;

    PWM1CON = 0b11001000;
    PWM1DCH = duty >> 2;
    PWM1DCL = (duty & 0x0C) << 6;
    T2CONbits.TMR2ON = 1;
}

von Ste N. (steno)


Lesenswert?

Versuche mal in der main() vor dem beschreiben der PWM Register die 
Interrupts zu sperren. Danach natürlich wieder freigeben.
Oder den Timer während des beschreibens anhalten.
1
  T2CONbits.TMR2ON = 0;
2
  PWM1DCH = duty >> 2;
3
  PWM1DCL = (duty & 0x0C) << 6;
4
  T2CONbits.TMR2ON = 1;

Gibt es beim PIC12 keinen Timerinterrupt? Versuche doch mal die Register 
im Interrupt zu setzen. So macht man das normalerweise, damit das 
syncron zum Timer ist.

von H. H. (hhinz)


Lesenswert?

Lass dir doch über die Serielle ausgeben was tatsächlich in die Register 
geschrieben wird.

von Ste N. (steno)


Lesenswert?

Klaus B. schrieb:
> PWM1CON = 0b11001000;

PWM1CON ist auch falsch initialisiert. Bit3 ist lt. Manual nicht belegt. 
Daran wird es zwar nicht liegen, sollte aber geändert werden.

von Ste N. (steno)


Lesenswert?

Oder die Werte für die PWM Register vorher berechnen. Eventuell ist die 
Zeit zwischen dem Beschreiben wegen den Berechnungen zu lang.
1
  pwm_h = duty >> 2;
2
  pwm_l = (duty & 0x0C) << 6;
3
  PWM1DCH = pwm_h;
4
  PWM1DCL = pwm_l;

von Klaus B. (klaus_b307)


Lesenswert?

Alle Antworten plausibel und getestet - ich bekomm die Krise ....

immer noch das gleiche Verhalten: bei ca. 1/5 der PWM Zeit startet er 
bein initialen Duty Wert.

neuer Code mit den eingpeflegten Vorschlägen:

#define _XTAL_FREQ 8000000

unsigned int duty = 100, i;
unsigned char dutyh, dutyl;

void init(void);

void __interrupt() myISR(void) {
    TMR2IF = 0;
    PWM1DCH = dutyh;
    PWM1DCL = dutyl;
}

void main(void) {
    init();
    while (1) {
        __delay_ms(10);
        duty++;
        if (duty > 1023)duty = 0;
        dutyh = duty >> 2;
        dutyl = (duty & 0x03) << 6;
    }
}

void init(void) {
    OSCCON = 0b01110010; //Intern 8Mhz
    INTCON = 0b11000000; // GIE = ON / PEIE = ON
    PIE1bits.TMR2IE = 1; // T2 IF = ON
    T2CON = 0b00000101; //T2 on, Prescaler = 1:4
    PR2 = 0xFF; //

    TRISAbits.TRISA2 = 0;
    ANSELAbits.ANSA2 = 0;

    PWM1CON = 0b11001000;
    PWM1DCH = duty >> 2;
    PWM1DCL = (duty & 0x0C) << 6;
    T2CONbits.TMR2ON = 1;
}

von Ste N. (steno)


Lesenswert?

Letzter Versuch!
Ersetze in der main()
1
dutyh = duty >> 2;
durch
1
dutyh = 0xff;

Wenn deine PWM jetzt nahezu 100% hat, müßte ein typecast helfen.
1
dutyh = (int)duty >> 2;

: Bearbeitet durch User
von Klaus B. (klaus_b307)


Lesenswert?

Ste N. - Danke. Hilft vielleicht ber der Ursachenermittlung ;-)

dutyh = (int)duty >> 2; --> gleiches Bild
ABER

wenn ich in dutyh = 0xff setzte kommt es alles 2 Sekunden zu einem 
"reset".

ich sehe es am Oszi und noch deutlicher am angescholssenen Voltmeter 
(soll eine Meterclock werden) da der Zeiger kurz "einbricht"

Es sieht so aus als ob das PWM Modul alle 2 Sekunden einen reset macht.

Vielleicht hat wer eine Idee?

von Andras H. (andras_h)


Lesenswert?

Klaus B. schrieb:
> Vielleicht hat wer eine Idee?

Das wird dann eher der Watchdog werden. Ist der aktiv? Wenn ja dann 
triggern, sonst deaktivieren.

von Klaus B. (klaus_b307)


Lesenswert?

DANKE !!!!!

es war der Watchdog - auf den hab ich völlig vergessen...

von Ste N. (steno)


Lesenswert?

Kaum macht man es richtig, schon funktionierts ;)

Was mich allerdings wundert...

Klaus B. schrieb:
> Wenn ich einen fixen Wert einstelle passt alles (also ohne den duty zu
> erhöhen oder zu verändern). Da sind von 1% bis 99% konstant möglich.

Der Watchdog hätte doch hier auch schon zuschlagen müssen.

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.