mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik PWM-Werte messen


Autor: Owen Senmeis (senmeis)
Datum:

Bewertung
0 lesenswert
nicht 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
if (tmp != 0){} else {}
zu optimieren, damit es schneller laeuft?
Ist es besser mit
if ((tmp & 0x01) != 0)
statt
if ((tmp & 0x01) == 0x01)
?

Code unten:
ISR(TIMER1_COMPA_vect) {
  // andere Bearbeitungen  
  pwm_value = PWM_INPUT_PIN;
}

void pwm_processing(void)
{
  uint8_t tmp;
  uint8_t pwm_counter[8];
  tmp = (~pwm_value_old & pwm_value);
  
  if (tmp != 0)  // Anstiegsflanken ankommen
  {
    if ((tmp & 0x01) == 0x01)
    {
      pwm_input[0] = pwm_counter[0];  // entsprechende Messwerte gueltig machen
      pwm_counter[0] = 0;
    }
    if ((tmp & 0x02) == 0x02)
    {
      pwm_input[1] = pwm_counter[1];
      pwm_counter[1] = 0;
    }
    if ((tmp & 0x04) == 0x04)
    {
      pwm_input[2] = pwm_counter[2];
      pwm_counter[2] = 0;
    }
    if ((tmp & 0x08) == 0x08)
    {
      pwm_input[3] = pwm_counter[3];
      pwm_counter[3] = 0;
    }
    if ((tmp & 0x10) == 0x10)
    {
      pwm_input[4] = pwm_counter[4];
      pwm_counter[4] = 0;
    }
    if ((tmp & 0x20) == 0x20)
    {
      pwm_input[5] = pwm_counter[5];
      pwm_counter[5] = 0;
    }
    if ((tmp & 0x40) == 0x40)
    {
      pwm_input[6] = pwm_counter[6];
      pwm_counter[6] = 0;
    }
    if ((tmp & 0x80) == 0x80)
    {
      pwm_input[7] = pwm_counter[7];
      pwm_counter[7] = 0;
    }
  }
  else
  {
    if ((pwm_value & 0x01) == 0x01)
      pwm_counter[0]++;  // Zaehler erhoehen wenn Eingang HIGH ist
    if ((pwm_value & 0x02) == 0x02)
      pwm_counter[1]++;
    if ((pwm_value & 0x04) == 0x04)
      pwm_counter[2]++;
    if ((pwm_value & 0x08) == 0x08)
      pwm_counter[3]++;
    if ((pwm_value & 0x10) == 0x10)
      pwm_counter[4]++;
    if ((pwm_value & 0x20) == 0x20)
      pwm_counter[5]++;
    if ((pwm_value & 0x40) == 0x40)
      pwm_counter[6]++;
    if ((pwm_value & 0x80) == 0x80)
      pwm_counter[7]++;
  }
  pwm_value_old = pwm_value;  // Messwerte als Referenz fuer naechste Bearbeitung
}
Besten Dank im Vorraus
Senmeis

Autor: Michael Haberler (mah)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sieh Dir mal vertikale Zähler an.

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

- Michael

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Wolfgang Mües (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also,

erstmal ist
(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
 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:
if (tmp & 0x01) {
  pwm_input[0] = *pwm_counter[0];
  pwm_counter[0] = 0;
} else if (pwm_value & 0x01) {
  pwm_counter[0]++;
}
Und das einfach 8 mal hintereinander.
Weitere Optimierungen sind sehr davon abhängig, welchen Assemblercode 
Dein Compiler aus diesem Stück macht!

Autor: Wolfgang Mües (Gast)
Datum:

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

Autor: Owen Senmeis (senmeis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen Dank fuer die Antworten.

Eines habe ich fast vergessen. Die Eingaenge duerfen nur gemessen werden 
wenn richtige Zeitpunkte
ankommen.
Also:
ISR(TIMER1_COMPA_vect) {
// andere Bearbeitungen  
  pwm_value = PWM_INPUT_PIN;
  pwm_read_enable = 1;
}

void pwm_processing(void){
  uint8_t tmp;
  uint8_t pwm_counter[8];
  if (pwm_read_enable == 1)
  {
    pwm_read_enable = 0;
    tmp = (~pwm_value_old & pwm_value);
  
    if (tmp & 0x01) 
    {
        pwm_input[0] = pwm_counter[0];
        pwm_counter[0] = 0;
    } 
    else if (pwm_value & 0x01) 
    {
        pwm_counter[0]++;
    }
    ...
  }
}

Gruss
Senmeis

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.