Hallo,
ich bin hier auf ein kleines Problem gestoße:
Wenn ich mit dem ADC des AT90 ein symmetriesches Meßsignal
(+/-10V) erfasse, muß ich aus dem Signal erst mal z.B. 0...2,56V
(Interne Referenz) machen. Soweit, so gut. Bei der Berechnung
des wirklichen MEsswertes für die Ausgabe auf einem LCD ergibt sich nun
die Notwendigkeit, den Nullpunkt nach oben zu verschieben.
Das Problem dabei ist, daß man mit Integer-Arithmetik die negativen
Vorkommastellen nur schwer berechnen kann, da der AT90 imm abrundet.
(d.h., aus z.B. -0,7 wird dann -1).
Wenn ich negative Werte nun um 1 positiver mache, dann funktionert
das. Aber nur für nicht-ganzzahlige Ergebnisse (z.B. -1 + 1 = 0 =>
Messwert 0,... obwohl er ja 1,0 sein sollte).
Im Moment denke ich daran, das Problem durch Unterscheidung dreier Fälle
zu lösen:
* Positive Ergebnisse => Messwert = Ausgangswert_ADC -10
* Negativ-gebrochene Ergebnisse: => Messwert = 10 - (Ausgangswert_ADC +
1)
* Negativ-ganzzahlige Ergebnisse: => Messwert = 10 - Ausgangswert_ADC
Allerdings frage ich mich (und jetzt natürlich euch hier), ob man das
nicht eleganter lösen kann.
TIA,
Harald
Ich denke nicht, dass der AT90 von sich aus rundet...
Vorschlag:
1. Messwert * 500
2. Ergebnis 8 Bit nach rechts schieben -> 0...1999
3. Minus 1000
4. In String wandeln und das Komma "von Hand" reinsetzen
Gruß Jörg
@ Harald (Gast)
>Wenn ich mit dem ADC des AT90 ein symmetriesches Meßsignal>(+/-10V) erfasse, muß ich aus dem Signal erst mal z.B. 0...2,56V>(Interne Referenz) machen. Soweit, so gut. Bei der Berechnung
Die ist aber nicht sonderlich genau.
>Das Problem dabei ist, daß man mit Integer-Arithmetik die negativen>Vorkommastellen nur schwer berechnen kann, da der AT90 imm abrundet.>(d.h., aus z.B. -0,7 wird dann -1).
Nöö.
Festkommaarithmetik
MfG
Falk
Hallo Jörg,
>Ich denke nicht, dass der AT90 von sich aus rundet...
doch, doch, der rundet ab. Wie gesagt, aus z.B. -0,7 macht er
mir eine -1.
>1. Messwert * 500>2. Ergebnis 8 Bit nach rechts schieben -> 0...1999>3. Minus 1000>4. In String wandeln und das Komma "von Hand" reinsetzen
da kann ich dir grade nicht so ganz folgen:
Ich mach mal ein Beispiel, ganz von vorne:
Eingangsspannung: -7V
Spannung nach dem Eingangsteiler des ADC: 0,384V (= 2,56/20 (Ue + 10))
-> Messwert bezogen auf -10V: 3V
1. Messwert * 500 = 1500
Umrechnung Dezimal -> Binär: 0d1500 = 0b101 1101 1100
2. 8 Bits nach rechts: Die 3 MSB bleiben übrig -> 0b101 = 0d5
3. Minus 1000: 5 - 1000 = -1995...
...wo machich den Denkfehler?
Gruß,
Harald
@ Harald (Gast)
>>Ich denke nicht, dass der AT90 von sich aus rundet...>doch, doch, der rundet ab. Wie gesagt, aus z.B. -0,7 macht er>mir eine -1.
Das liegt am Programmierer, nicht am AVR. Der kennt nämlich gar keine
Kommazahlen, nur ganze Zahlen.
>Eingangsspannung: -7V>Spannung nach dem Eingangsteiler des ADC: 0,384V (= 2,56/20 (Ue + 10))>-> Messwert bezogen auf -10V: 3V
???
Bei 0,384V am ADC-Eingng ergibt das einen ADC-Wert von 154 (bei 10Bit
Auflösung und 2,56V Referenzspannung).
>1. Messwert * 500 = 1500
??? Du musst in ADC-Werten rechnen, nicht Volt!
>Umrechnung Dezimal -> Binär: 0d1500 = 0b101 1101 1100
Das kannst du weglassen, irritiert nur. Rechne rein mit Dezimalzahlen.
>...wo machich den Denkfehler?
Lies mal das Tutorial und denk drüber nach.
Mfg
Falk
Dein Denkfehler (und das was Falk und Joerg versuchen, Dir
nahezubringen) ist, dass Du versuchst, das ganze von Anfang an in Volt
zu rechnen. Das ist aber der falsche Ansatz, weil dadurch die Auflösung
vor die Hunde geht. Rechne solange es geht in ganzen Zahlen und mach
erst für die Ausgabe einen Volt-Wert daraus. Dann aber nicht einfach
durch eine Division, sondern mach die Ausgabe z.B. in 100stel Volt oder
in mV und füge an der richtigen Stelle ein Komma ein.
Hallo Falk,
>Du musst in ADC-Werten rechnen, nicht Volt!
da meinten dann Jörg und ich wohl was verschiedenes mit Messwert.
So ergibt es wieder einen Sinn.
>>[AVR rundet...]>Das liegt am Programmierer, nicht am AVR. Der kennt nämlich gar keine>Kommazahlen, nur ganze Zahlen.
Ok, daß der AVR nur ganze Zahlen kennt, ist klar. Was mir nicht so klar
ist, ist inwiefern ich die Rundung in die falsche Richtung denn nun beim
Programmieren vermeiden kann?
Beispiel:
<code>
int zahl;
zahl = 1,2-2;
</code>
Theoretisch wäre der Gleitkommawert von zahl jetzt -0,8.
Lasse ich mir Zahl nun ausgeben, dann bekomme ich -1.
Wie vermeidet man das?
Gruß,
Harald
Harald wrote:
> Beispiel:>> <code>> int zahl;> zahl = 1,2-2;> </code>>> Theoretisch wäre der Gleitkommawert von zahl jetzt -0,8.
Nein. Ignoriere ich mal den Tippfehler (in C werden Gleitkommazahlen
immer mit einem . gebildet und nicht mit einem ,)
dann ist das erwartete Ergebnis in zahl auf jeden Fall mal 0
Das liegt zu einem nicht unbeträchtlichen Teil daran, dass
zahl als int definiert wurde und in C wird nicht gerundet
wird, sondern die Kommastellen werden einfach abgeschnitten.
Runden ist was völlig anderes.
Man kann aber die Eigenschaft: Kommastellen werden abgeschnitten
dazu verwenden um eine Rundung zu machen:
1
intRound(doubleValue)
2
{
3
if(Value>0.0)
4
return(int)(Value+0.5);
5
elseif(Value<0.0)
6
return(int)(Value-0.5);
7
return0;
8
}
Dann werden Gleitkommazahlen zur nächsten ganzen Zahl hin
gerundet.
Aber auch da ergibt eine Rundung von -0.8 nun mal -1, weil
-1 die nächstliegende ganze Zahl zu -0.8 ist.
Allerdings ergibt die Rundung von beispielsweise -0.3 dann 0.
Anzumerken wäre noch, dass die bessere Möglichkeit meistens
das Rechnen ohne Gleitkommazahlen ist. Auf einem µC ohne
FPU geht das dann auch schneller.
Harald wrote:
> ...die Rundung in die falsche Richtung...
Das ist keine Rundung! Es wird nur der ganzzahlige Teil ausgegeben und
eben nicht gerundet. Erinnere Dich mal zurück an die Schule. Da ist
normalerweise das erste an Division, was man lernt, die ganzzahlige
Division mit Rest. Und genau das macht eine Integer-Division in diesem
Fall auch. Es ist keine Rundung, sondern ein "Abschneiden" des
Nachkommateils.
> Theoretisch wäre der Gleitkommawert von zahl jetzt -0,8.> Lasse ich mir Zahl nun ausgeben, dann bekomme ich -1.> Wie vermeidet man das?
Indem Du nicht in so kleinen Werten rechnest, sondern mit größeren
Zahlen. Da spielt das kaum ne Rolle. Wie schon gesagt: Mache alle
Rechnungen z.B. in Millivolt anstatt in Volt. Dann hast Du nominell drei
Nachkommastellen, die nicht abgheschnitten werden.
Mach ne Tabelle!
für die 1024 Möglichkeiten ist das ruck zuck erledigt und dein µC
braucht sich nicht mit Gleitkomma Zahlen rumplagen!
Spannung = Tabelle[ADCWert];
Hallo Johannes,
>Dein Denkfehler (und das was Falk und Joerg versuchen, Dir>nahezubringen) ist, dass Du versuchst, das ganze von Anfang an in Volt>zu rechnen.
Das hat sich mittlerweile als Missverständnis entpuppt.
>Das ist aber der falsche Ansatz, weil dadurch die Auflösung>vor die Hunde geht. Rechne solange es geht in ganzen Zahlen und mach>erst für die Ausgabe einen Volt-Wert daraus. Dann aber nicht einfach>durch eine Division, sondern mach die Ausgabe z.B. in 100stel Volt oder>in mV und füge an der richtigen Stelle ein Komma ein.
Ist auch alles klar. Kein Problem.
Vielleicht stelle ich nochmal anders dar, wo es klemmt:
* Meine Eingangsspannung ist -10...+10V.
* Diese Wird für den Eingang des ADC in 0...2,56V umgewandelt.
* Der ADC macht daraus einen Wert zwischen 0...1023.
* Die (asymmetrische) Spannung errechne ich aus diesem Wert wir folgt:
Uasym = (20V * ADC_WERT)/1023
* Problem: Jetzt sitzt der Nullpunkt noch an der falschen Stelle, also:
Usym = Uasym - 10V
Und hier ist jetzt das Problem, daß ich eine um 1 zu kleine
Vorkommastelle bekomme.
Gruß,
Harald
Harald wrote:
> * Die (asymmetrische) Spannung errechne ich aus diesem Wert wir folgt:>> Uasym = (20V * ADC_WERT)/1023>> * Problem: Jetzt sitzt der Nullpunkt noch an der falschen Stelle, also:>> Usym = Uasym - 10V>> Und hier ist jetzt das Problem, daß ich eine um 1 zu kleine> Vorkommastelle bekomme.
Wie gibst du aus?
Hall Karl-Heinz,
>> Theoretisch wäre der Gleitkommawert von zahl jetzt -0,8.>Nein. Ignoriere ich mal den Tippfehler (in C werden Gleitkommazahlen>immer mit einem . gebildet und nicht mit einem ,)>dann ist das erwartete Ergebnis in zahl auf jeden Fall mal 0
und genau das hätte ich auch erwartet, nämlich abgeschnittene
Nachkommastellen. Ich werde jetzt erstmal im Labor nochmal überprüfen,
ob ich beim Experimentieren keinen Fehler gemacht oder irgendwas
fehlinterpretiert habe.
Gruß,
Harald
@ Jonny M. (Gast)
>Mach ne Tabelle!>für die 1024 Möglichkeiten ist das ruck zuck erledigt und dein µC>braucht sich nicht mit Gleitkomma Zahlen rumplagen!>Spannung = Tabelle[ADCWert];
Klar, die Tabelle ist ja auch sooo klein. Und vor allem muss ja auch der
Messwert tausend mal pro Sekunde aktualisiert werden.
Ich empfehle Brain 2.0.
@ Harald (Gast)
>und genau das hätte ich auch erwartet, nämlich abgeschnittene>Nachkommastellen. Ich werde jetzt erstmal im Labor nochmal überprüfen,>ob ich beim Experimentieren keinen Fehler gemacht oder irgendwas>fehlinterpretiert habe.
Erstmal solltest du uns verraten, in welcher Programmiersprache du
arbeitest. Aber egal ob C oder Assembler, Gleitkommazahlen sind
Overkill. Hast du mal das Tutorial gelesen?
MFG
Falk
Hallo Falk,
>Erstmal solltest du uns verraten, in welcher Programmiersprache du>arbeitest.
C mit WinAVR.
>Aber egal ob C oder Assembler, Gleitkommazahlen sind>Overkill. Hast du mal das Tutorial gelesen?
Ich verwende ja auch keine Gleitkommazahlen. Wie kommst du da drauf?
Tutorial hab ich schon gelesen, les´ ich gerade nochmal.
Gruß,
Harald
Harald wrote:
>>Aber egal ob C oder Assembler, Gleitkommazahlen sind>>Overkill. Hast du mal das Tutorial gelesen?>> Ich verwende ja auch keine Gleitkommazahlen. Wie kommst du da drauf?
Häää.
Wovon reden wir dann dauernd. Wieso ist dann jedes dritte
Wort von dir 'Vorkomma' und 'Nachkomma' und 'runden'
Ich denke es wird Zeit, dass du mal ein bischen Code zeigst,
bevor das Rätselraten, was du denn nun wirklich machst
in Gehirnjogging ausartet.
Mit schwant was:
Könnte es sein, dass du der Meinung bist, dass das hier
Uasym = (20V * ADC_WERT)/1023
mit Gleitkomma (also mittels Kommazahlen) ausgerechnet wird?
Mal ne andere Frage:
> symmetriesches Meßsignal>(+/-10V) erfasse, muß ich aus dem Signal erst mal z.B. 0...2,56V>(Interne Referenz) machen. Soweit, so gut.
WIe machst du das??
Hallo Karl-Heinz,
>Häää.>Wovon reden wir dann dauernd. Wieso ist dann jedes dritte>Wort von dir 'Vorkomma' und 'Nachkomma' und 'runden'
also, ich möchte auf einem LCD vier Vorkomma- und drei Nachkommastellen
angezeigt bekommen. Dazu werden separat die Vor- und die Nackommastellen
als Integers berechnet und dann für die Ausgabe zusammengesetzt.
Im Moment geht es nur um die Vorkommastellen.
>Ich denke es wird Zeit, dass du mal ein bischen Code zeigst,>bevor das Rätselraten, was du denn nun wirklich machst>in Gehirnjogging ausartet.
lcd_write(LCD_3,&analog_value_3);//Ausgabe auf LCD
Gerade eben habe ich mir das im Labor nochmal angeschaut.
Wenn man für ad_value mal 200 wals Wert einsetzt, dann ergibt sich:
value = (20*200)/1023 - 10 = 4000/1023 - 10 = 3-10 = -7.
Soweit korrekt. Problem: Ich möchte mir ja die richtigen
Vorkommastellen für eine Ausgabe als (aus Integers zusammengesetzten)
Dezimalbruch berechnen. Und die Bruchzahl müsste dann -6,09 lauten.
Also brauche ich ein Verfahren, daß mir -6 anstatt -7 liefert.
Eine Lösung für dieses Problem habe ich im Usprungsposting beschrieben.
Sie gefällt mir aber nicht, und vielleicht geht es besser.
>Mit schwant was:>Könnte es sein, dass du der Meinung bist, dass das hier> Uasym = (20V * ADC_WERT)/1023>mit Gleitkomma (also mittels Kommazahlen) ausgerechnet wird
Nein, der Meinung bin ich nicht.
Gruß,
Harald
Hallo Matthias,
>> symmetriesches Meßsignal>>(+/-10V) erfasse, muß ich aus dem Signal erst mal z.B. 0...2,56V>>(Interne Referenz) machen. Soweit, so gut.>Wie machst du das??
Schaltung ist beigefügt.
Achtung: Anstatt der eingezeichneten Dioden gehört da nur
eine normals_Siliziumdiode hin! Schottky & Zener belasten den Teiler
zu stark.
Gruß,
Harald
>lcd_write(LCD_3,&analog_value_3);//Ausgabe auf LCD
11
>
>
OK.
Jetzt hab ich dich. Wenn du das gleich am Anfang gepostet hättest,
hätten wir uns viel erspart.
Das einfachste ist, du rechnest alles in Hunderstel-Volt oder
in Millivolt (wenn du 3 Nachkommastellen haben willst)
(Aber Achtung: Zur Vermeidung von Overflows, ist es gut di3
ganze Berechnung in long durchzuführen. Ich hab jetzt nicht
untersucht, ob sich int bei einem ad_value von 1023 noch
ausgeht).
ad_value = ReadChannel(3); //ADC auslesen
value = (2000L * ad_value) / 1023 - 1000;
Jetzt lautet das Ergebnis nicht mehr -7 oder -6, sondern
-609. Bei der Ausgabe brauchst du nur noch das Komma an
der richtigen Stelle einfügen.
sprintf (&analog_value_3, "%d.%02d", value / 100, value % 100);
//Ausgabeformatierung
Wenn du deinem µC was gutes tun willst, dann nimmst du nicht
einen Faktor von 100, sondern einen Faktor von 256. Dann
dividiert sich das beim sprintf leichter :-)
Du meinst
value = (20*ad_value - 10230)/1023;
aber ansonsten: Auch ein guter Einwand: Divisionen soweit
als möglich nach rechts schieben. Ändert aber erst mal
nichts an seinem Problem.
ich glaube du musst da die fälle unterscheiden, weil ja kommazahlen
unter 0 kleiner sind und kommazahlen größer 0 sind größer. doof
ausgedrückt :(
beispiel:
Also -6,1 ist 0,1 kleiner 6
und 6,1 ist 0,1 GRÖSSER 6
Hallo,
>Jetzt hab ich dich. Wenn du das gleich am Anfang gepostet hättest,>hätten wir uns viel erspart.
Sorry. Das Problem ist, daß der Laborrechner hier nur über
Frisbee-Netzwerk
angebunden ist. Code posten ist also immer ein bischen Rennerei. Aber es
scheint sich zu lohnen :-).
> ad_value = ReadChannel(3); //ADC auslesen> value = (2000L * ad_value) / 1023 - 1000;andenkopfschlag
Da hätte ich aber auch drauf kommen können...
...ich brauch Urlaub.
Danke! Hat mir sehr weitergeholfen!
Gruß,
Harald
Harald wrote:
> also, ich möchte auf einem LCD vier Vorkomma- und drei Nachkommastellen> angezeigt bekommen.
Du täuscht Genauigkeit vor, die du nicht hast.
Bei 20V und einem 10 Bit ADC kannst du gerade mal auf
knapp 2 Hunderstel Volt genau messen. Also 2 Nachkommastellen
wobei die Hunderstelstelle auch schon daneben liegen wird.
Selbst wenn du durch Mittelwertbildung von 4096 Messungen
noch 2 Bits herausholst, ist deine Messung gerade mal auf
ca. 5 Tausendstel genau.
Nochmal eine Anmerkung zu der Teilerschaltung:
Man sollte sowas nur dann machen, wenn man weiß, mit
welchen angeschlossenen Ausgangsimpedanzen zu rechnen
ist. Und beliebig Hochohmig kann man das auch nicht
gestalten, weil es irgendwann Störungsanfällig wird.
Gruß,
Harald
Also ich habs jetzt nicht nachgerechnet, aber ich traue der schaltung
nicht wirklich zu dass sie das tut:
>> symmetriesches Meßsignal>>(+/-10V) erfasse, muß ich aus dem Signal erst mal z.B. 0...2,56V>>(Interne Referenz) machen. Soweit, so gut.
Hallo Karl-Heinz,
>Du täuscht Genauigkeit vor, die du nicht hast.
Ich weiß.
>Bei 20V und einem 10 Bit ADC kannst du gerade mal auf>knapp 2 Hunderstel Volt genau messen. Also 2 Nachkommastellen>wobei die Hunderstelstelle auch schon daneben liegen wird.
Das liegt daran, daß ich gerade auch noch ein Formatierungproblem mit
sprintf
und meinen LCDs habe, um das ich mich später noch kümmern werde.
Gruß,
Harald
Matthias L. wrote:
> @ Karl heinz Buchegger:>> Ja das meinte ich, wobei du ne Null zuviel getippt hast, aber:>
Nein.
a / b - c <==> ( a - bc ) / b
> bei 10bit Wandlern ist das doch immer durch 1024!!
Der größte Wert, den der ADC liefern kann lautet aber 1023.
Hallo Matthias,
>Also ich habs jetzt nicht nachgerechnet, aber ich traue der schaltung>nicht wirklich zu dass sie das tut:>>> symmetriesches Meßsignal>>>(+/-10V) erfasse, muß ich aus dem Signal erst mal z.B. 0...2,56V>>>(Interne Referenz) machen. Soweit, so gut.
So? Warum denn nicht?
Gruß,
Harald
(P.S.: Lass das die Schaltung hier im Labor nicht hören, bisher scheint
sie noch nicht zu wissen, daß sie das gar nicht kann... ;-)
Ne, hattest recht. das ist ja zehn mal 1023.
Ja, aber sollten trotzdem 1024 sein. weil 0...1023 sind 1024 Werte. und
ist U_in > (Uref-Ulsb) wird 1023 ausgegeben.
Bei DA Wandlern ists ja auch so: Uout = Uref * N / 1024 und nicht 1023.
@ Karl heinz Buchegger (kbuchegg)
@ Harald
Auf die Gefahr hin mich zu wiederholen.
Festkommaarithmetik
Ist sooo ein schöner Ariklel. Einfach mal ganz in Ruhe das Problem
angehen.
MFG
Falk
@ Harald (Gast):
Ich wills nicht beschwören, muss mal in ruhe die Kal.fkt ausrechnen
(kann ich abends mal tun), aber auf den ersten Blick siehst nicht so
aus, als ob diese das tut:
-10V => 0V
...
0V => 1,28V
...
+10V => 2,56V
>(+/-10V) erfasse, muß ich aus dem Signal erst mal z.B. 0...2,56V
Aber kann mich täuschen. Werd ich später sehen wenn ich gerechnet habe
Hallo Matthias,
das mit dem Teiler wurde hier:
Beitrag "+/-10V mit 0-5V ADC Messen"
bereits diskutiert.
Alles, was man dann noch machen muß, ist die 0...5V am
Teilerpunkt nochmals herunterteilen.
Gruß,
Harald