Forum: Compiler & IDEs Anfänger Frage zu PWM beim ATMEGA8


von Martin R. (m-joy)


Lesenswert?

Guten Tag,
Ich bin totaler anfänger, und versuche eine ganz simple 
aufgabenstellung, an der ich scheitere :( ich versuche per ATMEGA8 über 
pin PB1 eine LED zu dimmen. Dafür habe ich ein tutorial für den ATMEGA16 
gelesen, und wollte dieses nun auf den ATMEGA8 anwenden, was wohl 
garnicht so leicht ist.
Folgendes habe ich nun :

1
#define F_CPU 1000000UL  // 1 MHz
2
  
3
#include <avr/io.h>
4
#include <util/delay.h>
5
{
6
void InitPWM()
7
8
   TCCR2= (1<<WGM20)|(1<<COM21)|(1<<CS20);
9
   DDRB|=(1<<PB1);
10
}
11
12
void SetPWMOutput(uint8_t duty)
13
{
14
   OCR2=duty;
15
}
16
17
void Wait()
18
{
19
 _delay_loop_2(3200);
20
}
21
22
void main()
23
{
24
   uint8_t brightness=0;
25
26
    InitPWM();
27
28
   
29
   while(1)
30
   {
31
      
32
      for(brightness=0;brightness<255;brightness++)
33
      {
34
        
35
         SetPWMOutput(brightness);
36
37
         Wait();
38
      }
39
40
     
41
      for(brightness=255;brightness>0;brightness--)
42
      {
43
44
         SetPWMOutput(brightness);
45
46
         Wait();
47
      }
48
   }
49
}



wieso funktioniert da garnichts :(

lg

von Karl H. (kbuchegg)


Lesenswert?

Martin Rocks schrieb:

> wieso funktioniert da garnichts :(

Weil der OC2 Pin (da wo die PWM vom Timer 2 rauskommt) beim Mega8 nicht 
der Pin PB1 sondern PB3 ist

von Martin R. (m-joy)


Lesenswert?

Guten Tag,
alsooo jetzt habe ich den ausgang umgeändert in:
1
DDRB|=(1<<PB3);

aber es klappt immernoch nicht.... :( Ist der Timer 2 überhaupt 
brauchbar für das vorhaben?

grüßeee

von Martin R. (m-joy)


Lesenswert?

ahhhh jetzt tut sich etwas..., wenn das das so abändere:
1
 DDRB|=(1<<PB3);
2
  TCCR2= (1<<WGM21)|(1<<WGM20)|(1<<COM21)|(1<<CS20);


könnte ich denn auch den PB1 ansteuern? vielleicht auch gleichzeitig?

lg

von Martin R. (m-joy)


Lesenswert?

Bitte erneut um Hilfe !
Ich habe jetzt alle 3 PWM Kanäle programmiert, und möchte diese jeweils 
unabhängig von 3 Schaltern, die an PC0- PC2 hängen anschalten, und 
wieder abschalten können. Angesteuert werden 3 LEDs, die sich an PB1-PB3 
befinden. Mein Problem ist, wenn ich alle 3 Taster drücke, läuft jeweils 
nur eine LED (PB1) und wenn diese durchlaufen ist, läuft die nächste.... 
aber ich kann nicht alle 3 gleichzeitig anlassen. wieso?
1
#define F_CPU 1000000U  // 1 MHz
2
  
3
#include <avr/io.h>
4
#include <util/delay.h>
5
6
7
void InitPWM()
8
{
9
   DDRB|= (1<<PB1) | (1<<PB2) | (1<<PB3);
10
   TCCR2= (1<<WGM20)|(1<<COM21)|(1<<CS20);
11
   TCCR1A = (1<<WGM10) | (1<<COM1A1)|(1<<COM1B1); // 8bit-Counter, nicht invert. PWM
12
   TCCR1B = (1<<CS10); // Pre-Scaler = 1
13
   DDRC|=(0<<PC0) | (0<<PC1) | (0<<PC2);
14
   PORTC |= (1<<PC0) | (1<<PC1) | (1<<PC2); // PULL UPS 
15
16
}
17
18
/******************************************************************
19
         duty
20
 Vout=  ------ x 5v
21
         255 
22
23
This can be used to control the brightness of LED or Speed of Motor.
24
*********************************************************************/
25
26
27
/******************************************************************** 
28
29
Simple Wait Loop
30
31
*********************************************************************/
32
33
void Wait()
34
{
35
  _delay_loop_2(3200);
36
}
37
38
   void DIMMER1 ()
39
   {
40
   uint8_t brightnessc1=0;
41
   for(brightnessc1=0;brightnessc1<255;brightnessc1++)
42
        {
43
          if ( !(PINC & (1<<PINC0)) )
44
            { do
45
                {
46
                brightnessc1=brightnessc1--;
47
                OCR1A=brightnessc1;
48
                Wait();
49
                }
50
              while (brightnessc1!=0);
51
                main();
52
               }
53
        OCR1A=brightnessc1;
54
        Wait();
55
        }
56
    
57
    
58
    
59
       for(brightnessc1=255;brightnessc1>0;brightnessc1--)
60
            {
61
          if ( !(PINC & (1<<PINC0)) )
62
            { do
63
                {
64
                brightnessc1=brightnessc1--;
65
                OCR1A=brightnessc1;
66
                Wait();
67
                }
68
              while (brightnessc1!=0);
69
              main();
70
              }
71
             OCR1A=brightnessc1;
72
           Wait();
73
            }  
74
  } // von DIMMER1      
75
      
76
void DIMMER2()
77
{
78
  uint8_t brightnessc2=0;
79
        for(brightnessc2=0;brightnessc2<255;brightnessc2++)
80
        {
81
          if ( !(PINC & (1<<PINC1)) )
82
            { do
83
                {
84
                brightnessc2=brightnessc2--;
85
                OCR1B=brightnessc2;
86
                Wait();
87
                }
88
              while (brightnessc2!=0);
89
                main();
90
               }
91
        OCR1B=brightnessc2;
92
        Wait();
93
        }
94
    
95
    
96
    
97
       for(brightnessc2=255;brightnessc2>0;brightnessc2--)
98
            {
99
          if ( !(PINC & (1<<PINC1)) )
100
            { do
101
                {
102
                brightnessc2=brightnessc2--;
103
                OCR1B=brightnessc2;;
104
                Wait();
105
                }
106
              while (brightnessc2!=0);
107
              main();
108
              }
109
             OCR1B=brightnessc2;
110
           Wait();
111
            }  
112
113
      } // von DIMMER2    
114
  
115
void DIMMER3()
116
{
117
  uint8_t brightnessc3=0;
118
 for(brightnessc3=0;brightnessc3<255;brightnessc3++)
119
        {
120
          if ( !(PINC & (1<<PINC2)) )
121
            { do
122
                {
123
                brightnessc3=brightnessc3--;
124
                 OCR2=brightnessc3;
125
                Wait();
126
                }
127
              while (brightnessc3!=0);
128
                main();
129
               }
130
        OCR2=brightnessc3;
131
        Wait();
132
        }
133
    
134
    
135
    
136
       for(brightnessc3=255;brightnessc3>0;brightnessc3--)
137
            {
138
          if ( !(PINC & (1<<PINC2)) )
139
            { do
140
                {
141
                brightnessc3=brightnessc3--;
142
                OCR2=brightnessc3;
143
                Wait();
144
                }
145
              while (brightnessc3!=0);
146
              main();
147
              }
148
             OCR2=brightnessc3;
149
           Wait();
150
            }  
151
} // von DIMMER3  
152
153
void main()
154
{
155
  
156
InitPWM();
157
158
//Do this forever
159
160
while(1)
161
  {
162
// ************************************ PIN C0 ******************************************************
163
164
      if ( PINC & (1<<PINC0) ) /* Fuehre Aktion aus, wenn Bit Nr. 0 (das "erste" Bit) in PINC gesetzt (1) ist */
165
    {
166
      DIMMER1();
167
    }
168
    
169
// ************************************ PIN C1 ******************************************************
170
      if ( PINC & (1<<PINC1) ) /* Fuehre Aktion aus, wenn Bit Nr. 0 (das "erste" Bit) in PINC gesetzt (1) ist */
171
    {
172
      DIMMER2();
173
    }
174
// ************************************ PIN C2 ******************************************************
175
      if ( PINC & (1<<PINC2) ) /* Fuehre Aktion aus, wenn Bit Nr. 0 (das "erste" Bit) in PINC gesetzt (1) ist */
176
    {
177
        DIMMER3();
178
    }        
179
   }      //von while(1)
180
   
181
   }    // von (main)

von Ralf (Gast)


Lesenswert?

Martin Rocks schrieb:
> while (brightnessc3!=0);
>               main();

'main();' ??????

'DIMMER()' würde ich nur einmal machen und mit Parameter aufrufen.

von Martin R. (m-joy)


Lesenswert?

Huhuu Ralf =) ja das mit main() ist verwirrend, aber ich wusst enicht 
wie ich sonst aus der schleife raus komme G

aber wenn ich die ganze unterschleife entferne (die war dafür dass die 
LED den aktuellen helligkeitswert speichert, und dann nicht direkt 
ausgeht sondern ausdimmt, wenn ich den schalter umlege), klappt es 
immernoch nicht....

ich möchte ja alle 3 kanäle parallel laufen haben,.... also so wäre die 
methode ohne unterschleife:
1
#define F_CPU 1000000U  // 1 MHz
2
  
3
#include <avr/io.h>
4
#include <util/delay.h>
5
6
7
void InitPWM()
8
{
9
   DDRB|= (1<<PB1) | (1<<PB2) | (1<<PB3);
10
   TCCR2= (1<<WGM20)|(1<<COM21)|(1<<CS20); 
11
   TCCR1A = (1<<WGM10) | (1<<COM1A1)|(1<<COM1B1); // 8bit-Counter, nicht invert. PWM
12
   TCCR1B = (1<<CS10); // Pre-Scaler = 1
13
   DDRC|=(0<<PC0) | (0<<PC1) | (0<<PC2);
14
   PORTC |= (1<<PC0) | (1<<PC1) | (1<<PC2); //PULL UPS  
15
16
}
17
18
/******************************************************************
19
         duty
20
 Vout=  ------ x 5v
21
         255 
22
23
This can be used to control the brightness of LED or Speed of Motor.
24
*********************************************************************/
25
26
27
/******************************************************************** 
28
29
Simple Wait Loop
30
31
*********************************************************************/
32
33
void Wait()
34
{
35
  _delay_loop_2(3200);
36
}
37
38
   void DIMMER1 ()
39
   {
40
   uint8_t brightnessc1=0;
41
   for(brightnessc1=0;brightnessc1<255;brightnessc1++)
42
        {
43
        OCR1A=brightnessc1;
44
        Wait();
45
        }
46
      
47
       for(brightnessc1=255;brightnessc1>0;brightnessc1--)
48
            {
49
       OCR1A=brightnessc1;
50
           Wait();
51
            }  
52
  } // von DIMMER1      
53
      
54
void DIMMER2()
55
{
56
  uint8_t brightnessc2=0;
57
        for(brightnessc2=0;brightnessc2<255;brightnessc2++)
58
        {
59
        OCR1B=brightnessc2;
60
        Wait();
61
        }
62
    
63
    
64
       for(brightnessc2=255;brightnessc2>0;brightnessc2--)
65
            {          
66
             OCR1B=brightnessc2;
67
           Wait();
68
            }  
69
70
      } // von DIMMER2    
71
  
72
void DIMMER3()
73
{
74
  uint8_t brightnessc3=0;
75
  for(brightnessc3=0;brightnessc3<255;brightnessc3++)
76
        {
77
        OCR2=brightnessc3;
78
        Wait();
79
        }
80
    
81
  for(brightnessc3=255;brightnessc3>0;brightnessc3--)
82
            {
83
             OCR2=brightnessc3;
84
           Wait();
85
            }  
86
} // von DIMMER3  
87
88
void main()
89
{
90
  
91
InitPWM();
92
93
//Do this forever
94
95
while(1)
96
  {
97
// ************************************ PIN C0 ***************************************
98
99
      if ( PINC & (1<<PINC0) ) /* Fuehre Aktion aus, wenn Bit Nr. 0 (das "erste" Bit) in PINC gesetzt (1) ist */
100
    {
101
      DIMMER1();
102
    }
103
    
104
// ************************************ PIN C1 ***********************************
105
      if ( PINC & (1<<PINC1) ) /* Fuehre Aktion aus, wenn Bit Nr. 0 (das "erste" Bit) in PINC gesetzt (1) ist */
106
    {
107
      DIMMER2();
108
    }
109
// ************************************ PIN C2 *****************************************
110
      if ( PINC & (1<<PINC2) ) /* Fuehre Aktion aus, wenn Bit Nr. 0 (das "erste" Bit) in PINC gesetzt (1) ist */
111
    {
112
        DIMMER3();
113
    }        
114
   }      //von while(1)
115
   
116
   }    // von (main)

schaltplan:
http://www7.pic-upload.de/01.06.11/311te4rbdri1.png

von Ralf (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Martin Rocks schrieb:
>
>> wieso funktioniert da garnichts :(
>
> Weil der OC2 Pin (da wo die PWM vom Timer 2 rauskommt) beim Mega8 nicht
> der Pin PB1 sondern PB3 ist

...

von Martin R. (m-joy)


Lesenswert?

ähhh...?? hä :D

also timer 2 funktioniert. timer 1 auch mit 2 pwm kanälen... aber nicht 
gleichzeitig. das ist ja das problem. ich weiß nicht ob das n fehler in 
der schleife ist, oder ob der atmega8 damit generell nicht klar kommt oO

von Ralf (Gast)


Lesenswert?

Im Simulator funktioniert alles so, wie es programmiert ist.
Sind die LEDs wirklich so angeschlossen, wie im Schaltplan?
Die Schalter sind 'low-activ' angeschlossen, 'high' wird aber abgefragt.

von Felix (Gast)


Lesenswert?

Zum Warum:
Du fragst in deiner While(1) Loop einen Schalter ab und führst dann zB 
Dimmer1 aus. Dabei wird die LED auf- und abgedimmt.
DANACH fragst du den zweiten Schalter ab und es wird ggfs die zweite LED 
auf- und abgedimmt.
Das gleiche mit dem dritten Schalter und der dritten LED.
Also alles nacheinander!

Du musst das "parallelisieren".
Gibt verschiedene Wege...
ZB den Zustand in "Dimmer" global merken und bei jedem Aufruf von Dimmer 
immer nur einen Schritt weiter gehen.
Der Programmdurchlauf ist schnell genug und du siehst alle LEDs quasi 
gleichzeitig dimmen. Ist dann halt von der Programmdurchlaufzeit 
abhängig.
Oder du arbeitest mit einem Interrupt.
Der gibt dir einen regelmäßigen Zeittick und davon abhängig gehst du in 
deiner Dimmerfunktion einen Schritt weiter. Dann muss der 
Programmdurchlauf zwar immer noch zügig sein (was er auch locker ist), 
aber du kannst die Geschwindigkeit des Dimmens ohne lästige Waits 
steuern und hast noch Zeit für anderes.

von Ralf (Gast)


Lesenswert?

Felix schrieb:
> Du fragst in deiner While(1) Loop einen Schalter ab und führst dann zB
> Dimmer1 aus. Dabei wird die LED auf- und abgedimmt.
> DANACH fragst du den zweiten Schalter ab und es wird ggfs die zweite LED
> auf- und abgedimmt.
> Das gleiche mit dem dritten Schalter und der dritten LED.
> Also alles nacheinander!

Und das funktioniert_ _so auch fehlerfrei (Simulator).

von Felix (Gast)


Lesenswert?

Das kann ja sein, aber er fragte doch, warum die nicht gleichzeitig 
angehen, wenn er alle Knöpfe gleichzeitig drückt, bzw. was er machen 
muss, damit alle gleichzeitig dimmen können.

von Martin R. (m-joy)


Lesenswert?

ahhh "parallelisieren" ist das stichwort !
klasse..... oh man das hört sich aber schwer an mit den interrupts usw.
Urghs. Okay muss ich schauen wie ich das hinbekomme.
Aber vielen dank für eure hilfe :) :)

grüüße

von Felix (Gast)


Lesenswert?

Kannst es ja auch erstmal ohne Interrupts machen.
Du musst dir den Zustand des Dimmens außerhalb der Dimm-Funktion merken.
Stichwort globale Variable.
Bei jedem Aufruf veränderst du den Zustand.
Du kannst ja auch die Funktion aufteilen in Aufdimmen1() und 
Abdimmen1().
Über Merker (Flags) signalisierst du dann am Funktionsende, dass zB das 
Aufdimmen fertig ist und jetzt Abdimmen an der Reihe ist.
Dann kannst du das Flag mit "if" abfragen und entscheiden, welche 
Funktion jetzt dran ist.
Wenn dir die Schritte des Dimmens dann zu schnell sind musst du eben 
irgendwo warten (unschön) oder den Aufruf der Dimmfunktionen verzögern.
Soll heißen nicht bei jedem Durchlauf ausführen.
ZB in der While(1) Loop eine Variable hochzählen (Runtime++;)
dann irgendwo sowas wie
if (RunTime>=100) {
RunTime=0;
if (Flag) {
 Flag=0;
 AbDimmer1();
}
else
 AufDimmen1();
}
Dann wird das nur noch alle 100 Durchläufe ausgeführt.
Diesen Zähler kann man dann später in einen Timerinterrupt verlegen, 
dann ist er genauer. Ein Programmdurchlauf kann ja unterschiedlich lang 
sein, wenn es Aufgaben gibt, die nicht immer zu erledigen sind (zB etas 
über UART ausgeben oder so).

So in etwa.

von Felix (Gast)


Lesenswert?

Nächstes Thema das du dir ansehen solltest ist dann "Eingang 
entprellen".
Viel Erfolg.

von Martin R. (m-joy)


Lesenswert?

waaaah ich glaub ich muss gleich erstmal meinen kopf entprellen xD
ich komme gerade garnicht mehr zurecht. aber wenigstens weiß ich jetzt 
wo der fehler liegt. mal sehen was ich drauß mache. vielen dank nochmal.
falls jemand, der sich damit aus kennt, lust hat mich per icq in dem 
vorhaben zu unterstützen darf mich gerne adden : 105565858
würd mich freuen ;)
grüüüßeee

von Martin R. (m-joy)


Lesenswert?

huhu,
ich krisgs nicht gebacken mit den interrupts. keinen plan davon. auch 
das tutorial zu interrupts bringt mich kein stück weiter.
kann mir vlt jemand erklären wie das geht? welche interrupts ich brauche 
und wofür oO

lg

von Felix (Gast)


Lesenswert?

Hallo Martin,

hast du es denn erst mal ohne Interrupts so umgebaut, dass deine LEDs 
quasi gleichzeitig dimmbar sind? Das brauchst du für die 
interruptgesteuerte Variante auch. Der Interrupt soll dir ja später nur 
einen genaueren Zeitpunkt fürs "Weiterschalten" liefern, also das 
Zeitmanagment übernehmen.

Der Interrupt den du dann anschließend verwendest, braucht eine 
Auslösebedingung. Für diesen Zweck bietet sich ein TimerOverFlow 
Interrupt an. In den meisten Anwendungen läuft dafür beispielsweise 
Timer0. 8Bit reichen hier völlig, da wir ja eine möglichst kleine 
Zeitbasis haben wollen, zählen wir eh nicht so weit.
Ein Overflowinterrupt alle 10ms wäre zB gut. Das bedeutet, du musst 
Timer0 konfigurieren. Dabei spielt dein verwendeter Takt eine Rolle.
Du musst also alles so einstellen, dass dein Timer0 alle 10ms überlauft.
Dann aktivierst du noch die Interrupts über das entsprechende Bit.
Das war es dann schon fast, es fehlt dann nur noch die Interruptroutine.
Das ist im Prinzip nur eine Funktion mit bestimmten Namen, die über eben 
diesen Namen an eine bestimmte Bedingung (hier Timer0 Overflow) 
gekoppelt wird.
In dieser Funktion zählst du einfach eine Variable. Da der Interrupt ja 
fest alle 10ms ausgelöst wird, hast du nun eine feste Zeitbasis.
Du kannst beispielsweise immer bis 10 zählen und ein neues Flag setzen, 
dass dir 100ms signalisiert.

Wichtig ist, dass die Interruptsoutine schnell abzuarbeiten ist. Also 
hier keine aufwändigen Berechnungen und tief verschachtelte 
Funktionsaufrufe!
Außerdem mußt du bedenken, dass der Interrupt ja immer dazwischen haut 
und dein Programm kurz unterbricht. Er weiß zwar wo er danach weiter 
machen muss, aber es gibt ein paar Dinge zu beachten. Variablen die im 
Interrupt geändert werden und dann noch woanders verwendet werden müssen 
als volatile deklariert werden. Aufpassen musst du auch bei 
zeitkritischen Sachen in deinem Code, beispielsweise wenn bestimmte 
Timings für irgendwas eingehalten werden müssen. Dann musst du deinen 
Code davor schützen, dass der Interrupt dazwischen haut. Stichwort 
"atomic block", "CLI()", "SEI()"...
Hört sich vielleicht alles gefährlich an, ist es aber nicht. Man muss 
hier eben nur ein bisschen aufpassen und sorgfältig arbeiten. Dein 
Programm ist eine gute Übung!

Also mein Tipp:
Erstmal alles so umbauen, dass deine LEDs gleichzeitig ohne Interrupt 
dimmbar sind.
Danach sind deine Stichworte Timer0 und OverFlowInterrupt.
Hoffe das hilft weiter.

Gruß
Felix

von Felix (Gast)


Lesenswert?


von Martin R. (m-joy)


Lesenswert?

wuhuuu felix du bist auf jedenfall der beste ^^
wat würd ich nur ohne dich tun...:P

jahaaa also nach stundenlangen qualen habe ich es irgendwie mittels 
globaler variablen hinbekommen jepeee*freu*
ich bin allerdings der meinung, dass es sehr unschön und unkompakt 
programmiert ist. wie könnte ich das nun optimieren? Bisher habe ich es 
nur mit 2 kanälen gemacht....aber der 3. ist dann auch nimmer das 
problem :P
1
#define F_CPU 1000000U  // 1 MHz
2
  
3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include <stdlib.h>
6
7
 uint8_t Zustand,Zustand2;
8
 uint8_t brightness1,brightness2;
9
10
void InitPWM()
11
{
12
   DDRB|= (1<<PB1) | (1<<PB2) | (1<<PB3);
13
   TCCR1A = (1<<WGM10) | (1<<COM1A1)|(1<<COM1B1); // 8bit-Counter, nicht invert. PWM
14
   TCCR1B = (1<<CS10); // Pre-Scaler = 1, also ohne Teiler
15
   DDRC|=(0<<PC0) | (0<<PC1) | (0<<PC2);
16
}
17
void aufdimmen ()
18
      {    if (brightness1!=255)
19
        brightness1++;
20
        else Zustand=1;
21
      }
22
void abdimmen ()
23
      {    if (brightness1!=0)
24
        brightness1--;
25
        else Zustand=0;
26
      }
27
void aufdimmen2 ()
28
      {    if (brightness2!=255)
29
        brightness2++;
30
        else Zustand2=1;
31
      }
32
void abdimmen2 ()
33
      {    if (brightness2!=0)
34
        brightness2--;
35
        else Zustand2=0;
36
      }
37
38
void Wait()
39
{
40
  _delay_loop_2(3200);
41
}
42
43
void main()
44
{
45
InitPWM();
46
Zustand=0; //startwert
47
Zustand2=0;
48
brightness1=0; //startwert
49
brightness2=0; //startwert
50
//Do this forever
51
while(1)
52
  {
53
      if ( PINC & (1<<PINC0) )
54
    {
55
        if (Zustand==0)   //bei Zustand 0 aufdimmen
56
        {
57
          aufdimmen();
58
        }
59
        else      //bei Zustand 1 abdimmen
60
          abdimmen();
61
    }
62
63
      if ( PINC & (1<<PINC1))
64
    {
65
        if (Zustand2==0)   //bei Zustand 0 aufdimmen
66
        {
67
          aufdimmen2();
68
        }
69
        else      //bei Zustand 1 abdimmen
70
          abdimmen2();
71
    }    
72
     pwmoutput();
73
   }      //von while(1)
74
}    // von (main)
75
76
77
void pwmoutput()
78
{
79
OCR1A=brightness1;
80
OCR1B=brightness2;
81
Wait();
82
}

von Felix (Gast)


Lesenswert?

Schön, dass es hilft. Du machst aber auch deinen Teil! Ich gebe ja nur 
Denkanstöße... Aber ich bin sicherlich kein Profi.

Jedenfalls gefällt mir dein Programm schon ganz gut.
Schön kommentiert und eingerückt (bis auf die IFs der Pinabfrage, aber 
das kann ja dem Upload geschuldet sein). So lernt man Schritt für 
Schritt.
Daher immer der Rat von allen, macht das Tutorial durch und fangt mit 
ner LED an!

Ich finde man sieht jetzt hier 3 Dinge ganz gut:
1) Die beiden Dimmvorgänge laufen unabhängig voneinander.
2) Du hast 4 Funktionen (auf- und abdimmen), von denen jeweils 2 genau 
das gleiche machen, nur eben mit anderen Variablen.
3) Das Wait() in pwmoutput()

