Forum: Mikrocontroller und Digitale Elektronik PWM-Werte messen


von Owen S. (senmeis)


Lesenswert?

Servus,

ich muss 8 Kanaele von PWMs mit einem ATmega128 messen, wobei die 
PWM-Periode 20ms ist und der PWM-Schritt 100us betraegt.

Eine Timer1-ISR gibt die 100us-Zeitbasis und aktualisiert die 
Eingangswerte.
Die Methode pwm_processing() macht die Verarbeitungen und aktualisiert 
das Zielarray pwm_input[].
Eine Anstiegsflanke deutet auf den Anfang eines PWM-Zykluses.

Die Frage ist, ob es moeglich ist, diesen Vorgang
1
if (tmp != 0){} else {}
zu optimieren, damit es schneller laeuft?
Ist es besser mit
1
if ((tmp & 0x01) != 0)
statt
1
if ((tmp & 0x01) == 0x01)
?

Code unten:
1
ISR(TIMER1_COMPA_vect) {
2
  // andere Bearbeitungen  
3
  pwm_value = PWM_INPUT_PIN;
4
}
5
6
void pwm_processing(void)
7
{
8
  uint8_t tmp;
9
  uint8_t pwm_counter[8];
10
  tmp = (~pwm_value_old & pwm_value);
11
  
12
  if (tmp != 0)  // Anstiegsflanken ankommen
13
  {
14
    if ((tmp & 0x01) == 0x01)
15
    {
16
      pwm_input[0] = pwm_counter[0];  // entsprechende Messwerte gueltig machen
17
      pwm_counter[0] = 0;
18
    }
19
    if ((tmp & 0x02) == 0x02)
20
    {
21
      pwm_input[1] = pwm_counter[1];
22
      pwm_counter[1] = 0;
23
    }
24
    if ((tmp & 0x04) == 0x04)
25
    {
26
      pwm_input[2] = pwm_counter[2];
27
      pwm_counter[2] = 0;
28
    }
29
    if ((tmp & 0x08) == 0x08)
30
    {
31
      pwm_input[3] = pwm_counter[3];
32
      pwm_counter[3] = 0;
33
    }
34
    if ((tmp & 0x10) == 0x10)
35
    {
36
      pwm_input[4] = pwm_counter[4];
37
      pwm_counter[4] = 0;
38
    }
39
    if ((tmp & 0x20) == 0x20)
40
    {
41
      pwm_input[5] = pwm_counter[5];
42
      pwm_counter[5] = 0;
43
    }
44
    if ((tmp & 0x40) == 0x40)
45
    {
46
      pwm_input[6] = pwm_counter[6];
47
      pwm_counter[6] = 0;
48
    }
49
    if ((tmp & 0x80) == 0x80)
50
    {
51
      pwm_input[7] = pwm_counter[7];
52
      pwm_counter[7] = 0;
53
    }
54
  }
55
  else
56
  {
57
    if ((pwm_value & 0x01) == 0x01)
58
      pwm_counter[0]++;  // Zaehler erhoehen wenn Eingang HIGH ist
59
    if ((pwm_value & 0x02) == 0x02)
60
      pwm_counter[1]++;
61
    if ((pwm_value & 0x04) == 0x04)
62
      pwm_counter[2]++;
63
    if ((pwm_value & 0x08) == 0x08)
64
      pwm_counter[3]++;
65
    if ((pwm_value & 0x10) == 0x10)
66
      pwm_counter[4]++;
67
    if ((pwm_value & 0x20) == 0x20)
68
      pwm_counter[5]++;
69
    if ((pwm_value & 0x40) == 0x40)
70
      pwm_counter[6]++;
71
    if ((pwm_value & 0x80) == 0x80)
72
      pwm_counter[7]++;
73
  }
74
  pwm_value_old = pwm_value;  // Messwerte als Referenz fuer naechste Bearbeitung
75
}
Besten Dank im Vorraus
Senmeis

