Forum: Mikrocontroller und Digitale Elektronik Vermessung eines Signals mit 50MHz µC


von Hans F. (dani1632)


Lesenswert?

Hallo!

Ich will mit einem 50 MHz µC von Atmel ein 50kHz Rechtecksignal mit 
einem Duty Cycle von 90% vermessen. Dazu verwende ich einen Timer, der 
mit 25 MHz läuft (Maximum). Ich starte den Timer bei einer positiven 
Flanke des Signales, lade den Timerwert bei der negativen Flanke in ein 
Register (der Timer wird bei der nächsten positiven Flanke wieder von 0 
gestartet). Bei jeder negativen Flanke wird ein Interrupt aufgerufen, in 
dessen Service Routine ich die Werte verarbeite. Ich habe also für diese 
Verarbeitung so lange Zeit, wie das Signal auf Low ist (Duty Cycle 90%). 
Die Periodendauer bei 50kHz ist 20ms, für die Verarbeitung habe ich also 
2ms (10% Low-Time) Zeit. Wie wichtig ist hier die Geschwindigkeit der 
Verarbeitung (Effizienz des Codes), wenn der µC mit 50MHz läuft?

Ich will für die Werte einen gleitenden Mittelwertfilter verwenden. Dazu 
wird jeder neue Wert in ein Array geschrieben (z.B. 100 Werte, wobei 
nach Überlauf wieder bei 0 begonnen wird), und jedesmal von allen 100 
Werten ein Mittelwert gebildet wird, der mit dem aktuellen Wert 
verglichen wird. Ich muss also immer das gesamte Array in einer 
for-Schleife durchlaufen und alle Werte aufsummieren, danach durch die 
Anzahl der Werte dividieren). Wie könnte man hier eine effizientere 
Möglichkeit realisieren?

Hab im Moment den Code leider nicht verfügbar, deswegen habe ich es 
versucht im Text zu beschreiben...
Vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

>  Ich starte den Timer bei einer positiven Flanke des Signales,
> lade den Timerwert bei der negativen Flanke in ein Register
> (der Timer wird bei der nächsten positiven Flanke wieder von
> 0 gestartet). Bei jeder negativen Flanke wird ein Interrupt
> aufgerufen, in dessen Service Routine ich die Werte verarbeite.

Hat denn der µC keine Input Capture Unit am Timer?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

>  Ich muss also immer das gesamte Array in einer for-Schleife durchlaufen und 
alle Werte aufsummieren

Nö, musst du nicht.

Du brauchst nur aus der Summe den jeweils ältesten Wert raussubtrahieren 
und den jüngsten Wert addieren. Und schon ist deine Summe wieder 
aktuell.

Wenn du dich nicht auf 100 Werte kaprizierst, sondern auf eine 2-er 
Potenz, zb 128, dann vereinfacht sich auch die Division extrem, so dass 
dieser Mittelwert mit 1 Addition, 1 Subtraktion und ein bischen 
Bitschieben aktuell gehalten werden kann. d.h. Solange du keine 
Nachkommastellen brauchst. Brauchst du die, dann macht man halt statt 
dessen eine Fixpunkt Arithmetik, dann fällt das Schieben bei der 
Ermittlung des Mittelwertes auch noch raus.

Und dann gibts da ja auch noch den gleitenden Mittelwert, bei dem man 
sich dann auch die älteren Werte nicht mehr merken muss.

: Bearbeitet durch User
von Thomas Z. (tezet)


Lesenswert?

Falls du die einzelnen Werte nicht später irgendwie brauchst, dann macht 
es wenig Sinn, diese in einem Array zu halten und immer neu zu 
Summieren. Google man nach gleitendem Mittelwert. Du brauchst nur eine 
Summe zu speichern.

von Karl H. (kbuchegg)


Lesenswert?

>  in dessen Service Routine ich die Werte verarbeite.

kommt drauf an, was genau du unter "verarbeiten" verstehst.
In der ISR sammelst du erst mal die Daten. Wenn neue Daten vorliegen, 
dann setzt die ISR ein Flag, so dass dann die Hauptschleife gemütlich 
die Daten auswerten kann. Das schlimmste was dir passieren kann ist, 
dass die Hauptschleife nicht hinterherkommt und ab und auch mal einen 
von der ISR ermittelten Datensatz auslässt. Meistens ist das aber kein 
Beinbruch.

von Hans F. (dani1632)


Lesenswert?

@ Karl Heinz:
ja, der µC hat eine Capture UNit und die verwende ich auch...
OK, aber woher weiß ich den ältesten wert, den ich aus der Summe 
subtrahieren muss?

Was meinst du mit "und dann gibt es da noch den gleitenden 
Mittelwert...". Sind denn deine Beschreibungen mit den Bitshifts nicht 
auf gleitende Mitelwerte bezogen? Ich benötige einen gleitenden 
Mittelwert der jeweils letzten X werte. Die genaue Zahl von X kenne ich 
nocht nicht, wenn das aber nicht so relevant ist, werde ich das mit den 
Bitshifts auf alle Fälle ausprobieren.

@Thomas: Danke für den Tip, die Werte brauche ich später wirklich nicht, 
es geht nur darum den mittelwert zu berechnen. Aber auch in diesem Fall 
meien Frage: woher kenn ich dann den ältesten wert, den ich subtrahieren 
muss?