Punkt 1) löst erstmal dein urpsprüngliches Problem.

Punkt 2) finde ich auch nicht so schön kompakt, vor allem wenn man 
bedenkt, dass ja noch die dritte LED fehlt. Und vielleicht kommt ja noch 
eine 4.?
Hier könntest du ja jetzt eine Funktion LEDXaufdimmen() und eine 
Funktion LEDxabdimmen() schreiben, die Parameter übergeben bekommt.
Da ja immer exakt das gleiche gemacht wird, ist dies quasi ein Fall aus 
dem Lehrbuch. Kriegst du das hin?

Punkt 3) deutet auch schon in Richtung Timer und Interrupt.
Solange du nichts anderes in deinem Programm machst, stört das Wait() 
nicht. Aber du musst es dir als aktives Warten vorstellen, dh es wird 
erzwungen, dass NICHTS gemacht wird. Und das für einen Zeitraum, der für 
einen uControlller verdammt lang ist!
Ohne Timer und Interrupts gibt es jetzt noch einen Weg, das ohne Wait zu 
machen. Der sieht aber erstmal umständlich aus. Bei jedem Durchlauf 
zählst du eine Variable (zB 16bit) und beispielsweise immer wenn sie bei 
30000 ist, setzt du sie zu 0 und führst deine Funktionen aus. Du kannst 
dir auch ausrechenen bis wohin du zählen musst, damit du etwa die 
gleiche Zeit wartest. Das Funktioniert aber nur bedingt (su).
Das bedeutet dann zwei Dinge:
Es wird nicht mehr aktiv gewartet, sondern es gibt ganz kurze Durchläufe 
in denen nichts anderes gemacht wird, als die Variable hochzuzählen.
Und zweitens deine Zählgeschwindigkeit ist genau davon abhängig, ob im 
Programm noch was anderes gemacht werden soll oder nicht.
Du hast quasi die Zeit, die vorher aktiv gewartet wurde, für andere 
Aufgaben gewonnen. Aber wenn du relativ gleichmäßig Dimmen willst, dann 
kommst du um den Timer und den Interrupt nicht herum. Das ist dann eine 
saubere Lösung. Und der Systemtick, den du dir mit dem Timer erzeugst, 
läßt sich für alles mögliche benutzen. Es ist also immer gut, ihn zu 
haben. :-)

