Software PWM will nicht?

Gast #1157113
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?
Gast #1159563
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.
#1159602
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.
#1159638
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
}
#1159672
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.
#1159692
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren