www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Software PWM will nicht?


Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallöle, ich habe vor mir eine lustige Steuerbare 
RGB-LED-Zimmerbeleuchtung zu basteln. Dazu muss ich natürlich die 
RGB-LED ansteuern und zwar mit PWM. Ich hab mich für Software PWM 
entschieden weil ja alle 3 unabhängig vonneinander laufen müssen. Mein 
Code sieht wie folgt aus:
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 8000000UL
#define LED_R PORT3
#define LED_B PORT5
#define LED_G PORT7

volatile int PWMCOUNT = 0;
volatile int PWM_R,PWM_B, PWM_G = 0;

int main()
{

  DDRD |= 1<<LED_R | 1<<LED_B | 1<<LED_G;
    DDRB &= ~(1<<PORT0 | 1<<PORT1 | 1<<PORT2 | 1<<PORT3 | 1<<PORT4 | 1<<PORT5);
    TCCR0 |= 1<<CS00;
    TIMSK |= 1<<TOIE0;
    sei();

    while(1)
    {
        if(PINB & (1<<PIN0)&& PWM_R++ < 255) PWM_R++;
        if(PINB & (1<<PIN1)&& PWM_R++ > 0) PWM_R--;
        if(PINB & (1<<PIN2)&& PWM_B++ < 255) PWM_B++;
        if(PINB & (1<<PIN3)&& PWM_B++ > 0) PWM_B--;
        if(PINB & (1<<PIN4)&& PWM_G++ < 255) PWM_G++;
        if(PINB & (1<<PIN5)&& PWM_G++ > 0) PWM_G--;
    }

return 0;

}

ISR(TIMER0_OVF_vect) 
{
        PWMCOUNT++;

        if(PWM_R > PWMCOUNT)
        {
            PORTD |= 1<<LED_R;
        }
        else
        {
            PORTD &= ~(1<<LED_R);
        }


        if(PWM_B > PWMCOUNT)
        {
            PORTD |= 1<<LED_B;
        }
        else
        {
            PORTD &= ~(1<<LED_B);
        }


        if(PWM_G > PWMCOUNT)
        {
            PORTD |= 1<<LED_G;
        }
        else
        {
            PORTD &= ~(1<<LED_G);
        }
}

Wird alles mit dem GCC kompiliert. Controller ist ein Atmega8 der mit 
den internen 8 MHz läuft (getestet wirds an nem STK500). Also müsste ich 
ja eine PWM-Frequenz von 8*10^6/(256^2) = ~120 Hz haben. Aber wenn ich 
dann die Schalter drücke um den Grenzwert für die LED's zu verändern 
blinkt das ganze Gebilde nur ganz niederfrequent rum (mir ist klar das 
ich das mit den Tastern noch ändern muss aber für Testzwecke sollte es 
langen das ich mit gedrückthalten des Tasters von 0 auf 255 komm). Was 
mache ich falsch?

Autor: kbuchegg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PWMCOUNT ist ein int.
Der zählt bis 65535 bis er einmal überläuft und nicht bis 255, wie du 
angenommen hast.

Autor: Martin Z. (zilluss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wars vielen Dank! Kann ich ja nicht wissen das der Kompeiler mir da 
ein 16Bit int auf nen 8Bit Controller bastelt

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich will mal hoffen, dass du nur den Smily vergessen hast :-)