Noch zwei Anmerkungen:
- Die globalen Variablen Zustand und Brightness würde ich noch etwas 
"sprechender" bennennen. Vielleicht ZustandLED1 und BrightnessLED1 oder 
besser LED1Zustand und LED1Brightness. etc.
- Die IF-Abfragen beim Dimmen würde ich eher nicht mit != lösen.
Ist zwar völlig korrekt, aber mit <=255 und >=0 liest es sich meiner 
Meinung nach einfacher und praktischer Nebeneffekt ist, du baust eine 
weitere Sicherung ein. Ist zwar hier unwahrscheinlich, aber stell dir 
vor deine Variable wird irgendwie verändert (Programmerweiterung, 
kosmische Strahlung, was weiß ich) und Brightness wird >255, dann zählst 
du munter weiter hoch (wenn es 16bit wären). Abfragen auf <= und >= sind 
sicherer als Abfragen auf == und !=. Da du nicht auf genau einen Zustand 
abfragst.
Klingt vielleicht etwas an den Haaren herbeigezogen, aber warum nicht 
diese "Sicherheit" einbauen, wenn es nichts kostet?! Kann ja sein, dass 
du irgendwann deinen Datentyp von uint8_t auf int8_t oder uint16_t 
änderst...

Weiter so.

Gruß
Felix

