Hallo liebe Gemeinde, mit einem ATMega16 möchte ich Ziffern einer uint32_t Variable auf einer 6 Stelligen 7Segmentanzeige ausgeben. Die entsprechenden Ziffern picke ich mir mit einer geschriebenen Modulo-Funktion heraus. Folgendes Problem beschäftigt mich derzeit: Ich berechne eine momentane Verbrauchsleistung mit Divison und Multiplikation, sodass mir wie zu erwarten die Nachkommastellen des Ergebnises verloren gehen. Ich benötige jedoch 3 der Nachkommastellen für weitere Funktionen in der selben Variable. Nun würde ich gerne meine unsigned long Variable so gestalten, dass die ersten drei Bits den Nachkommastellen entsprechen und die weiteren Bits eben der linken Seite der Fließkommazahl entsprechen. Da der Wertebereich von einer double bzw. float Variable meinem Ergebnis nicht genügt, fehlt mir der Ansatz um dieses Problem zu lösen. Ich bin relativ neu in der Materie und habe etwas über Typecast gelesen, welches entsprechende Variablen als bestimmten Variablentyp behandelt. Könnte mir diese Möglichkeit die Nachkommastellen in meine uint32_t Variable einbinden oder bewege ich mich mit dieser Lösungsmögichkeit auf dem Holzweg? Für effektivere bzw. sinnvollere Lösungsansätze / -vorschläge würde ich mich sehr freuen. Danke im Voraus.
Gast
#2949502
Mr. Xton schrieb: > Da der Wertebereich von einer double bzw. float Variable meinem Ergebnis > nicht genügt, fehlt mir der Ansatz um dieses Problem zu lösen. Das mußt du jetzt mal näher erklären. Der Wertebereich von float ist RIESIG und um da rauszukommen, muss man schon einiges anstellen. Was spricht dagegen, deine Zahlen als Milli-Irgendwas in der Integer Variablen abzulegen. Dann hast du die Tausendstel mit drin.
Gast
#2949518
Fixed Point?!? Man benötigt wirklich selten Fließkomma. Aus 10,234 kannst du auch 10234 machen, wo is der Unterschied? Ingo
Gast
#2949527
1. Typecast==Holzweg 2. Auszugebender Wertebereich ist unklar. 6 Stellen wäre 0..999999, es sei denn, das Komma ist verschiebbar. Welchen Wertebereich willst Du ausgeben (z.B. 1mW..1000W) ? 3. Zweiter Absatz ist völlig unklar (3 Nachkommastellen ./. 3 Bits?!?) 4. "Da der Wertebereich von einer double bzw. float Variable meinem Ergebnis nicht genügt," - Glaube ich erstmal nicht, meinst Du was anderes?
Danke euch beiden für die schnelle Antwort. Hier ein Teilcode fürs Verständnis: uint32_t wert = 0; wert = 1 / IMPULSE_PRO_KWH; // Umrechnung der Impulse in kWH wert = wert * 1000; // Umrechnung kWH in WH wert = wert / 3600; // Umrechnung WH in Ws wert = wert / 100; // Umrechnung Ws in Wms wert = wert / Gemessene_Zeit_ms; // Umrechnung mit verstrichener Zeit(ms) wert = wert * 100; // Rückrechnung Wms in Ws Da ich die zeit wegen der Genauigkeit in ms ermittel, bin ich gezwungen kurzzeitig die Leistung in W/ms umzurechnen. Bereits in der 1. Rechnung gehen mir die Nachkommastellen verloren, sodass das Ergibnis an der Stelle Null ist. Würde ich hier mit float rechnen, bringt dieses jedoch den Nachteil mit sich, das mir die Vorkommastellen verloren gehen (wenn auch nich in der 1. Rechnung). Also ist mein Ansatz, das ich die 1. Zeile in eine floatvariable schieben möchte. Sprich: float kwh_impuls = 1 / IMPULSE_PRO_KWH; Jetzt benötige ich aber eine Rechnung aus uint32_t und float: wert = (unsinged long) kwh_impuls * 1000; ... Leider ist die Hardware noch nicht einsatzbereit und ich weiß nicht was die Variable wert dann beinhalten würde, da ich noch nie mit typecast gearbeitet habe. lg
Gast
#2949546
Rechne einfach mit Float. Da gehen keine Vorkommastellen verloren. Und stelle mal eine Gesamtformel auf. Du wirst sehen, das sich einige Probleme durch kürzen ohnehin auflösen.
Mr. Xton schrieb: > Würde ich hier mit float rechnen, bringt dieses jedoch > den Nachteil mit sich, das mir die Vorkommastellen verloren gehen Kannst du diese Aussage bitte etwas erläutern?
Gast
#2949555
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Wenn man das mal zusammenfasst, ergibt das:
1 | |
Jetzt stellen wir alle Divisionen ans Ende:
1 | |
Äquivalent:
1 | |
So, das klappt natürlich nicht, weil da nur ganzzahlige Werte zwischen 0 und 10 rauskommen können. Also hängst Du ein paar Nullen an:
1 | |
Jetzt kann ein Wert zwischen 0 und 10 Millionen rauskommen. Da musst Du nur noch gedanklich bzw. bei der Ausgabe ein Komma an die richtige Stelle reinsetzen und Du bist fertig. Mit float gehts natürlich auch, ist aber auf einem Mikrocontroller viel langsamer und hier unnötig.
Gast
#2949558
Ergänzung: Der Wertebereich ist natürlich kleiner. Der Maximalwert ist 10 Millionen durch (36 IMPULSE_PRO_KWH 1). Wenn das nicht reicht, hängst Du halt noch mehr Nullen an und gehst auf uint64_t.
Danke euch! @Hmm: die Zeilen sind ausführlich aufgeführt um das Verständnis zu veranschaulichen. Werde es mir in einer Formel zu gemüte führen. Zum Thema Vorkommastelle: Der Wertebereich von float kann Daten bergen, die sowohl im negativen, als auch im positiven Bereich sein können. Und im Vergleich zum unsigned long Typ kann dieser im positiven Bereich eine kleinere Zahl ablegen. Da weder die Zeit noch die Leistungsgröße pro Impuls bekannt ist, kann auch keine feste Aussage über die Größe der Momentanleistung getroffen werden. Sie soll im Endeffekt vielseitig einsetzbar sein.
Gast
#2949566
> Werde es mir in einer Formel zu gemüte führen. Mache es jetzt . Nicht später. >Da weder die Zeit noch die Leistungsgröße pro >Impuls bekannt ist, kann auch keine feste Aussage über die Größe der >Momentanleistung getroffen werden. Genau darüber aber musst Du Dir klar werden und Aussagen machen. Erst dann kannst Du Entwurfsentscheidungen treffen.
Vielen Dank xfr. Die Formel (Äquivalent:) habe ich vorliegen und ist schlüssig. xfr schrieb: > wert = 10UL 1000 1000 / (36 IMPULSE_PRO_KWH Gemessene_Zeit_ms); Kannst du mir erklären was das 10UL bedeutet und wie es sich auswirkt? lg
Gast
#2949576
Vor allem reden wir hier über 10 hoch 14 Yottawatt. Hast Du die ganze Galaxie an Deinem Stromzähler? :-)
Hmm schrieb: > Vor allem reden wir hier über 10 hoch 14 Yottawatt. Hast Du die ganze > Galaxie an Deinem Stromzähler? :-) Das ist eben das Problem, ich kann zum jetzigen Zeitpunkt wirklich keine Aussage darüber treffen wieviel MW momentan verbraucht werden ;) Spaß bei Seite, es handelt sich um ein Projekt für einen Abnehmer XY, und ich wollte es eben diesen so recht wie möglich machen, indem ich die Wertebereiche ziemlich groß gestalte. Man befindet sich einfach auf der sicheren Seite. Änderungen kann man im Praxiseinsatz immernoch bei Bedarf vornehmen. Und steht der Code einmal kann er auch bei anderen Abnehmern eingesetzt werden. Vielen Dank nochmal, für eure Bemühungen. lg
Gast
#2949591
Standardmäßig sind Konstanten Integer-Werte, die auf dem AVR nur 16 Bit breit sind. Wenn man jetzt rechnet:
1 | |
Dann passt das Ergebnis nicht in einen 16-Bit-Integer und es kommen seltsame Werte bei raus. Also muss man mit 32 Bit rechnen. Das UL steht für unsigned long:
1 | |
Ebenso geht:
1 | |
Damit stimmt dann der Wert wie erwartet. Für 64 Bit muss man ULL bzw. uint64_t nehmen. Außerdem sollte man möglichst zuerst alle Konstanten zuerst miteinander verrrechnen, dann macht der Compiler das schon beim Optimieren. Im Maschinencode ist dann im Endeffekt nur noch eine 32-Bit-Division:
1 | |
Oder für noch größeren Wertebereich, aber immer noch 32-Bit-Division:
1 | |
Gast
#2949596
OK. Megawatt. Das wären dann 10 Hoch 32 Megawattsekunden. Der ganze Weltenergiebedarf betrug 2010 etwa 140.168 Mrd.kWh. Also so über den Daumen das 1/10^24 stel des Zahlenbereichs von (üblichen) Floats. Dein Kunde muss seeeeeeeeeeeeeeeeeeeeeeeeeeeehr gross sein. Ich möchte nochmal betonen wie wichtig es ist, sich vor einer Implementierung über die Grössenordnungen klar zu werden. An sich gehört sowas in das Lastenheft. Es dem Kunden so recht wie möglich zu machen ist ohnehin vergebliche Liebesmüh, da endlos.
xfr schrieb: > Standardmäßig sind Konstanten Integer-Werte, die auf dem AVR nur 16 Bit > breit sind. Wenn man jetzt rechnet: >
1 | |
> Dann passt das Ergebnis nicht in einen 16-Bit-Integer und es kommen > seltsame Werte bei raus. > > Also muss man mit 32 Bit rechnen. Das UL steht für unsigned long: >
1 | |
> Ebenso geht: >
1 | |
> > Damit stimmt dann der Wert wie erwartet. Für 64 Bit muss man ULL bzw. > uint64_t nehmen. Super, vielen Dank für die ausführliche Erklärung!
Hmm schrieb: > OK. Megawatt. Das wären dann 10 Hoch 32 Megawattsekunden. Der ganze > Weltenergiebedarf betrug 2010 etwa 140.168 Mrd.kWh. Also so über den > Daumen das 1/10^24 stel des Zahlenbereichs von (üblichen) Floats. > > Dein Kunde muss seeeeeeeeeeeeeeeeeeeeeeeeeeeehr gross sein. > > Ich möchte nochmal betonen wie wichtig es ist, sich vor einer > Implementierung über die Grössenordnungen klar zu werden. An sich gehört > sowas in das Lastenheft. Es dem Kunden so recht wie möglich zu machen > ist ohnehin vergebliche Liebesmüh, da endlos. Du hast natürlich vollkomen Recht mit dem was du schreibst. Ich muss mich entschuldigen, da ich einige andere Funktionen des weiteren Programmcodes vorenthalten habe, wie zbsp. die Ermittlung der verbrauchten Leistung, die nach Jahren einen XY Betrag haben kann. Mein Programm soll für "jedermann" verwendbar sein, wodurch dieses letztlich von der Anzahl der Digits als auch der Impulse pro kwh abhängt. So sind bspw. die genannte Modulofunktion so geschrieben worden, dass eine Zahl (uint32_t) übergeben wird und somit für Verbrauchte- und Momentanleistung fungiert. Neben der genannten Funktion gibt es noch viele weitere, die ebenso zur Verfügung stehen. Im Gesamt handelt es sich um ein hobbymäßiges Projekt um meinen Lernerfolg im Umgang mit µCern und der Programmiersprache zu fördern.
Gast
#2949739
Mr. Xton schrieb: > Ich muss mich entschuldigen, da ich einige andere Funktionen des > weiteren Programmcodes vorenthalten habe, wie zbsp. die Ermittlung der > verbrauchten Leistung, die nach Jahren einen XY Betrag haben kann. Die Leistung ist durch den Anschlußwert des Gebäudes nach oben begrenzt und von der Zeit unabhängig. Falls du die Energie meinst, wird dir hauptsächlich die Auflösung Sorgen machen, da sich über die Zeit einerseits ein hoher Wert aufsummieren kann und andererseits bei bei jedem Impuls nur ein geringer Betrag dazukommt. Float-Zahlen sind da eher kontraproduktiv, weil die Auflösung vom bereits aufsummierten Wert abhängt und außerdem noch Bits für den Exponenten verloren gehen.
Gast
#2949758
Mr. Xton schrieb: > Mein Programm soll für "jedermann" verwendbar sein, wodurch dieses > letztlich von der Anzahl der Digits als auch der Impulse pro kwh abhängt. Trotzdem muss dich der Wert IMPULSE_PRO_KWH nur wenig kümmern. Zur Messung der Gesamtenergie reicht es, die Impulse zu zählen und später für die Anzeige in absolute Einheiten umzurechnen. Dann gibt es keine Probleme mit der Auflösung und du hast einen Ganzzahl-Zähler, der optimal an den Impulsgeber angepaßt ist und trotzdem nichts verschenkt.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.