Forum: Mikrocontroller und Digitale Elektronik Software PWM will nicht?


von Martin (Gast)


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:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define F_CPU 8000000UL
5
#define LED_R PORT3
6
#define LED_B PORT5
7
#define LED_G PORT7
8
9
volatile int PWMCOUNT = 0;
10
volatile int PWM_R,PWM_B, PWM_G = 0;
11
12
int main()
13
{
14
15
  DDRD |= 1<<LED_R | 1<<LED_B | 1<<LED_G;
16
    DDRB &= ~(1<<PORT0 | 1<<PORT1 | 1<<PORT2 | 1<<PORT3 | 1<<PORT4 | 1<<PORT5);
17
    TCCR0 |= 1<<CS00;
18
    TIMSK |= 1<<TOIE0;
19
    sei();
20
21
    while(1)
22
    {
23
        if(PINB & (1<<PIN0)&& PWM_R++ < 255) PWM_R++;
24
        if(PINB & (1<<PIN1)&& PWM_R++ > 0) PWM_R--;
25
        if(PINB & (1<<PIN2)&& PWM_B++ < 255) PWM_B++;
26
        if(PINB & (1<<PIN3)&& PWM_B++ > 0) PWM_B--;
27
        if(PINB & (1<<PIN4)&& PWM_G++ < 255) PWM_G++;
28
        if(PINB & (1<<PIN5)&& PWM_G++ > 0) PWM_G--;
29
    }
30
31
return 0;
32
33
}
34
35
ISR(TIMER0_OVF_vect) 
36
{
37
        PWMCOUNT++;
38
39
        if(PWM_R > PWMCOUNT)
40
        {
41
            PORTD |= 1<<LED_R;
42
        }
43
        else
44
        {
45
            PORTD &= ~(1<<LED_R);
46
        }
47
48
49
        if(PWM_B > PWMCOUNT)
50
        {
51
            PORTD |= 1<<LED_B;
52
        }
53
        else
54
        {
55
            PORTD &= ~(1<<LED_B);
56
        }
57
58
59
        if(PWM_G > PWMCOUNT)
60
        {
61
            PORTD |= 1<<LED_G;
62
        }
63
        else
64
        {
65
            PORTD &= ~(1<<LED_G);
66
        }
67
}

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?

von kbuchegg (Gast)


Lesenswert?

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

von Martin Z. (zilluss)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

Ich will mal hoffen, dass du nur den Smily vergessen hast :-)

von Martin Z. (zilluss)


Lesenswert?

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

von Martin Z. (zilluss)


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?

von Urs (Gast)


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.

von Karl H. (kbuchegg)


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
1
        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
1
        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.

von Martin Z. (zilluss)


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.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
5
#define F_CPU 8000000UL
6
#define LED_R PORT3
7
#define LED_B PORT5
8
#define LED_G PORT7
9
10
volatile uint8_t PWMCOUNT = 0;
11
volatile uint8_t PWM_R,PWM_B, PWM_G;
12
13
int main()
14
{
15
16
  DDRD |= 1<<LED_R | 1<<LED_B | 1<<LED_G;
17
    DDRC &= ~(1<<PORT0 | 1<<PORT1 | 1<<PORT2 | 1<<PORT3 | 1<<PORT4 | 1<<PORT5);
18
    TCCR0 |= 1<<CS00;
19
    TIMSK |= 1<<TOIE0;
20
    sei();
21
    
22
    //Start-Testwerte
23
    PWM_R = 100;
24
    PWM_B = 100;
25
    PWM_G = 200;
26
27
    while(1)
28
    {
29
        if((PINC & (1<<PIN0))&& PWM_R != 255) PWM_R++;
30
        if((PINC & (1<<PIN1))&& PWM_R != 0) PWM_R--;
31
        if((PINC & (1<<PIN2))&& PWM_B != 255) PWM_B++;
32
        if((PINC & (1<<PIN3))&& PWM_B != 0) PWM_B--;
33
        if((PINC & (1<<PIN4))&& PWM_G != 255) PWM_G++;
34
        if((PINC & (1<<PIN5))&& PWM_G != 0) PWM_G--;
35
    }
36
37
return 0;
38
39
}
40
41
ISR(TIMER0_OVF_vect) 
42
{
43
        if(PWMCOUNT < PWM_R)
44
        {
45
            PORTD |= 1<<LED_R;   
46
        }
47
        else
48
        {
49
            PORTD &= ~(1<<LED_R);  
50
        }
51
52
53
        if(PWMCOUNT < PWM_B )
54
        {
55
            PORTD |= 1<<LED_B;
56
        }
57
        else
58
        {
59
            PORTD &= ~(1<<LED_B);
60
        }
61
62
63
        if(PWMCOUNT < PWM_G)
64
        {
65
            PORTD |= 1<<LED_G;
66
        }
67
        else
68
        {
69
            PORTD &= ~(1<<LED_G);
70
        }
71
72
73
        PWMCOUNT++;
74
        return;
75
}

von Karl H. (kbuchegg)


Lesenswert?

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

von Karl H. (kbuchegg)


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)
1
        if(PWMCOUNT < PWM_R)
2
            PORTD |= 1<<LED_R;     // Led aus 
3
        else
4
            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.

von Martin Z. (zilluss)


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:
1
if(PWMCOUNT < PWM_G)
2
        {
3
            PORTD &= ~(1<<LED_G);
4
        }
5
        else
6
        {
7
            PORTD |= 1<<LED_G;
8
        }

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?

von Martin Z. (zilluss)


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?

von Martin Z. (zilluss)


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 :-)

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.