von Felix (Gast)


Lesenswert?

Felix schrieb:
> - Die IF-Abfragen beim Dimmen würde ich eher nicht mit != lösen.
> Ist zwar völlig korrekt, aber mit <=255 und >=0 liest es sich meiner
> Meinung nach einfacher und ...

Es muss natürlich <255 und >0 heißen...

von Martin R. (m-joy)


Angehängte Dateien:

Lesenswert?

Hurraa ich bin on fire, ich habs mal wieder hinbekommen, diesmal sogar 
in rekordzeit G

Jetzt muss ich nur noch das mit den interrupts irgendwie schaffen ;)

das programm ist im anhang


vielen dank nochmal
das mit den interrupts schaff ich auch noch G
CPU load steht bei 85%, sieht viel aus oO

von Karl H. (kbuchegg)


Lesenswert?

Martin Rocks schrieb:
> Hurraa ich bin on fire, ich habs mal wieder hinbekommen, diesmal sogar
> in rekordzeit *G*
>
> Jetzt muss ich nur noch das mit den interrupts irgendwie schaffen ;)

Lies dir lieber in deiner C-Lehrbuch das Kapitel über Arrays durch

von Martin R. (m-joy)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Martin Rocks schrieb:
>> Hurraa ich bin on fire, ich habs mal wieder hinbekommen, diesmal sogar
>> in rekordzeit *G*
>>
>> Jetzt muss ich nur noch das mit den interrupts irgendwie schaffen ;)
>
> Lies dir lieber in deiner C-Lehrbuch das Kapitel über Arrays durch