Autor: Martin Z. (zilluss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaro :-P solche Sachen schleichen sich leider so schnell ein. Das kenn 
ich aber sonst nur aus der PC-Programmierung.

Autor: Martin Z. (zilluss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt hab ich leider das Problem das die jeweiligen Farben auch noch auf 
der untersten PWM Stufe leicht leuchten. Wenn ich aber z.B. einen Taster 
gedrückt halte bleibt die Farbe aus. Weiß jemand woran das liegen 
könnte?

Autor: Urs (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wir wissen nur, dass Du einen AVR, drei Leuchtdioden und anscheinend 
auch irgendwo noch einen Taster hast. Aber ohne zu wissen, wie die 
miteinander jetzt genau verbunden sind kann man Deine Frage leider nicht 
beantworten.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Urs wrote:
> Wir wissen nur, dass Du einen AVR, drei Leuchtdioden und anscheinend
> auch irgendwo noch einen Taster hast. Aber ohne zu wissen, wie die
> miteinander jetzt genau verbunden sind kann man Deine Frage leider nicht
> beantworten.

@Martin

.... wobei dieses
        if(PINB & (1<<PIN0)&& PWM_R++ < 255) PWM_R++;

wenn es denn noch nicht korrigiert wurde, dazu führen wird, das PWM_R 
(falls das noch immer ein int ist) größer als 255 werden kann.

wohingegen die Gegenrichtung
        if(PINB & (1<<PIN1)&& PWM_R++ > 0) PWM_R--;

im Grunde nur Zeitverschwendung ist, den PWM_R wird am Ende unverändert 
bleiben.

PS: Die Analyse, wie diese Vergleiche tatsächlich ausgewertet werden, 
spar ich mir jetzt. Ist mir zu mühsam da jetzt rauszusuchen, ob der 
Compiler die Klammerung der Ausdrücke auch so sieht wie du. Ich hätt 
halt alles klar gemacht, indem ich explizit ein paar Klammern eingefügt 
hätte. Nicht nur für den Compiler sondern auch für mich. Ist einfach 
simpler zu lesen, wenn man nicht gross nachdenken muss, welche Operation 
jetzt höhere Priorität hat: & && oder >  und in welcher Reihenfolge die 
Auswertung passiert.

Aber letztendlich ist das alles Kaffeesatzleserei. Das einzige was man 
mit einiger Sicherheit sagen kann: Du hast einen Fehler im Programm. 
Aber worin der Fehler jetzt besteht lässt sich ohne Programm in seiner 
jetzigen Form nicht sagen.

Autor: Martin Z. (zilluss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen dank für die Antworten. Den Fehler mit den Tasten hab ich schon 
ausgebessert. Komm in letzter Zeit spät heim und dann macht man solche 
Fehler leider sehr schnell.

Hier die verbesserte Version, aber dieses "flimmer" besteht immernoch 
ausser ich halte die dekrementierenden Taster gedrückt. Sind übrigens 
die normalen STK500 Taster also über das Flachbandkabel angeschlossen.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>

#define F_CPU 8000000UL
#define LED_R PORT3
#define LED_B PORT5
#define LED_G PORT7

volatile uint8_t PWMCOUNT = 0;
volatile uint8_t PWM_R,PWM_B, PWM_G;

int main()
{

  DDRD |= 1<<LED_R | 1<<LED_B | 1<<LED_G;
    DDRC &= ~(1<<PORT0 | 1<<PORT1 | 1<<PORT2 | 1<<PORT3 | 1<<PORT4 | 1<<PORT5);
    TCCR0 |= 1<<CS00;
    TIMSK |= 1<<TOIE0;
    sei();
    
    //Start-Testwerte
    PWM_R = 100;
    PWM_B = 100;
    PWM_G = 200;

    while(1)
    {
        if((PINC & (1<<PIN0))&& PWM_R != 255) PWM_R++;
        if((PINC & (1<<PIN1))&& PWM_R != 0) PWM_R--;
        if((PINC & (1<<PIN2))&& PWM_B != 255) PWM_B++;
        if((PINC & (1<<PIN3))&& PWM_B != 0) PWM_B--;
        if((PINC & (1<<PIN4))&& PWM_G != 255) PWM_G++;
        if((PINC & (1<<PIN5))&& PWM_G != 0) PWM_G--;
    }

return 0;

}

ISR(TIMER0_OVF_vect) 
{
        if(PWMCOUNT < PWM_R)
        {
            PORTD |= 1<<LED_R;   
        }
        else
        {
            PORTD &= ~(1<<LED_R);  
        }


        if(PWMCOUNT < PWM_B )
        {
            PORTD |= 1<<LED_B;
        }
        else
        {
            PORTD &= ~(1<<LED_B);
        }


        if(PWMCOUNT < PWM_G)
        {
            PORTD |= 1<<LED_G;
        }
        else
        {
            PORTD &= ~(1<<LED_G);
        }


        PWMCOUNT++;
        return;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmal zur Sicherheit.
Wann brennen deine Leds? Wenn der Portpin auf 0 oder auf 1 gesetzt wird?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Grund der Frage:  (Ich glaube beim STK ist es die übliche Sache: Portpin 
auf 0 schaltet die LED ein. Bin mir aber nicht mehr sicher)
        if(PWMCOUNT < PWM_R)
            PORTD |= 1<<LED_R;     // Led aus 
        else
            PORTD &= ~(1<<LED_R);  // Led ein

Wenn PWM_R den Wert 255 hat, dann wird die Led für PWMCOUNT Werte von 0 
bis 254 ausgeschaltet, aber beim PWMCOUNT Wert von 255 kurz 
eingeschaltet. Die Led ist also nie vollständig aus und das siehst du 
als ganz schwaches Glimmen.

Autor: Martin Z. (zilluss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke sehr nochmals. Ich benutze nicht die LED's des STK500 (die nochmal 
extra über PNP's angesteuert werden glaube ich) sondern habe die RGB-Led 
mit Widerständen über einen Stecker (deshalb auch Port 3,5 und 7) an die 
Ports und die gemeinsame Anode an den Versorgungsspannungspin 
angeschlossen. Die LED leuchtet also bei einer 0 am Pin.

Ich habe es jetzt mal so gedreht:
if(PWMCOUNT < PWM_G)
        {
            PORTD &= ~(1<<LED_G);
        }
        else
        {
            PORTD |= 1<<LED_G;
        }

Die LED dürfte also eigentlich nicht leuchten da wenn LED_G = 0 ist ja 
immer der else-Fall eintritt (eintreten sollte). An was kann es sonst 
noch liegen?

Autor: Martin Z. (zilluss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß noch nicht wieso aber es hängt mit den if-Anweisungen in der 
while-Schleife zusammen. Aber ich frage mich wieso denn die werden ja 
nicht aufgerufen oder?

Autor: Martin Z. (zilluss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibt leider keine Edit-Funktion. Ich habs jetzt aber rausgefunden. Es 
lag an den Tastern die gedrückt 0 sind und deshalb ein ! vor die Abfrage 
muss. Jetzt läuft alles einwandfrei und ich kann mich an die 
Verlangsamung des Tastvorgangs machen. Danke kbuchegg :-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.