Forum: Compiler & IDEs Sehr langsame Ausführung des Programms


von Maxim (Gast)


Lesenswert?

1
#define F_CPU 8000000L
2
 
3
#include <inttypes.h>
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <avr/pgmspace.h>
7
8
#define R_LED     PD2
9
#define G_LED     PD3
10
#define B_LED     PD4
11
#define LED_PORT   PORTD
12
#define PORT_DIR  DDRD
13
14
15
////////////////////////////////////////////////////////////////////////////////////////////////////
16
17
uint8_t    r, g, b;
18
uint16_t  phase;
19
20
////////////////////////////////////////////////////////////////////////////////////////////////////
21
22
void set_rgb(uint8_t r_new, uint8_t g_new, uint8_t b_new){
23
  
24
  r = r_new;
25
  g = g_new;
26
  b = b_new;
27
}
28
29
////////////////////////////////////////////////////////////////////////////////////////////////////
30
31
int main(void){
32
  
33
  phase = 0;
34
35
  PORT_DIR |= ((1<<R_LED) | (1<<G_LED) | (1<<B_LED));
36
37
  set_rgb(50, 50, 50);
38
39
  while(1){
40
    
41
    if(phase == r) LED_PORT &= ~(1<<R_LED);
42
    if(phase == g) LED_PORT &= ~(1<<G_LED);
43
    if(phase == b) LED_PORT &= ~(1<<B_LED);
44
45
    phase++;
46
47
    if(phase == 0) LED_PORT |= ((1<<R_LED) | (1<<G_LED) | (1<<B_LED));
48
  }
49
50
  return 0;
51
}

Der Quellcode ist sehr einfach und bedarf keiner Kommentare. Bei der 
Ausführung auf einem ATmega8 @ 8Mhz blinkt die LED ungefähr in einem 1/2 
Sekunden Takt. Daraus folgere ich, dass die while-Schleife wohl nur 
zweimal in der Sekunde durchläuft. Kann das sein?

von Jan (Gast)


Lesenswert?

Ja, das kommt hin.
Vier Vergleiche a vier Takte, ein inkrementieren 2 Takte, 2 Takte für 
die Schleife. Macht im besten Falle 20 Takte, die 2^16 Mal durchlaufen 
werden - macht 1.3 Millionen, also nicht sehr weit von deinen 
geschätzten 4 Millionen entfernt.

von Karl H. (kbuchegg)


Lesenswert?

Maxim wrote:

> Sekunden Takt. Daraus folgere ich, dass die while-Schleife wohl nur
> zweimal in der Sekunde durchläuft.

Die while Schleife wird schon öfter als 2 mal in der Sekunde
durchlaufen. Aber phase muss jedesmal bis 65535 hochgezählt werden,
bis dann durch den Überlauf wieder 0 in phase steht. Wenn das
2 mal pro Sekunde passiert, ist die while Schleife also mehr
in der Größenordnung von 130000 mal durchlaufen worden.

von Maxim (Gast)


Lesenswert?

>Die while Schleife wird schon öfter als 2 mal in der Sekunde
>durchlaufen. Aber phase muss jedesmal bis 65535 hochgezählt werden,
>bis dann durch den Überlauf wieder 0 in phase steht. Wenn das
>2 mal pro Sekunde passiert, ist die while Schleife also mehr
>in der Größenordnung von 130000 mal durchlaufen worden.

Ach stimmt! War gestern zu müde um das zu sehen. Es gibt also keinen Weg 
die PWM-Frequenz zu steigern? Wäre vielleicht ein Timer besser dafür 
geeignet?

von Johannes M. (johnny-m)


Lesenswert?

Maxim wrote:
> Ach stimmt! War gestern zu müde um das zu sehen. Es gibt also keinen Weg
> die PWM-Frequenz zu steigern? Wäre vielleicht ein Timer besser dafür
> geeignet?
Gibt es einen triftigen Grund für eine 16-Bit-Zählvariable? Entweder ne 
8-Bit-Variable nehmen (Faktor 256 in der Geschwindigkeit) oder sozusagen 
ein "CTC" (Clear Timer on Compare Match) in Software machen, also bei 
Erreichen eines bestimmten Zählwertes den Zähler zurücksetzen. Ich denke 
mal, eine Auflösung von 65536 Schritten ist i.d.R. eh nicht wirklich 
sinnvoll.

BTW:
Ich sehe grad, dass r, g, und b sowieso nur 8 Bit breit sind. Was soll 
dann überhaupt das mit der 16-Bit-Zählvariable? phase sollte 
sinnigerweise auch uint8_t sein, und nicht uint16_t.

von Maxim (Gast)


Lesenswert?

>Gibt es einen triftigen Grund für eine 16-Bit-Zählvariable? Entweder ne
>8-Bit-Variable nehmen (Faktor 256 in der Geschwindigkeit) oder sozusagen
>ein "CTC" (Clear Timer on Compare Match) in Software machen, also bei
>Erreichen eines bestimmten Zählwertes den Zähler zurücksetzen. Ich denke
>mal, eine Auflösung von 65536 Schritten ist i.d.R. eh nicht wirklich
>sinnvoll.

