Forum: Mikrocontroller und Digitale Elektronik Mittelwert Zweierkomplement


von Thomas (Gast)


Lesenswert?

Ich habe ein kleines Problem: Ein 16Bit ADC liefert sein Ergebnis im 
Zweierkomplement, und zwar 2x 8Bit. Nun möchte ich das Ergebnis 16x 
Mitteln, um das Rauschen wegzubekommen.
Eingelesen wird der Wert so:
1
HighByte = DataRead();
2
LowByte = DataRead();
Wie kann ich davon am schnellsten auf einem AVR den Mittelwert bilden 
und am Ende den 16Bitigen Wert erhalten?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

In C? C++ Pascal? Basic? ...

Allgemein:

1) Wert auf Passende Bitzahl (maximale Summe) erweitern (Sign beachten)
2) Aufsummieren
3) Entsprechend der Erweiterung schieben
4) die unteren 16bit sind dein Ergebnis

von Johannes V. (johannes_v)


Lesenswert?

Bist du sicher das dein 16Bit ADC dir 2x8Bit gibt die du mitteln kannst?

Für mich hört sich das eher nach MSB und LSB an.
1
ushort Messwert = (MSB << 8) + LSB;

Zum mitteln brauchst du dann mehr als einen Messwert.

Summe der Messwerte / Anzahl der Messwerte.

Das der ADC dir seinen Wert als 2er komplement bereitstellt ist ein 
Vorteil, du kannst einfach deine Messwerte aufaddieren ohne etwas zu 
beachten.

Falls du auf Genauigkeit verzichten kannst, dann benutze einfach nur das 
MSB als Messwert, das LSB infach ignorieren. Aber pass auf das du beim 
umrechenen zurück zu Spannung dann auch alles richtig machst.

Vref / 8  != Vref / 16

von Thomas (Gast)


Lesenswert?

1
HighByte = DataRead();
ist doch wohl recht eindeutig C/C++...
Pascal hätte := und Basic kein ;

Würde es also so funktionieren?
1
uint32_t erg = 0;
2
3
for (i=0; i<16; i++) {
4
5
  HighByte = DataRead();
6
  LowByte = DataRead();
7
8
  erg += ( ( HighByte * 256) + LowByte );
9
10
}
11
12
erg /= 16;

von NoPoP (Gast)


Lesenswert?

Du machst Dir eine 32 Bit "Akkumulatorvariable"

1) Jeden neuen ADC Wert zum Akkumulator addieren
2) Das jeweilige Ergebnis sichern und durch 16 teilen, also um 4 Bit 
nach links schieben.
3) Diese Ergebnis vom ursprünglichen Akkumulatorergebnis abziehen
4) Das so resultierende Ergebnis wieder 4 Bit nach links geschoben 
ergibt den (ungefähren) Mittelwert.

von NoPoP (Gast)


Lesenswert?

Pardon ..4 Bit nach rechts schieben..

von Johannes V. (johannes_v)


Lesenswert?

Ja, dieser Code sollte korrekt sein.

Aber je nach Anwendung (z.B. sharp Infrarot Sensor) würde ich eher die 
LSBs maskieren anstelle eine Schleife zu betretten.

Aber kommt halt immer drauf an, eine Wetterstation wird wohl kaum wegen 
zu langsamer Sensorauswertung gegen die Wand fahren.

Du musst einfach Anhand deiner Daten zusehen inwiefern sich das rauschen 
bemerkbar macht. Es kann gut sein das deine Schleife sich auch durch
1
short Messwert = (MSB << 8) + (LSB & 0xF0);

ersetzen ließe ohne dass es einen Unterschied macht.


BTW.

Dein 16 Bit ADC gibt dir sein Ergebnis als Zweierkomplement zurück. Bist 
du sicher, dass er auch negative Ergebnisse liefern kann? Ansonsten 
würde ich eifach mal behaupten es ist ein 15 Bit ADC ;)

So oder so, signed Variable wirds schon packen. Aber wenn er 16 Bit 
genauigkeit hat, also Vin = Vref -> Mess = 0xFFFF dann musst du 
unbedingt unsigned verwenden.

Bei 15 Bit währe dein Ergebniss ohnehin 0x7FFF und damit in jedem Fall 
unkritisch.

von Thomas (Gast)


Lesenswert?

Der ADC ist differenziell und liefert tatsächlich 16Bit im 
Zweierkomplement. Also Werte von 1000000000000000 bis 0111111111111111.
Und der angeschlossene Sensor rauscht tatsächlich, daher soll gemittelt 
werden und nicht maskiert, dann könnte ich auch einen 12Bit ADC nehmen.

von Johannes V. (johannes_v)


Lesenswert?

Gut, dann wirsd du um die Schleife nicht herumkommen.

Wie gesagt, dein Akkumulator muss dann aber auch "signed" sein, 
ansonsten sehe ich keinen Fehler in dem Code

von Peter D. (peda)


Lesenswert?

Dem Mittelwert ist es wurscht, ob signed oder unsigned, er funktioniert 
immer richtig.
Beim Teilen mußt Du bei signed das arithmetic Shift right (ASR) nehmen, 
der C-Compiler macht das automatisch richtig. In Assembler mußt Du es 
selber auswählen.
Vorausgesetzt, Du teilst durch 2-er Potenzen.


Peter

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.