Forum: Mikrocontroller und Digitale Elektronik Flackern bei PWM


von Beni W. (wenben)


Lesenswert?

Hallo zusammen,
ich versuche auf meinem Demoboard von PicKit eine ganz einfache SoftPWM 
zu Programmieren.

Es hat eigentlich ganz gut geklapt, nur die LED beginnt zu flackern 
sobald man unter ca. 80% ist.

Hier mein Code:

#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF 
// CONFIG1H
#pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 30 
// CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768 
// CONFIG2H
#pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC 
// CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF                    // 
CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF 
// CONFIG5L
#pragma config CPB = OFF, CPD = OFF 
// CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF 
// CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF 
// CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF 
// CONFIG7L
#pragma config EBTRB = OFF 
// CONFIG7H


/** I N C L U D E S **************************************************/
#include "p18f45k20.h"
#include "delays.h"

/** D E C L A R A T I O N S ******************************************/

unsigned char TIME;             //LED1 als 8-Bit


void LED (unsigned char ADWERT)
{

        TIME++;

    if (TIME<ADWERT) {LATD = 0b11111111;}
    else {LATD =0b00000000;}

}

int main(void) {
    TIME=0;
    TRISD = 0x00;
    TRISA = 0xFF;
    ANSELH = 0b00000000; //AN0 ist nun ein Analoger Eingang
    ADCON0= 0b00000001; //Teiler von 2 einstellen, und den ADC 
einschalten
    ADCON1= 0b10000000; //Rechtsbündig, Vcc und Vdd verwenden
    ADCON2= 0b00111000;
    CM1CON0 = 0b00000000; // Komperator 1 aus
    CM2CON0 = 0b00000000; // Komperator 2 aus


        while (1)
    {
        ADCON0bits.GO = 1;
        while(ADCON0bits.GO ==1);
        LED(ADRESH);
    }

return 0;
}




Woran könnte das liegen, was kann ich verbessern oder schneller machen?

von sdfg2qz2 (Gast)


Lesenswert?

Fahr doch mal einem Passat mit LED-Rücklichtern hinterher
und frag den Fahrer :-)

Spaß beiseite. LEDs sind unglaublich schnell. Was Du mit einer
Glühbirne und 50Hz flackerfrei hinbekommst, klappt mit einer LED
überhaupt nicht.

Hier kommt es darauf an, was der Betrachter (Mensch) noch
störend empfindet. Die LED wirst Du nie so schnell angesteuert
bekommen, dass sich eine mittlere Helligkeit direkt an der
LED einstellt.

von Karl H. (kbuchegg)


Lesenswert?

sdfg2qz2 schrieb:

> Hier kommt es darauf an, was der Betrachter (Mensch) noch
> störend empfindet. Die LED wirst Du nie so schnell angesteuert
> bekommen, dass sich eine mittlere Helligkeit direkt an der
> LED einstellt.


Was genau meinst du damit?
Eine 8-Bit PWM mit der man auf eine Zykluszeit jenseits von 100Hz kommt, 
schafft jeder Nasenpopel-AVR-Tiny. Und ausser für ganz empfindsame 
Gemüter IST die für 99% der Menschheit flackerfrei und eine in der 
Helligkeit stellbare LED.


Zu seinem Code kann ich nicht viel sagen, da ich mit diesem µC keine 
Erfahrung habe. Die PWM durch die Hauptschleife ist jetzt sicher nicht 
so der Bringer, aber abhängig vom CPU-Takt sollte sich damit selbst bei 
kleinen Taktfrequenzen schon eine flackerfreie PWM einstellen.

von Beni W. (wenben)


Lesenswert?

sdfg2qz2 schrieb:
> Hier kommt es darauf an, was der Betrachter (Mensch) noch
>
> störend empfindet. Die LED wirst Du nie so schnell angesteuert
>
> bekommen, dass sich eine mittlere Helligkeit direkt an der
>
> LED einstellt.

Ich habe das Programm umgestellt das der Pic nur einmal Initialisieren 
muss. Jetzt sieht das ganze sehr viel angenemer aus.