Was ich ursprünglih auch wissen wollte, ist, wie lange der 50MHz µC 
(grob) für folgende verarbeitung brauch: ein paar variablenzuweisungen 
(weniger als 5), und eine for-schleife, die die 100 werte des arrays 
durchläuft, die werte aufsummiert und dann für den mittelwert durch die 
anzahl dividiert. Liegt das ungefähr im bereich von 2 ms, also der Zeit, 
die das Signal auf Low ist. Ich bin da sehr unerfahren, liegt das 
ungefähr in diesem Bereich, deutlich drunter, deutlich drüber? wenn er 
mit 50MHz getaktet ist, dann benötigt er für eine Schritt ja 20ns. Kann 
ich nuun davon ausgehen, dass der µC für eine Codezeile 20ns braucht 
oder ist das komplett ein falscher Ansatz?

Danke, lg

von Purzel H. (hacky)


Lesenswert?

Schau mal nach 'exponentieller Mittelwert' in Wikipedia, oder bei
http://www.ibrtses.com/embedded/exponential.html
Das ist viel einfacher. Mit genau einer Speicherzelle.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Daniel F. schrieb:
> @ Karl Heinz:
> ja, der µC hat eine Capture UNit und die verwende ich auch...

Das hier
>  Ich starte den Timer bei einer positiven Flanke des Signales, lade den 
Timerwert bei der negativen Flanke in ein Register (der Timer wird bei der 
nächsten positiven Flanke wieder von 0 gestartet).

klingt aber nicht danach.
Spar dir doch das 0-setzen. Lass den Timer durchlaufen, dann ist die 
Zeitermittlung einfach nur Differenzbildung von Timerwerten, die die 
Capture Unit festgestellt hat.
Immer dieses 'Ich starte einen Timer, ich stoppe einen Timer, ich setzte 
den Timer 0'.
Brauchst du alles nicht. Man kann mit einer Uhr mit Sekundenzeiger 
genausogut stoppen: Wenn der Rennläufer losfährt zeigt der 
Sekundenzeiger auf 15. Wenn er ankommt ist der Sekundenzeiger auf 48. 
Also war er 48-15 = 33 Sekunden unterwegs.

> OK, aber woher weiß ich den ältesten wert, den ich aus der Summe
> subtrahieren muss?

Woher weißt du denn, wo ins Array der nächste Wert rein muss?
Der Wert der vorher dort stand ist der älteste.

Das ist dein Array (5 Werte)
1
  Array               wo wird der nächste Wert abgelegt
2
  0 0 0 0 0             0
3
4
  Summe: 0
der erste Wert kommt: 15
am Index 0 steht der älteste Wert. Der wird in bälde mit den 15 
überschrieben, aber vorher stand da 0
1
  15 0 0 0 0            1
2
3
Summe = alte Summe - 0 + 15 = 15

nächster Wert kommt: 18
die Indexvariable sagt dir, dass er ins Array an die Position 1 muss. 
dort steht jetzt eine 0, die wird durch 18 überschrieben
1
  15 18 0 0 0          2
2
3
Summe = 15 - 0 + 18 = 33

der nächste Wert kommt: 12
er kommt ins Array an die Position 2. vorher stand da 0, jetzt kommt 12 
rein
1
  15 18 12 0 0          3
2
3
  Summe = 33 - 0 + 12 = 45

nächster WErt: 14
Er kommt an die Position 3, vorher 0, jetzt 14
1
  15 18 12 14 0         4
2
3
  Summe = 45 - 0 + 14 = 59

nächster Wert 17. Achtung: Der Indexzähler hat das Ende des Arrays 
erreicht und wird wieder auf 0 getzt!
1
  15 18 12 14 17        0
2
3
  Summe = 59 - 0 + 17 = 76

nächster Wert 21
Der kommt an die Indexposition 0 ins Array (das ist gleichzeitig auch 
der älteste Wert im Array). Vorher stand da 15, jetzt kommt 21 rein
1
   21 18 12 14 17        1
2
3
  Summe = 76 - 15 + 21 = 82

nächster Wert: 17
Der kommt ins Array an die Position 1, dort ist auch der älteste Wert im 
Array, nämlich die 18.
1
   21 17 12 14 17         2
2
3
  Summe = 82 - 18 + 17 = 81

Kurze Probe zwischendurch:
1
 21 + 17 + 12 + 14 + 17 = 81
2
3
 Passt
4
 =====

und so geht das weiter.
Die Indexvariable sagt dir wo der nächste Wert hinmuss. Dort steht der 
älteste Wert im Array, den holst du dir, ziehst in von der Summe ab, 
speicherst den neuen Wert ins Array, zählst den zur Summe dazu und 
stellst die Indexvariable um 1 weiter. Ist die Indexvariable am Ende des 
Arrays angelangt, dann geht es vorne bei 0 wieder los.

> Was meinst du mit "und dann gibt es da noch den gleitenden
> Mittelwert...".

Bitte google danach.
Das ist ein feststehender Begriff und es gibt genügend Links dazu.
Wahrscheinlich ein paar Zehntausend mehr als du brauchst.

: Bearbeitet durch User
von Hans F. (dani1632)


Lesenswert?

Vielen Dank für die Hilfe :)

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.