>BTW:
>Ich sehe grad, dass r, g, und b sowieso nur 8 Bit breit sind. Was soll
>dann überhaupt das mit der 16-Bit-Zählvariable? phase sollte
>sinnigerweise auch uint8_t sein, und nicht uint16_t.

Danke für deine Vorschläge. Die 16-Bit-Auflösung ist nicht sinnlos 
gewählt. Ich braue sie um später ein exponentielles Anwachsen des 
Stromes durch einen linearen Faktor im Programm zu realisieren. Die 
8-Bit Variablen r, g und b werden dann durch eine Tabelle auf einen 
16-bittigen Wert umgerechnet, welcher mit dem Zähler vergliechen wird 
...

Zuerst muss das Programm aber wenigstens so funktionieren. Ich habe den 
Zähler auf Timer1 umgestellt. Die LED blinkt trotzdem etwa zweimal in 
der Sekunde auf. Es kann doch nicht sein, dass der ATMega8 bei 8Mhz 
keine dreifache software-PWM packt?!

Ach ja, CTC passt hier nicht, da ich ja drei unabhängige PWM-Signale 
brauche.

von Johannes M. (johnny-m)


Lesenswert?

Maxim wrote:
> Danke für deine Vorschläge. Die 16-Bit-Auflösung ist nicht sinnlos
> gewählt. Ich braue sie um später ein exponentielles Anwachsen des
> Stromes durch einen linearen Faktor im Programm zu realisieren. Die
> 8-Bit Variablen r, g und b werden dann durch eine Tabelle auf einen
> 16-bittigen Wert umgerechnet, welcher mit dem Zähler vergliechen wird
> ...
>
> Zuerst muss das Programm aber wenigstens so funktionieren. Ich habe den
> Zähler auf Timer1 umgestellt. Die LED blinkt trotzdem etwa zweimal in
> der Sekunde auf. Es kann doch nicht sein, dass der ATMega8 bei 8Mhz
> keine dreifache software-PWM packt?!
Doch, aber nicht mit der Auflösung. So ist das nunmal in einer 
Hochsprache. Und dann auch noch mit 16-Bit-Zahlenwerten, deren 
Verarbeitung sowieso deutlich länger dauert als bei 8-Bit-Werten.

> Ach ja, CTC passt hier nicht, da ich ja drei unabhängige PWM-Signale
> brauche.
Das eine hat mit dem anderen nichts zu tun. Ich sagte schließlich "in 
Software". Und da kannst Du auch einen Grenzwert setzen, ohne dafür 
andere Ressourcen einzubüßen. Das ist dann nur eine zusätzliche Abfrage, 
die zwar an sich den Durchlauf der Schleife ein wenig verlängert, aber 
insgesamt gesehen das ganze durchaus beschleunigen kann. Wenn Du 
anstelle von 16 Bit auf z.B. 11 Bit runtergehst, hast Du immerhin einen 
Faktor von ungefähr 32 in der Geschwindigkeit gewonnen. Du zählst dann 
eben nicht bis 65535, sondern nur bis 2047. Dementsprechend sind dann 
natürlich auch die Tabellenwerte anzupassen. Da die Größe der Tabelle im 
Mega8 sowieso ziemlich beschränkt sein dürfte (es sei denn, Du legst die 
Werte in einem externen Speicher ab), wirst Du um eine (lineare) 
Interpolation von Stützwerten eh nicht rumkommen. Und da macht es sicher 
keinen sichtbaren Unterschied, ob Du mit 16 oder mit 11 Bit arbeitest.

von Falk B. (falk)


Lesenswert?

@ Maxim (Gast)

>Danke für deine Vorschläge. Die 16-Bit-Auflösung ist nicht sinnlos
>gewählt. Ich braue sie um später ein exponentielles Anwachsen des
>Stromes durch einen linearen Faktor im Programm zu realisieren. Die

AHA.

LED-Fading

>der Sekunde auf. Es kann doch nicht sein, dass der ATMega8 bei 8Mhz
>keine dreifache software-PWM packt?!

Schon mal nachgerechnet? Per 16 Bit Timer und 8 MHz Takt kommst du auf 
~123Hz PWM-Freqeunz. Pech nur dass deine Schleife "etwas" mehr als einen 
Takt braucht.

Ergo.
Mach eine 8-Bit PWM in Software, das reicht. Siehe Artikel.

>Ach ja, CTC passt hier nicht, da ich ja drei unabhängige PWM-Signale
>brauche.

Dann brauchst du einen festen Timer, der den PWM Takt in Software 
nachbildet.
100 Hz, 8 Bit -> 39us.

MfG
Falk

von Maxim (Gast)


Lesenswert?

Hm, da wäre es fast besser, für jede Farbe einen ATTiny zu nehmen.

Ich probiere mal eine geringere Auflösung aus.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Maxim wrote:

> Hm, da wäre es fast besser, für jede Farbe einen ATTiny zu nehmen.

Oder gleich einen AT90PWM3?

von Maxim (Gast)


Lesenswert?

Die beste Lösung ist 12-Bit in Software. Die LED flackert fast gar nicht 
und die Auflösung ist ausreichend.

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.