Der neue Code:

void main(void) {
    TIME=0;
    TRISD = 0x00;
    TRISA = 0xFF;
    ADCON0= 0b00000001; //Teiler von 2 einstellen, und den ADC 
einschalten
    ADCON1= 0b10000000; //Rechtsbündig, Vcc und Vdd verwenden
    CM1CON0 = 0b00000000; // Komperator 1 aus
    CM2CON0 = 0b00000000; // Komperator 2 aus


        while (1)
    {
        TIME++;
        ANSELH = 0b00000000; //AN0 ist nun ein Analoger Eingang
        ADCON0bits.GO = 1;
        while(ADCON0bits.GO ==1);
        ADWERT=(ADRESH);

        if (TIME<ADWERT) {LATD = 0b11111111;}
        else {LATD =0b00000000;}
    }
}

Wenn jemand verbesserungs Vorschläge hat, ich bin offen für alles. Bin 
ein Mikrocontrollerneuling und lerne gerne dazu.

von Christian K. (Firma: Atelier Klippel) (mamalala)


Lesenswert?

Ja, kann man erheblich verbessern um die PWM schneller zu machen. Ein 
Problem ist die while() Schleife die auf den ADC wartet.

Wenn Du das ganze wirklich unbedingt ohne Interrupt machen willst, hier 
mal ein Beispiel (ohne den ganzen Init-Kram):
1
unsigned char pwm_count;
2
unsigned char led_value;
3
4
void do_pwm(void)
5
{
6
    pwm_count++;
7
8
    if(pwm_count < led_value)
9
    {
10
        LATD = 0xFF;
11
    }
12
    else
13
    {
14
        LATD = 0x00;
15
    }
16
}
17
18
void main(void)
19
{
20
    // Hier PIC und ADC init, etc.
21
    // ...
22
23
    ADCON0bits.GO = 1
24
25
    pwm_count = 0;
26
    led_value = 0;
27
28
    while(1)
29
    {
30
        if(ADCON0bits.GO == 0)
31
        {
32
            led_value = ADRESH;
33
            ADCON0bits.GO = 1;
34
        }
35
36
        do_pwm();
37
    }
38
}

So wird die PWM Routine permanent ausgeführt, und nicht erst wenn der 
neue ADC Wert eingelesen ist. Das Problem bei deiner Methode: Ohne sehr 
saubere Vref für den ADC, sowie ohne sehr saubere (= gefilterte) 
Eingangsspannung zum ADC werden da immer irgendwelche unteren Bits im 
Ergebnis "wackeln".

Nehmen wir mal an dein PWM Zähler steht auf 10, dein vorheriger ADC Wert 
war 11, somit ist PORTD jetzt an. Jetzt liest Du den ADC aus, wartest 
dabei aber bis der Wert da ist. Der ausgelesene Wert ist jetzt aber 10. 
Nun vergleichst Du wieder, und der Port wird abgeschaltet, da der Zähler 
jetzt 11 ist. Beim nächsten mall kann es dann sein das der ADC 12 ist, 
und somit wieder den Port wieder einschaltet.

Normalerweise ist das kein Problem, da eine PWM eigentlich mit fester 
und schneller Frequenz läuft. Durch die lange Verzögerung des 
ADC-Auslesens aber kann das zu sichtbarem flimmern kommen, je nach ADC 
Konfiguration.

Um das ganze noch besser als im Beispiel von mir zu machen: Entweder 
direkt das PWM Modul des PIC benutzen (wenn er eines hat). Oder einen 
Timer benutzen und das, was oben do_pwm() ist in die IRQ Routine stecken 
(plus das IRQ Flag des Timers dort löschen). Somit hast Du dann eine 
feste PWM Frequenz.

Achja, mit dem Code kann man den Augang übrigens nie komplett 
abschalten, weil ein Zählerwert von 0 nicht kleiner ist als ein ADC Wert 
von 0. Somit wird der Ausgang immer für einen Tick aktiviert sein.

Grüße,

Chris

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.