hmmm....? nicht so unkonkret bitte herr buchegger :)

von Karl H. (kbuchegg)


Lesenswert?

Martin Rocks schrieb:
> Karl Heinz Buchegger schrieb:
>> Martin Rocks schrieb:
>>> Hurraa ich bin on fire, ich habs mal wieder hinbekommen, diesmal sogar
>>> in rekordzeit *G*
>>>
>>> Jetzt muss ich nur noch das mit den interrupts irgendwie schaffen ;)
>>
>> Lies dir lieber in deiner C-Lehrbuch das Kapitel über Arrays durch
>
>
>
> hmmm....? nicht so unkonkret bitte herr buchegger :)

Was ist am Stichwort "Array" unkonkret?

von Felix (Gast)


Lesenswert?

>> DDRC|=(0<<PC0) | (0<<PC1) | (0<<PC2);       //PC0-PC2 mit "0" als Eingänge 
deklarieren

Löschen funktioniert so nicht!

Den Hinweis mit dem Array versteh ich gerade auch nicht...

von Karl H. (kbuchegg)


Lesenswert?

Felix schrieb:
>>> DDRC|=(0<<PC0) | (0<<PC1) | (0<<PC2);       //PC0-PC2 mit "0" als Eingänge
> deklarieren
>
> Löschen funktioniert so nicht!
>
> Den Hinweis mit dem Array versteh ich gerade auch nicht...