von Michael H. (mah)


Lesenswert?

Sieh Dir mal vertikale Zähler an.

http://everything2.com/e2node/vertical%2520counter

- Michael

von STK500-Besitzer (Gast)


Lesenswert?

>wobei die PWM-Periode 20ms ist und der PWM-Schritt 100us betraegt.

Klingt nach Modellbau.

Die Impule werden danei immer nacheinander übertragen.
Man muß also nur gucken, ob sich der aktuelle Zustand zum vorherigen 
geändert hat.
Hat sich nichts geändert, und ist der entsprechende Eingang noch High, 
dann zählt man die zugehörige Variable hoch.
Ist der Eingang auf low gegangen, dann muß man das Ergebnis 
weiterverarbeiten.

Wenn es wirklich um Modellbau-Impulse geht, dann sind deine 
100µs-Abtastrate etwas sehr grob. Du kämst auf Werte zwischen 10 und 
20...

von Wolfgang Mües (Gast)


Lesenswert?

Also,

erstmal ist
1
(value & maske) == maske
schon ein Ausdruck zuviel. Denn value & maske kann nur entweder 0 oder 
maske sein, und dann kann man auch nur auf 0 bzw != 0 testen.

Dann sollte man noch wissen, dass if in c implizit auf != 0 testet, d.h.
man schreibt in einem solchen Fall
1
 if (value & maske) {

Wenn ich Deinen Code richtig verstehe, dann möchtest Du die maximal 
verbrauchte Zeit minimieren, so dass der Code IMMER in weniger als 100us 
abläuft. Also ist solch ein Konstrukt wie if (tmp != 0) am Anfang, das 
nur zur Beschleunigung im nicht-worst-case Fall dient, überflüssig und 
verschlechtert nur den worst-case Fall.

Dann fällt auf, dass Du pwm_counter entweder als static deklarieren 
solltest oder außerhalb der Funktion. Sonst gehen die Werte darin 
verloren zwischen 2 Funktionsaufrufen.

Außerdem denke ich, das erste if() in Deinem Code kann eigentlich so 
nicht stimmen, denn Du möchtest bestimmt den else- Zweig für jedes Bit 
durchlaufen, wo keine Flanke gekommen ist.

Ich versuche jetzt mal einen anderen Entwurf:
1
if (tmp & 0x01) {
2
  pwm_input[0] = *pwm_counter[0];
3
  pwm_counter[0] = 0;
4
} else if (pwm_value & 0x01) {
5
  pwm_counter[0]++;
6
}
Und das einfach 8 mal hintereinander.
Weitere Optimierungen sind sehr davon abhängig, welchen Assemblercode 
Dein Compiler aus diesem Stück macht!

von Wolfgang Mües (Gast)


Lesenswert?

Sorry, vor dem ersten pwm_counter ist natürlich das "*" überflüssig...

von Owen S. (senmeis)


Lesenswert?

vielen Dank fuer die Antworten.

Eines habe ich fast vergessen. Die Eingaenge duerfen nur gemessen werden 
wenn richtige Zeitpunkte
ankommen.
Also:
1
ISR(TIMER1_COMPA_vect) {
2
// andere Bearbeitungen  
3
  pwm_value = PWM_INPUT_PIN;
4
  pwm_read_enable = 1;
5
}
6
7
void pwm_processing(void){
8
  uint8_t tmp;
9
  uint8_t pwm_counter[8];
10
  if (pwm_read_enable == 1)
11
  {
12
    pwm_read_enable = 0;
13
    tmp = (~pwm_value_old & pwm_value);
14
  
15
    if (tmp & 0x01) 
16
    {
17
        pwm_input[0] = pwm_counter[0];
18
        pwm_counter[0] = 0;
19
    } 
20
    else if (pwm_value & 0x01) 
21
    {
22
        pwm_counter[0]++;
23
    }
24
    ...
25
  }
26
}

Gruss
Senmeis

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.