Forum: Mikrocontroller und Digitale Elektronik AVR-gcc Mit Kommazahl dividieren


von AVR-Junge (Gast)


Lesenswert?

Hallo!
Ich möchte einen 8 Bit ADC-Wert auf einer 2-Stelligen 7-Segmentanzeige 
ausgeben lassen. Die Ausgabefunktion "versteht" nur uint8_t-Zahlen.
Theoretisch muss ich den ADC-Wert ja nun durch 2.55 teilen. Wie mache 
ich das am einfachsten?

Ich benutze AVRStudio 6 und programmiere in C. µC ist ein ATmega328.

Viele Grüße
Jürgen

von foo (Gast)


Lesenswert?

AVR-Junge schrieb im Beitrag #4187138:
> Theoretisch muss ich den ADC-Wert ja nun durch 2.55 teilen. Wie mache
> ich das am einfachsten?
1
 adc_wert / 2.55

Deine Referenzspannung ist 1 Volt?

von chris (Gast)


Lesenswert?

rechne doch mal 100 und dann durch 255

von Stefan (Gast)


Lesenswert?

dein µC kann doch sicher auch floats berechnen oder?
Teile deinen ADC Wert durch deine 2,55 natürlich alles als float und 
benutze zum Ausgeben den sprintf befehl. Sollte auch gehen oder?

von Malte S. (maltest)


Lesenswert?

Nur dass sowohl Fließkomma als auch printf Unmengen Ballast 
mitschleppen.
adc_value * 100 / 255
Wesentlich ist nur die Reihenfolge von Multiplikation und Division.

Edit:
@chris: haste ja schon gesagt... Habe deinen Post nur gerade ganz anders 
gelesen gehabt.

: Bearbeitet durch User
von lrep (Gast)


Lesenswert?

AVR-Junge schrieb im Beitrag #4187138:
> Theoretisch muss ich den ADC-Wert ja nun durch 2.55 teilen. Wie mache
> ich das am einfachsten?

Indem du mit 1/2,55 also 0,3921... multiplizierst.
Da das mit Integer Arithmetik nicht so ohne weiteres möglich ist, 
multiplizierst du die beiden Faktoren ersteinmal mit 2**N 
(linksschieben), bis du genügend viele  Stellen vor dem Komma hast, 
führst da die Multiplikation aus, evtl. auch eine Rundung oder 
Truncation, und anschliessend dividierst du durch 2**2N (rechtsschieben) 
und enhältst das gewünschte Ergebnis.

von Amateur (Gast)


Lesenswert?

Die Grundzahl in die Länge ziehen Byte -> Word oder sogar DWord.

Kräftig multiplizieren oder schneller schieben.

Dann Division durchziehen und danach dividieren (vorherige 
Multiplikation rückgängig machen) bzw. zurückschieben (schneller).

Geht flott, zumindest schneller als Deine Anzeige.

Braucht keine Fließkommabibliotheken.

von AVR-Junge (Gast)


Lesenswert?

Danke, die *100-Rechnung passt wunderbar, da hätt ich mal selbst drauf 
kommen können :)

von Max D. (max_d)


Lesenswert?

Wenn du durch 256 teilst wird das normal zu einem schieben optimiert und 
ist u.U. Immernoch genau genug.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Max D. schrieb:
> Wenn du durch 256 teilst wird das normal zu einem schieben optimiert und
> ist u.U. Immernoch genau genug.

Die Division durch 256 liefert sogar ein genaueres Ergebnis, da die
nominelle Schrittweite des ADC nicht Uref/(2^n-1), sondern Uref/2^n ist.

von Dr. Sommer (Gast)


Lesenswert?

Yalu X. schrieb:
> da die
> nominelle Schrittweite des ADC nicht Uref/(2^n-1), sondern Uref/2^n ist
Nein, es sind tatsächlich nur 255 Schritte! (zwischen 0 und 1, zwischen 
1 und 2, ... zwischen 254 und 255). Somit ist die Schrittweite 
Uref/(2^n-1). Das liegt daran dass ADC Wert 0 = 0V entspricht, und nicht 
der Spannung der Schrittweite. Dann stimmt auch die Formel bei ADC-Wert 
= max = 2^n-1 :
U=Uref * ADC Wert/2^n-1 => U=Uref

Somit ist 255 richtig...

von H.Joachim S. (crazyhorse)


Lesenswert?

Das alte Streitthema :-)

von lrep (Gast)


Lesenswert?

H.Joachim S. schrieb:
> Das alte Streitthema :-)

Kein Streitthema, der oben dargelegte Sachverhalt:

Dr. Sommer schrieb:
> Somit ist 255 richtig...

ist richtig.

Um das zu illustrieren nehmen wir der Einfachheit halber einen 3-Bit 
Wandler, der bei 7V  7 anzeigen soll, dessen  Stufenhöhe also  1V 
betragen soll:

Spannung/V  Anzeige/Digits
0               0
0,5             umschaltung 0|1
1               1
1,5             umschaltung 1/2
2               2
2,5             umschaltung 2|3
3               3
3,5             umschaltung 3|4
4               4
4,5             umschaltung 4|5
5               5
5,5             umschaltung 5|6
6               6
6,5             umschaltung 6|7
7               7
7,5 und mehr    bleibt bei 7, evtl. overrange Anzeige

Damit das Teil ordnungsgemäß funktioniert, muß die Referenzspannung also 
6,5V bzw. allgemein V_max - 0,5LSB  betragen.

von lrep (Gast)


Lesenswert?

P.S.:
Einen solchen ADC könnte man z.B. aus 7 (!) Komparatoren, ein bischen 
Logik,  und einer Widerstandsleiter aus 6 gleichen Widerständen R, sowie 
einem weiteren mit R/2 nach GND, aufbauen.

von *canoi* (Gast)


Lesenswert?

>Somit ist die Schrittweite
>Uref/(2^n-1)

Bei einem 1 Bit-Wandler also
Uref/(2^1-1) = Uref

FALSCH.

Bei einem 1-Bit Wandler ist die Schrittweite Uref/(2^1), also Uref/2

256 ist also richtig.

von *canoi* (Gast)


Lesenswert?

Das Problem liegt nämlich daran, dass man das Ergebnis immer zur 
nächsten Ganzzahl abrundet. Wenn man es besser runden würde, dann wäre / 
256 richtig, aber zusätzlich mit + Uref/512

Beispiel am 1Bit ADC:

(abgerundet)
0x00 = 0V
0x01 = Uref/2


(richtig, bzw besser gerundet)
0x00 = 1/4* Uref
0x01 = 3/4* Uref/2

von Uwe S. (de0508)


Lesenswert?


von Rolf Magnus (Gast)


Lesenswert?

*canoi* schrieb:
> Das Problem liegt nämlich daran, dass man das Ergebnis immer zur
> nächsten Ganzzahl abrundet.

Genau das ist richtig. Jeder ADC-Wert entspricht nämich nicht einer 
Spannung, sondern einem Spannungsbereich.  Ich erkläre das immer gerne 
an einem 2-Bit-ADC mit 4V Referenz.

Es ergibt sich:
1
ADC-Wert        Spannung
2
    0                  0V    <= U <   1V
3
    1                  1V    <= U <   2V
4
    2                  2V   <= U <    3V
5
    3                  3V   <= U <    4V

Die mathematisch genaueste Lösung wäre also:
1
ADC-Wert       Berechnetes Ergebnis       Maximale Abweichung
2
    0                       0,5V                                     +/- 0,5V
3
    1                       1,5V                                     +/- 0,5V
4
    2                       2,5V                                     +/- 0,5V
5
    3                       3,5V                                     +/- 0,5V
Dazu addiere ich zum ADC-Wert 0,5 dazu, teile es durch 4 (weil vier 
mögliche Werte des ADC) und multipliziere es wieder mit 4 (Weil 4V 
Referenz). Kommt also als Rechnung raus ADC-Wert + 0,5.

Die meisten kommen damit deshalb durcheinander, weil sie nur von 
Einzelwerten und nicht von Bereichen ausgehen und dann erwarten, daß 0 
den 0V entspricht und 3 den 1V. Wenn man so denkt, kommt man natürlich 
auf ADC-Wert / 3 * 4. Damit liegt aber jeder Wert nicht mehr in der 
Mitte seines Bereichs, wodurch die maximale Abweichung sich vergrößert. 
Die Tabelle von oben sähe so aus:
1
ADC-Wert       Berechnetes Ergebnis           Maximale Abweichung
2
    0                       0V                                       +1V        /  -0V
3
    1                       1,333V                                +0,666V /  -0,333V
4
    2                       2,666V                                +0,333V /  -0,666V
5
    3                       4V                                       +0V        /  -1V

von Rolf Magnus (Gast)


Lesenswert?

Rolf Magnus schrieb:
> und 3 den 1V.

Gemeint waren natürlich 4V.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Dr. Sommer schrieb:
> Somit ist 255 richtig...