brightness1, brightness2

und jetzt machen wir mal 30 PWM Stufen. Willst du da wirklich 30 
Variablen einzeln anlegen?

Genau dazu gibt es Arrays!

int brightness[30];

und wir haben die 30 Variablen. Um auf eine einzelne zuzugreifen, genügt 
es den Index zu variieren:
    brightness[5] = 232;
und den Index kann man sogar über einen Ausdruck berechnen lassen

   for( i = 0; i < 30; i++ )
      brightness[i] = 0;


Lernt doch die Sprache! Ihr verschenkt doch Power, wenn ihr nur 10% der 
Sprache beherrscht.

von Felix (Gast)


Lesenswert?

Ja ok, da kann man das benutzen. Fand ich jetzt nicht so wild, aber ok.

von Karl H. (kbuchegg)


Lesenswert?

Felix schrieb:
> Ja ok, da kann man das benutzen. Fand ich jetzt nicht so wild, aber ok.

Es ist nie wirklich wild.
Nach dem Array wartet dann das nächste: Strukturen
Auch die kann man hier nutzbringend einsetzen.

Und plötzlich wird dann aus einem Programm, welches bisher hauptsächlich 
aus Copy&Paste "Programmierung" für 3 Kanäle besteht, ein simpler 5 
Zeiler in der Hauptschleife, der dann auch noch banal zu parametrieren 
geht.

