Wenn der ADC Wert nun 0 ist, dann bekomme ich auch 0V. Allso richtig.
Ist dieser aber max, also 1023, dann ist pvval 30.69 Volt
durch #define pv_max_volt 40 müsste das ganze jedoch 40Volt sein..
Irgendwie, gehen da 10 Volt "verloren".
Kann mir wer da helfen?
Tobi S. schrieb:> float pv_volt_per_step = (pv_max_volt * 100 ) / pv_adc_steps;
Bei der Berechnung macht der Compiler die Berechnung als Ganzzahl, und
schneidet alles nach dem Komma ab. Erst dann wird die Zahl bei der
Zuweisung in eine Float gewandelt.
Gib mal pv_volt_per_step aus.
Lösung dürfte sein ein Define als float zu definieren:
#define pv_max_volt 40.0
Udo S. schrieb:> Tobi S. schrieb:>> float pv_volt_per_step = (pv_max_volt * 100 ) / pv_adc_steps;>> Bei der Berechnung macht der Compiler die Berechnung als Ganzzahl, und> schneidet alles nach dem Komma ab. Erst dann wird die Zahl bei der> Zuweisung in eine Float gewandelt.> Gib mal pv_volt_per_step aus.>> Lösung dürfte sein ein Define als float zu definieren:> #define pv_max_volt 40.0
Super perfekt. Genau das war es. Super. vielen vielen Dank.
Wenn man die Berechnung in Integer packt, ist das ganze wesentlich
schneller und kleiner, wenn der Controller nicht gerade eine FPU hat.
Dazu kann man die Skala ja vorausberechnen (40/1023=0,0391) und den Wert
z.B. als 391 speichern, passt in einen uint_16 (geht man über
"scale=40*10000/1023" muss es ein uint_32 sein!).
Dann "ADC*scale", was maximal 1023*391=399993 ergibt (ein uint_32), was
man einfach als "39,9993" mit eingefügtem Komma ausgeben kann.
Wenn das zuviele Nachkommastellen sind, kann man die auch einfach
weglassen, eine Division ist unnötig.
Wenn Du auf float umsteigst, kannst Du die /100 und *100 gleich
weglassen.
Entweder alles mit Integern - oder mit Floats, dann aber richtig.
Ich würde - da 40000/1024=39,0625 - alles int16 in Millivolt rechnen.
Oder (wenn die 40V-full-scale-Auflösung nicht ausreicht) mit int32 in
Mikrovolt: 40000000/1024=39062,5
Außerdem sind beide xxx_adc_steps 1024 und nicht 1023.
Jens M. schrieb:> Wenn man die Berechnung in Integer packt, ist das ganze wesentlich> schneller und kleiner, wenn der Controller nicht gerade eine FPU hat.
und wenn es platzsparender sein soll, gleich alles in centiVolt mit 2
Nachkommerstellen rechen oder in deziVolt mit einer Nachkommastelle.
Milli- oder Micro-volt gibt eh der ADC meist nicht her. (vorgetäusche
Auflösung)
Rechnen tut man mit Konstante als int16 +- oder uint16 und ausgeben
durch Komma einsetzen als Text.
Joachim, im Prinzip hast Du recht, aber um auf einigermaßen genaue
Zenti-Volt zu kommen, muss man den Faktor, mit dem man den ADC-Wert
multipliziert, genauer angeben, als dass 16 Bit beim Produkt ausreichen
(z.B. (1023 * 313) >> 3 = 40024 braucht 19 Bits).
Man kann also, um z.B. auf 40V bei ADC 1023 zu kommen, mit 39
multiplizieren, das trifft es ziemlich genau, aber die umliegenden
Schritte liegen dann 2,5% auseinander:
1023 * 38 = 38874
1023 * 39 = 39897
1023 * 40 = 40920
Man kann das Ergebnis nach der Multiplikation korrigieren, indem man den
ADC nach rechts schiebt, um "Nachkomma-Bits" zu erlangen:
1023 * 39 + (1023 >> 3) = 40024
Dann könnte man gleich ganz ohne Multiplikation schreiben:
wert = adc << 3; // *8
wert += wert << 2; // *32
wert -= adc; // *(-1)
wert += adc >> 3; // *0,125
Was einer Mul mit 39,125 (bei 1023 40024, also 40,02) entspricht. So
hätte man es früher gemacht, der Code ist halt nicht so leicht wartbar.
Aber noch effektiver (kleiner und schneller) kann man es nicht rechnen
(16 shifts und 6 adds mit 8 Bit).
Torsten B. schrieb:> Was einer Mul mit 39,125 (bei 1023 40024, also 40,02) entspricht.
Oh, der ist auch schick. Schnellst und kürzest für dieses
Multiplikation, würd ich sagen. Gefällt mir!
Joachim B. schrieb:> und wenn es platzsparender sein soll, gleich alles in centiVolt mit 2> Nachkommerstellen rechen oder in deziVolt mit einer Nachkommastelle.> Milli- oder Micro-volt gibt eh der ADC meist nicht her.
cV mit zwei Nachkommastellen kannst du besser als 100µV Ganzzahl
rechnen.
Das spart die Float-Rechnerei, deren Dynamik wegen der begrenzten
Auflösung eines ADC gar nicht sinnvoll, allenfalls bei Denkfaulheit
bequem ist ;-)
Schon bei einem 10Bit ADC, bei man ein Ergebnis mit 3 gültigen Stellen
erwartet, reicht die direkte Angabe des LSB in Einheiten von 100µV
allerdings nicht.
Falk B. schrieb:> Das Ganze steht seit Jahren im Artikel Festkommaarithmetik.
man muß nicht immer alles gelesen haben, manches konnte man sich auch
schon vorher selbst erarbeiten.
Jens M. schrieb:> Wenn man die Berechnung in Integer packt, ist das ganze wesentlich> schneller und kleiner,
Nicht automatisch, z.B. auf ATmega328:
uint32_t Division: ca. 615 Cycles
float Division: weniger als 500 Cycles
Johann L. schrieb:> Nicht automatisch, z.B. auf ATmega328:>> uint32_t Division: ca. 615 Cycles> float Division: weniger als 500 Cycles
und was ist mit flash und sram Verbrauch, manchmal ist es nicht die
Geschwindigkeit die bremst, sondern das der SRAM ausgeht oder weniger in
den FLASH paßt.
Joachim B. schrieb:> Johann L. schrieb:>> Nicht automatisch, z.B. auf ATmega328:>>>> uint32_t Division: ca. 615 Cycles>> float Division: weniger als 500 Cycles>> und was ist mit flash und sram Verbrauch, manchmal ist es nicht die> Geschwindigkeit die bremst, sondern das der SRAM ausgeht oder weniger in> den FLASH paßt.
Ja natürlich. Ich wollte nur zeigen, dass "float ist immer und überall
schlechter als int" nicht automatisch zutrifft. Wirklich nachmessen tut
wohl keiner.
Zum Beispiel ist u64 Division in manchen Beispielen schneller als u32
Division für die gleichen Eingaben (mit avr-gcc).
Joachim B. schrieb:> und was ist mit flash und sram Verbrauch, manchmal ist es nicht die> Geschwindigkeit die bremst, sondern das der SRAM ausgeht oder weniger in> den FLASH paßt.
Ja und oftmals hat man SRAM im Überfluß, FLASH im Überfluß, CPU cycles
im Überfluß. Und nutzt FP-Arithmetik weil's im Forum halt so gefordert
wird.
Johann L. schrieb:> Wirklich nachmessen tut wohl keiner.
Doch, ich zum Beispiel schon vor langer Zeit. Darum nutze ich FP auch
nur wenn es mir wirklich etwas bringt.
Norbert schrieb:> Ja und oftmals hat man SRAM im Überfluß, FLASH im Überfluß, CPU cycles> im Überfluß. Und nutzt FP-Arithmetik weil's im Forum halt so gefordert> wird.
und manchmal hat man sich auf dem 328p mühsam sparsame eigene Routinen
geschaffen und ist froh das man diese auch auf einem ESP32 nutzen kann,
wozu als den Überfluß SRAM und FLASH ohne Not nutzen?
Joachim B. schrieb:> und manchmal hat man sich auf dem 328p mühsam sparsame eigene Routinen> geschaffen und ist froh das man diese auch auf einem ESP32 nutzen kann,> wozu als den SRAM und FLASH ohne Not nutzen?
Aha, jetzt also die Strohmann Argumente.
Johann L. schrieb:> Nicht automatisch, z.B. auf ATmega328:>> uint32_t Division: ca. 615 Cycles
Deswegen ist es klug, die Division ganz zu vermeiden. Wenn der Divisor
eine 2er-Potenz ist, machen die meisten Compiler das von sich aus und
verwenden statt dessen eine Shift-Operation.
Rainer W. schrieb:>> uint32_t Division: ca. 615 Cycles>> Deswegen ist es klug, die Division ganz zu vermeiden. Wenn der Divisor> eine 2er-Potenz ist, machen die meisten Compiler das von sich aus und> verwenden statt dessen eine Shift-Operation.
In der Tat. Steht auch alles im Artikel Festkommaarithmetik.
Um noch die Grundlagen für das eigentliche Verständnisproblem
nachzureichen:
Ein 10-Bit ADC unterteilt seinen Messbereich in 1024 gleichgroße
Bereiche.
Der Rückgabewert von "analogRead" ist die "Nummer" des Bereichs, in dem
der Messwert liegt.
Die übliche (im Datenblatt genannte) Umrechnungs-Formel (mit 1024)
berechnet daraus die Spannung für die "untere Kante" vom Bereich. Nicht
den Mittelpunkt vom Bereich und auch nicht die obere Kante.
Tobi S. schrieb:> Wenn der ADC Wert nun 0 ist, dann bekomme ich auch 0V. Allso richtig.
Nein.
ADC-Wert von 0 bedeutet: Spannung liegt zwischen 0V und 0.039V.
ADC-Wert von 1 bedeutet: Spannung liegt zwischen 0.039V und 0.078V
...
ADC-Wert von 1023 bedeutet: Spannung ist größer als 39.96V
Wenn du nun so tust, als hätte dein 10-Bit ADC nur 9.9986 Bits (also:
Als würde der nur 1023 Bereiche unterscheiden können) stimmt die
Rechnung halt nicht mehr mit der Hardware überein, du kriegst aber an
den Grenzen schönere Zahlen angezeigt...
Kann man machen, wenn man sich im klaren ist was man tut.
Jens M. schrieb:> Wenn man die Berechnung in Integer packt, ist das ganze wesentlich> schneller und kleiner, wenn der Controller nicht gerade eine FPU hat.
Nur kann man sich oft genau 0,nix dafür kaufen.
Ich hatte mich auch lange mit Rundungsfehlern und Überläufen abgeplagt.
Dann hatte ich die Nase voll und benutze einfach float.
Selbst bei Software-FP ist das fast nie ein Flaschenhals. Z.B. für die
Anzeige von Meßwerten ist eine Rate von 2..5 Werten/s ergonomisch.
Darüber lacht jede FP-Lib nur.
Dabei teilst du pv_max_volt durch pv_adc_steps, jedoch multiplizierst du
es zuerst mit 100, was zu einem falschen Wert führt. Du solltest einfach
pv_max_volt durch pv_adc_steps teilen, ohne die Multiplikation mit 100:
Gerald K. schrieb:> Durch diese Anpassung wird pvval bei einem ADC-Wert von 1023 korrekt 40> Volt ergeben.
40V ist an der Stelle nicht korrekt. 40V ist der aufgerundete
Wunsch-Anzeigewert.
Der ADC hat garkeine Möglichkeit, 40V zu erkennen, die Hardware gibt nur
eine Erkennung "Größer als 39.96V" her.