Schauen wir doch einfach mal ins Datenblatt des ATmega328:
1
24.7 ADC Conversion Result
2
3
After the conversion is complete (ADIF is high), the conversion result
4
can be found in the ADC Result Registers (ADCL, ADCH).
5
6
For single ended conversion, the result is

Damit wäre schon einmal der Umrechnungsfaktor bei Nutzung der vollen 10
Bit des ADC-Ergebnisses geklärt. Hervorzuheben ist, dass da 1024 und
nicht etwas 1023 steht.

Noch unklar ist an dieser Stelle, ob der ADC bei der Quantisierung
abrundet oder zum nächsten ganzzahligen Wert hin rundet. Diese Frage
wird zwei Seiten davor indirekt bei der Definition des Offset-Fehlers
beantwortet:
1
Offset: The deviation of the first transition (0x000 to 0x001) compared
2
to the ideal transition (at 0.5 LSB).

Daraus ist zu schließen, dass der ADC zur nächsten Ganzzahl rundet.
Handelte es sich um einen abrundenden ADC, läge der erste Übergang nicht
bei 0,5 LSB, sondern bei 1 LSB.

Man kann also mit


den ADC Wert in die angelegte Spannung zurückrechnen, wobei der maximale
Quantisierungfehler im Bereich [0V, V_REF - 0,5 LSB] der Fehler ±0,5 LSB
beträgt¹.

Nun nutzt der TE von dem 10-Bit-Ergebnis des ADC nur 8 Bit. Entsprechend
muss in den beiden Formeln 1024 durch 256 ersetzt werden.

Ob auf Softwareseite für die korrekte Rundung noch etwas addiert werden
muss, hängt davon ab, ob es sich bei den genutzten 8 Bit um die
niederwertigen (Bit 0 bis 7) oder die höherwertigen (Bit 2 bis 9)
handelt.

Im ersten Fall sind keine weiteren Maßnahmen zur Rundung erforderlich,
da der ADC die Rundung schon übernimmt. Es muss lediglich V_REF durch 4
dividiert werden.

Im zweiten Fall hat man durch das Abschneiden von Bit 0 und 1 effektiv
eine abrundende Division durch 4 ausgeführt, weswegen zur Korrektur zum
Ergebnis noch 2 LSB hinzuaddiert werden müssen:


Bei den ganzen Überlegungen sollte man natürlich nicht aus den Augen
verlieren, dass es weitere Fehlerquellen (Offset-Fehler, Gain-Fehler und
Nichtlinearitäten) gibt, die schlimmstenfalls größer als die 0,5 LSB
sind, um die hier gefeilscht wird. Trotzdem ist es nicht verkehrt, sich
Gedanken um die richtige Umrechnung zu machen, da diesbezügliche Fehler
den Gesamtfehler noch einmal vergrößern würden.

@Rolf Magnus:

Vorsicht: Was du beschreibst, ist richtig für einen abrundenden ADC,
nicht aber für den AVR-ADC, um den es hier geht.

<edit>
Was die Problematik mit dem Umrechnungsfaktor betrifft, sind deine
Überlegungen aber auch auf den AVR-ADC übertragbar. Vor allem in deinem
letzte Abschnitt samt Tabelle, wo du exemplarisch durch 3 statt durch 4
dividierst, sieht man sehr gut, warum durch 2^n und nicht durch 2^n-1
dividiert werden muss.
</edit>

——————————————
¹) Bei einem abrundenden ADC müsste man softwaremäßig jeweils noch
   0,5 LSB zum Ergebnis addieren, hätte aber den Vorteil, dass der
   Quantisierungfehler innerhalb des gesamten Messbereichs [0, V_REF]
   (also auch im letzten 0,5-LSB-Intervall) auf ±0,5 LSB beschränkt ist,
   was beim AVR-ADC nicht der Fall ist.

: Bearbeitet durch Moderator
von Falk B. (falk)


Lesenswert?


von Dr. Sommer (Gast)


Lesenswert?

Dann hat der AVR ja einen komischen ADC.
Sei eine Schrittweite:

Um die Spannung zu finden, bei der der ADC-Wert zwischen 0 und 1 
umschaltet, setzen wir ADC=0.5 und berechnen:
somit
Nicht überraschend erfolgt der Übergang bei der halben Schritt-Spannung. 
Der nächste Übergang erfolgt bei 1.5 * Vlsb, der nächste bei 2.5 * Vlsb 
usw.

Interessant ist jetzt der letzte Übergang, also zwischen 1022 und 
1023. Dieser erfolgt also bei 1022.5 * Vlsb. Im gesamten Bereich 
1022.5*Vlsb bis Vref=1024*Vlsb ist der ADC-Wert 1023 (das Maximum bei 
10bit). Dieser Bereich ist 1.5 * Vlsb groß. Somit gilt:

* Für ADC = 0 ist der mögliche Eingangsspannungsbereich  0.5 * Vlsb groß 
(Fehler also max 0.5 * Vlsb).
* Für ADC in [1,1022] ist der mögliche Eingangsspannungsbereich jeweils 
1*Vlsb groß, der Fehler ist aber immer noch max 0.5*Vlsb weil der 
Bereich nach oben und unten geht
* Für ADC = 1023 ist der mögliche Eingangsspannungsbereich 1.5 * Vlsb 
groß. Hier ist der Fehler also plötzlich 1.5 * Vlsb.

Das bedeutet also der Quantisierungsfehler ist bei ADC=1023 dreimal so 
groß wie im restlichen Bereich.
Da ja "ADC" maximal bis 1023 geht (da 10bit-Zahl), kann die Formel
 niemals die Eingangsspannung Vref erreichen, und somit kann man nicht 
die volle Referenzspannung messen.

von Norbert (Gast)


Lesenswert?

Eine Sekunde:
  Dateimanager öffnen
Drei Sekunden:
  zum Atmel Dokumentenordner wechseln
Fünf Sekunden:
  im Mega128 Dokument zur Seite 233 wechseln
1
The ADC converts an analog input voltage to a 
2
10-bit digital value through successive approximation.
3
The minimum value represents GND and 
4
the maximum value represents the voltage on the AREF pin minus 1 LSB.

von Ralf G. (ralg)


Lesenswert?

Yalu X. schrieb:
> Bei den ganzen Überlegungen sollte man natürlich nicht aus den Augen
> verlieren, dass es weitere Fehlerquellen (Offset-Fehler, Gain-Fehler und
> Nichtlinearitäten) gibt, die schlimmstenfalls größer als die 0,5 LSB
> sind, um die hier gefeilscht wird.

Und da kann man auch
rechnen...
Dr. Sommer schrieb:
> niemals die Eingangsspannung Vref erreichen, und somit kann man nicht
> die volle Referenzspannung messen.

... und kann jetzt bis 'oben' messen. (Je nach Anwendungsfall, wenn die 
Untergrenze eher zweitrangig ist.)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Malte S. schrieb:
> Nur dass sowohl Fließkomma [...] Unmengen Ballast mitschleppen.
> adc_value * 100 / 255

Und wer verlangt dass es Fließkomma ist?

http://gcc.gnu.org/onlinedocs/gcc/Fixed-Point.html#Fixed-Point

von Yalu X. (yalu) (Moderator)


Angehängte Dateien:

Lesenswert?

Dr. Sommer schrieb:
> Dann hat der AVR ja einen komischen ADC.

Die meisten ADCs sind in dieser Hinsicht "komisch" ;-)

Ich habe im Anhang mal mehrere HW/SW-Alternativen zur A/D-Konvertierung
zusammengestellt. Der Einfachheit halber dient als Beispiel ein
4-Bit-ADC, dessen Referenzspannung 24V beträgt.

Die grüne Linie zeigt an, wie die Eingangsspannung idealerweise (d.h.
ohne Quantisierungfehler) in den ADC-Wert umgesetzt werden sollte. Die
rote Treppenlinie stellt die Quantisierung dar. Die blauen Punkte geben
an, wie üblicherweise die diskreten ADC Werte durch die Software in
entsprechende Spannungswerte zurückgerechnet werden.


Zur nächsten Ganzzahl rundend
=============================

So machen es die meisten ADCs (einschließlich der im AVR verbaute). Der
Eingangsspannungsbereich wird dabei in 2^n Intervalle unterteilt, wobei
alle Intervalle bis auf das erste und das letzte die Breite Uref/2^n
haben. Das erste Intervall ist nur halb so breit, dafür ist das letzte
um 50% breiter.

Vorteile:

- Die Rückrechnung in den Spannungswert erfolgt durch eine einfache
  Multiplikation mit Uref/2^n.

- Die rückgerechneten Spannungswerte beginnen bei 0V.

Nachteile:

- Der maximale Quantisierungsfehler im letzten Intervall ist nicht, wie
  in allen anderen Intervallen, ±0,5 LSB, sondern kann bis zu +1 LSB
  betragen.

- Die rückgerechneten Spannungswerte reichen nicht bis Uref, sondern nur
  bis Uref - 1 LSB¹.


Abrundend
=========

Der Eingangsspannungsbereich wird in 2^n Intervalle unterteilt,
wobei alle Intervalle die gleiche Breite Uref/2^n haben.