von Martin R. (m-joy)


Lesenswert?

Guten Abend Herr Burchegger,

mir ist aufgefallen, dass Sie als Moderator sehr viel darüber reden wie 
toll man alles machen kann und wie toll Sie das alles können. Leider 
haben Sie mir bei meinem Problem noch nicht so wirklich weiter helfen 
können.
Wenn Sie das Programm in 5 Zeilen schaffen, dann lassen Sie uns doch 
bitte an Ihrem Wissen teil haben, und zeigen uns wie das funktioniert.
Darüber wäre ich sehr erfreut.

Ich möchte nochmal anmerken, dass das hier mein erstes Programm ist. 
Dafür finde ich das schon ziemlich gut.

grüüüßeee

von Guru (Gast)


Lesenswert?

Genau Herr Buchegger. Machen Sie mal. Nicht das der TO noch was 
selbermachen muss. Tststs. ;-)

von Martin R. (m-joy)


Lesenswert?

uaaargh nach langem gewusel und gewurschtel ist das jetzt endlich 
einigermaßen fertig :)
Ich belasse es vorerst so, und bedanke mich bei allen die mir geholfen 
haben. Vlt sehen wir uns ja schon bald im nächsten thread wieder :)
1
#define F_CPU 8000000U  // 8 MHz
2
       
