software pwm mit pic16F628A und XC8

Mein aktuelles Wissen über PICs beschränkt sich derzeit auf einfaches LED-Blinken mit und ohne Verwendung von Interrupts und Timern in C-Code mit XC8, MPLAB IDE und Pickit 3. Ich habe Probleme, diese Software pwm auf einem PIC16F628A basierend auf Anweisungen für andere Bilder zu implementieren der PIC18F-Familie auf dieser Seite: Software-PWM für PIC18F-Familie und deren ursprüngliche Implementierung auch nicht ganz sinnvoll war.

Hier ist meine Version:

#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

#define _XTAL_FREQ 4000000

unsigned char pwmCounter = 0;
unsigned char ledActualBrightness = 20;
unsigned char ledTargetBrightness = 0;
unsigned char fadeCounter = 0;
void initialize (){
    // Tri-state registers. Sets all pins to outputs
    TRISA = 0; 
    TRISB = 0;
    // Turn off all comparators
    CMCON = 7;

    PORTA = 0;
    PORTB = 0;
    GIE = 1;
    T0IE = 1;
    T0CS = 0;
    PSA = 0;
    PS0 = 0;
    PS1 = 1;
    PS2 = 0;
    TMR0 = 255 - 250;
}


void main(void) {

    initialize(); 

    while (1){
    }
}

void interrupt isr(void){
    if (T0IF){
        GIE = 0;
        T0IE = 0;
        T0IF = 0;
        // Perform the PWM brightness control
        if (ledActualBrightness > pwmCounter)
            RB0 = 1; else RB0 = 0;

        pwmCounter++;
        if (pwmCounter > 19) pwmCounter = 0;

        // Perform fading control
        if (ledActualBrightness <= ledTargetBrightness)
            ledActualBrightness = ledTargetBrightness;
        else
        {
            fadeCounter++;
            if (fadeCounter >= 24)
            {
                ledActualBrightness--;
                fadeCounter = 0;
            }
        }

        TMR0 = 255 - 250;
        GIE = 1;
        T0IE = 1;
    }
}

Dieser Code lässt die LED nur einmal vollständig verblassen, danach bleibt sie vollständig gedimmt (oder AUS), im Gegensatz zu dem, worauf ich abzielte: die LED wiederholt ausblenden zu lassen. Außerdem kann ich mit dem Auge eine hochfrequente Oszillation der Helligkeit sehen, während sie langsam abklingt (das Abklingen erfolgt über etwa 0,5 Sekunden). In Bezug auf die Originalversion im bereitgestellten Link habe ich zusätzlich zum PIC-Setup meinen Prescaler auf ein Verhältnis von 1: 8 geändert, weil ich dachte, dass er mir 250 Timer-Ticks gibt, um 1000 Mikrosekunden mit dem internen Oszillator von 4 MHz zu messen. Ich habe auch die ledTargetBrightnessvon 0 auf 20 geändert. Es auf Null zu haben, wie im ursprünglichen Code, machte keinen Sinn (und es hat tatsächlich überhaupt nicht funktioniert, die LED blieb die ganze Zeit AUS).

Ich würde gerne verstehen, warum meine Version die LED nur einmal und nicht regelmäßig alle ~ 0,5 Sekunden ausblendet und wie dies behoben werden kann, während dieselbe Strategie beibehalten wird (innerhalb dieses Interrupts).

Irgendwann dachte ich, es könnte eine falsche Handhabung der Interrupt-Flags sein, die nicht in der richtigen Reihenfolge oder an der richtigen Stelle gesetzt oder gelöscht wurden, aber das Lesen des Datenblatts zeigte, dass es in Ordnung zu sein scheint, wie ich sie verwende: T0IF wird vor dem erneuten Löschen gelöscht Aktivieren des Interrupts durch TOIE = 1 (und GIE = ​​1, obwohl es nicht offensichtlich ist, ob es sinnvoll ist, dies im Interrupt-Codeblock zu tun).

[EDIT] Nach dem Hinweis im Kommentar leuchtet die LED nicht mehr auf, weil die if-Anweisung nicht ordnungsgemäß zurückgesetzt wurde. Anstatt auf den Anfangshelligkeitswert von 20 zurückzusetzen, habe ich ihn so gelassen, wie er im ursprünglichen Code war, wo er tatsächlich nur auf 0 gesetzt ist, wodurch die LED gezwungen wird, AUS zu bleiben. Wenn ich die if-Anweisung ändere zu:

if (ledActualBrightness <= ledTargetBrightness)
            ledActualBrightness = 20;

Das Abklingen wiederholt sich. Ich sehe jedoch immer noch hochfrequente Ein / Aus-Oszillationen, während sie verblasst, was ich immer noch nicht verstehe. Das Timing sollte schnell genug sein, um dies nicht einmal zu bemerken.

Willkommen bei EE.SE. Meine erste Vermutung ist, dass Sie keinen Code haben, um die Helligkeitsstufe zurückzusetzen. Ich sehe ein paar Countdown-Timer, aber Sie müssen die Helligkeit zurücksetzen, bevor Ihr Code beendet wird.
Danke @Sparky256. In Bezug auf das Zurücksetzen der Helligkeit, ist es nicht das, was if (ledActualBrightness <= ledTargetBrightness) ledActualBrightness = ledTargetBrightness;zu tun ist?
Ich sehe, Sie haben Recht @Sparky256, ich habe das nicht richtig aus dem ursprünglichen Code angepasst. Diese if-Anweisung setzt die Helligkeit überhaupt nicht zurück und ich verstehe nicht einmal, wofür sie ursprünglich war.

Antworten (2)

Ihr Code ist gut, aber die Timer0-Eingabe auf Microchip-Teilen ist die Befehlszykluszeit, die die Oszillatorfrequenz / 4 ist. Mit Ihrem aktuellen Setup arbeiten Sie also mit einer Eingangsfrequenz von 1 MHz anstelle von 4 MHz. Nachdem Sie Ihren Prescaler durchlaufen haben, sind Sie auf 125 KHz gesunken, und da Sie von 250 aufwärts zählen, erhalten Sie einen Interrupt mit einer Rate von 500 Hz. Da Sie die LED alle 20 Interrupts ein- und ausschalten, sind Sie auf 25 Hz herunter, was Sie sehen können. Probieren Sie einen Prescaler von einem aus. Dadurch wird die PWM auf 200 Hz beschleunigt, aber auch die Zeit zum Ausblenden verkürzt. Sie können die Zahl fadeCounter >= auf 192 (24*8) erhöhen, um dies zu kompensieren und sie mit der gleichen Rate verblassen zu lassen. Wenn es immer noch zu schnell verblasst, ändern Sie fadeCounter von einem vorzeichenlosen Zeichen in eine 16-Bit-Ganzzahl, damit Sie eine größere Zahl als 255 verwenden können. Viel Spaß!

Nachdem Sie sich Ihren Code angesehen haben, if (ledActualBrightness <= ledTargetBrightness) ledActualBrightness = ledTargetBrightness;sollte ledActualBrightness = 20 sein; (oder verwenden Sie den Alias ​​für diesen Wert).

Der Code, wie Sie ihn geschrieben hatten, hielt ihn einfach bei null Helligkeit gesperrt. Am Ende Ihres Codes müssen Sie ihn wieder auf volle Helligkeit zurücksetzen, damit er wieder verblassen kann.

Duplizieren Sie diesen Code (eine weitere Schleife), aber kehren Sie Ihre Auf- und Abwärtszählung um, und Sie erhalten ein Licht, das nach oben, dann nach unten, dann nach oben, dann nach unten usw. geht.

Was das Rauschen betrifft, ist es vielleicht eine Unterbrechung in der Schleife , die eine LED flackern lässt. Eine LED kann Tausende Male pro Sekunde ein- und ausschalten. Eine Alternative besteht darin, ein RC-Netzwerk zu verwenden, um die LED mit bereinigten Impulsen anzusteuern.

Code hat keine Gnade mit dem Programmierer. Bei winzigen Boo-Boos kann Dampf aus Ihren Ohren kommen. Viel Glück.

vielen Dank, dass Sie sich den Code angesehen haben. Ich hoffe, ich kann dieses flackernde/oszillierende Problem schließlich mit dem Code beheben. Ich versuche, eine Platine mit dieser Art von Bild mit 7 LEDs herzustellen, die mit Software-PWM gesteuert werden, und ich möchte die Anzahl der zu lötenden Komponenten minimieren. Das Hinzufügen von Widerständen und Kondensatoren könnte den Zweck verfehlen. Ich denke, ich muss möglicherweise das Modell des Bildes dafür ändern, wenn es zu langsam oder zu ungenau ist, um die sichtbare PWM-Oszillation zu beheben.