Vorteile:

- Der maximale Quantisierungsfehler ist in jedem Intervall gleich.

- Die rückgerechneten Spannungswerte beginnen bei 0V¹.

Nachteile:

- Der Quantisierungsfehler ist in jedem Intervall maximal -1 LSB, also
  schlechter als die ±0,5 LSB im vorigen Fall.

- Die rückgerechneten Spannungswerte reichen nicht bis Uref, sondern nur
  bis Uref - 1 LSB¹.


Abrundend mit Softwarekorrektur
===============================

Den Quantisierungsfehler des abrundenden ADC kann man softwareseitig
halbieren, indem man zu den gelesenen ADC-Werten jeweils den Wert 0,5
bzw. zu den rückgerechneten Spannungswerten 0,5 LSB (im Beispiel wären
dies 3V) addiert.

Vorteile:

- Der maximale Quantisierungsfehler ist in jedem Intervall ±0,5 LSB,
  was das Optimum darstellt.

Nachteile:

- Es muss eine zusätzlich Softwareaddition ausgeführt werden.

- Die rückgerechneten Spannungswerte reichen nicht von 0V bis Uref, 
sondern nur
  von 0,5 LSB bis  Uref - 0,5 LSB¹.


Vorschlag von Dr. Sommer
========================

Der Eingangsspannungsbereich wird in 2^n Intervalle unterteilt, von
denen alle bis auf das erste und das letzte die Breite Uref/(2^n-1)
haben. Die beiden Randintervalle haben die halbe Breite, also
Uref/(2·(2^n-1)).


Vorteile:

- Der maximale Quantisierungsfehler ist in jedem Intervall betragsmäßig
  gleich.

- Die rückgerechneten Spannungswerte reichen von 0V bis Uref¹.

Nachteile:

- Durch die größeren Intervalle ist der Quantisierungsfehler gegenüber
  den bisher vorgestellten Methoden um den Faktor 2^n/(2^n-1) größer
  (was bei größeren Bitbreiten n aber kaum eine Rolle spielt).

- Die Rückrechnung in Spannungswerte ist mit Integer-Arithmetik nicht so
  leicht zu realisieren, da entweder durch eine Nichtzweierpotenz
  dividiert werden, oder – um dies zu umgehen – evtl. mit größeren
  Bitbreiten gerechnet werden muss.

- ADCs, die nach diesem Prinzip arbeiten, gibt es vermutlich nicht zu
  kaufen.


Zur nächsten Ganzzahl rundend mit Korrektur der Referenzspannung
================================================================

Das von Dr. Sommer gewünschte Verhalten kann mit einem gewöhnlichen ADC
dadurch erreicht werden, dass man die Referenzspannung um den Faktor
2^n/(2^n-1) erhöht, dennoch aber nur denjenigen Eingangsspannungsbereich
nutzt, den man auch ohne diese Erhöhung nutzen würde. Der ungenutzte
Bereich ist im Diagramm gestrichelt gezeichnet.

Vorteile:

- Der maximale Quantisierungsfehler ist in jedem Intervall betragsmäßig
  gleich.

- Die rückgerechneten Spannungswerte reichen von 0V bis zum oberen Ende
  des genutzten Eingangsspannungsbereichs¹.

Nachteile:

- Auch hier entsteht durch die größeren Intervalle größerer
  Quantisierungsfehler.

- Auch hier ist die Rückrechnung in Spannungswerte ist mit Integer-
  Arithmetik nicht so leicht zu realisieren.

- Da Uref meist nicht größer als die Versorgungsspannung des ADC sein
  darf, ist der nutzbare Eingangsspannungsbereich kleiner als die
  Versorgungsspannung.

- Die erhöhte Referenzspannung ist meist ein ziemlich krummer Wert und
  muss erst einmal bereitgestellt werden.

- Man kann nicht – wie bei ratiometrischen Messungen sonst üblich – für
  ADC und angeschlossenem Sensor dieselbe Referenzspannungsquelle
  verwenden.


———————————
¹) Ob dies als Vorteil bzw. Nachteil angesehen wird, ist aber primär
   eine Frage des persönlichen Geschmacks.

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
> Malte S. schrieb:
>> Nur dass sowohl Fließkomma [...] Unmengen Ballast mitschleppen.
>> adc_value * 100 / 255
>
> Und wer verlangt dass es Fließkomma ist?

Das Posting, das direkt vor dem steht, auf das du dich beziehst.
(mal abgesehen davon, daß "float" nicht "fließen" heißt)

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.