3
#include <avr/io.h>
4
#include <stdlib.h>
5
#include <avr/interrupt.h>
6
//Globale Variablen:
7
volatile unsigned char mstime[3],pwmwert[3];     //0-255, bei 256 wechselt er auf 0
8
volatile uint8_t LED[3];            //LED 0 bis LED 2
9
10
void InitPWM()
11
{
12
       DDRB|= (1<<PB1) | (1<<PB2) | (1<<PB3);          //PB1-PB3 mit "1" als Eingänge deklarieren
13
     DDRC|=(0<<PC0) | (0<<PC1) | (0<<PC2);           //PC0-PC2 mit "0" als Eingänge deklarieren
14
     PORTC |= (1<<PC0) | (1<<PC1) | (1<<PC2);        // PULL UPS an für Taster
15
       TCCR0=(1<<CS00);                  // prescaler 1
16
       TIMSK = (1<<TOIE0);                  // T0 Starten, Overflow Interrupt f/256                                     
17
}
18
void main()
19
{
20
uint8_t n=0;
21
InitPWM();
22
  
23
while(1)
24
       {
25
      for (n=0;n<=2;n++)
26
            {     cli();
27
          if ( PINC & (1<< n) )      //wenn schalter n gedrückt
28
                    {
29
                          LED[n]=1;
30
                    }      
31
                    
32
                    if ( !(PINC & (1<< n)) )
33
                    {
34
                          PORTB &= ~(1 << n+1);    // Ausgang auf low, LED aus
35
                          LED[n]=0;
36
                    }
37
      }  
38
    n=0;
39
    sei();
40
   }             //von while(1)
41
}                            // von (main)
42
43
ISR(TIMER0_OVF_vect) 
44
{  
45
  uint8_t i=0;
46
  
47
  for (i=0;i<=2;i++)
48
    {if (LED[i]==1)
49
       {
50
       mstime[i]++;
51
       if (mstime[i] == 255)
52
       {
53
       pwmwert[i]++;
54
       }
55
       
56
       if (mstime[i] == 0)
57
           PORTB |= (1 << i+1);        // Ausgang auf high, LED Leuchtet 
58
             
59
           if (mstime[i] > pwmwert[i])
60
           PORTB &= ~(1 << i+1);      // Ausgang auf low, LED aus
61
        }       
62
   }                         
63
}

grüße

von Karl H. (kbuchegg)


Lesenswert?

Martin Rocks schrieb:
> uaaargh nach langem gewusel und gewurschtel ist das jetzt endlich
> einigermaßen fertig :)

Schon viel besser.

Und, hats weh getan seine Kentnisse zu verbessern?
Das nächste Sprachkonstrukt wartet schon: Strukturen

von Karl H. (kbuchegg)


Lesenswert?

Martin Rocks schrieb:

> Wenn Sie das Programm in 5 Zeilen schaffen, dann lassen Sie uns doch
> bitte an Ihrem Wissen teil haben, und zeigen uns wie das funktioniert.
> Darüber wäre ich sehr erfreut.


Wissen sie, Herr Rocks:

Ich helfe gerne Leuten durchaus auch mit Code aus.
Aber wenn ich der Meinung bin, dass es sich beim Nichtkönnen um absolute 
Grundlagentechniken handelt, die in jedem, aber auch wirklich jedem 
C-Buch ohne Probleme zu finden sind, weil es sich um etwas handelt, dass 
dort in einem eigenen Kapitel seitenweise beschrieben und erklärt wird, 
dann spar ich mir das.
Es ist leider ein weit verbreiteter Irrtum, dass man eine 
Programmiersprache ohne ausreichende Unterlagen lernen könnte.

von Martin R. (m-joy)


Lesenswert?

Herr Buchegger, Sie haben recht, ich gebe es zu. Ich glaube wir zwei 
können noch gute Freunde werden :P

Aber manchmal ist für einen Anfänger der Code hilfreicher, wenn man null 
peil hat.... Das ist so, als wäre man in China Urlaub machen, und kann 
kein chinesisch. Selbst mit einem chinesischen Wörterbuch ist man da 
manchmal hilflos :P


greetings

von Klaus W. (mfgkw)


Lesenswert?

... aber nach China fahren, um dort vom ersten Tag an schwieige Dinge
zu besprechen (=MC programmieren), ohne vorher mal ein paar Brocken
chinesisch zu lernen (C-Grundlagen, Tutorial zu AVR), ist nicht
besonders schlau.

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.