Forum: Compiler & IDEs Divisions Rest wandeln


von Bernd (Gast)


Lesenswert?

Hallo,
wer kann mir helfen? Hab folgendes Problem: Ich möchte den Wert des 
A/D-Wandlers in eine Temperatur 12,34 wandeln. Bei einem ADC_WERT von 
0x07FF sollte das Ergebnis 0x22 , 0x4F = 34,79 sein. Heraus bekomme ich 
aber 0x22 , 0xE8 = 34,23. Wo liegt mein Fehler ?


int32_t t;
int8_t x,z = 0;

  t = ADC_WERT [ADC_CANNEL];
  t = t / 5;
  t = t - 84;
  t = t * 100;
  x = t / 934;
  ADC_TEMP [z] = x;
  t = t % 934;
  x = t;
        ADC_TEMP [z + 1] = x;

von Isaac Newton (Gast)


Lesenswert?

>in eine Temperatur 12,34 wandeln

>Wo liegt mein Fehler ?

>sollte das Ergebnis 0x22 , 0x4F = 34,79 sein
                                   ^^^^^
                                    da!

Du wolltest 12,34 als Ergebnis haben, nicht 34,79!

Das folgende Programm läuft einwandfrei:

int32_t t;
int8_t x,z = 0;

  t = ADC_WERT [ADC_CANNEL];
  t = t / 5;
  t = t - 84;
  t = t * (84-7*12);
  x = t + 12;
  ADC_TEMP [z] = x;
  t = t + 22;
  x = t;
        ADC_TEMP [z + 1] = x;

von Peter (Gast)


Lesenswert?

Kann mir mal jemand erklären, wie ihr rechnet?

von Bernd (Gast)


Lesenswert?

Also 12,34 sollte nur ein Beispiel sein, 2 Stellen vor dem Komma und 2 
danach. Der Ganzzahlige Wert der Rechnung stimmt immer nur der Divisions 
Rest nicht. Da mache ich irgendwo einen Fehler. Ich erhalte 0xE8 als 
Divisions Rest und das sind Dezimal 232. Der Fehler legt in der 
Umrechnung, aber wo? Wie rechne ich es richtig um?

von Peter (Gast)


Lesenswert?

>Bei einem ADC_WERT von 0x07FF sollte das Ergebnis 0x22 , 0x4F = 34,79 sein.

Du bist echt etwas -sagen wir mal- beschränkt, wenn du meinst, dass das 
irgendeine sinnvolle Information darstellt zusammen mit deinem 
sogenannten Programm, zu dem du nicht einmal angibst, welche Sprache das 
darstellen soll geschweige denn, auf welchem Supercomputer das Programm 
läuft.

Alles, was ich dir sagen kann, ist, dass du mit einer if-Abfrage für den 
Fall, daß der ADC_WERT 0x07FF beträgt, das Ergebnis auf 0x22 , 0x4F 
setzen kannst (was immer das bedeuten mag). Für jeden weiteren ADC_WERT 
hast du rein gar keine Information gegeben, wie das Ergebnis aussehen 
KÖNNTE, wenn denn richtig gerechnet wird.

Du bist der typische Anfänger, der sich in das hoffentlich bald 
eingerichtete Anfängerforum verziehen sollte, da du nicht in der Lage 
bist, Fragen zu stellen, die ein µC-Experte beantworten könnte.

Peter

von Peter D. (peda)


Lesenswert?

Ich sach mal, den Beitrag hätte sich "Peter (Gast)" sparen können.
Der ist mir schon öfter unangenehm aufgefallen.


@Bernd,

wenn Du 2 Nachkommastellen haben willst, muß der Wert das 100-fache sein 
und dann:

vorkomma = x / 100;
nachkomma = x % 100;

(gilt aber nur für positive Zahlen)


Peter

P.S.:
Bei der Ausgabe der Nachkommastellen nicht die führende Null 
unterdrücken !

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bernd, nette Kopfnuss!

Auf deine Faktoren (5, 84 und 934) und die Rechenoperationen ( - ) 
komme ich nicht.

Aber ich habe ein nettes Tutorial zum Ganzzahlrechnen hier gefunden: 
http://www.avr-asm-tutorial.net/avr_de/rechnen/fpconv.html

Der (Gleitkomma-)Dreisatz Temperatur_1 = Messwert * 34,79 / 0x7FF kann 
so umgeformt werden.

Statt mit 34.79 rechnet man mit dem Hundertfachen und ist dann schon 
teilweise ganzzahlig. Man muss aber später das Komma richtig setzen bzw. 
... bis gleich ;-)

Temperatur_2 = Messwert * 3479 / 2047

Malnehmen mit 3479 wäre noch OK, aber durch 2047 teilen ist eine 
kniffelige Sache, die man verbessern sollte.

Mit 2048 malgenommen ist der Bruch 3479*2048/2047 = 3480,699... und das 
ist aufgerundet 3481. Nicht vergessen durch die 2048 wieder zu teilen.

Temperatur_3 = Messwert * 3481 / 2048

Jetzt kann man statt durch die "krumme" 2047 durch eine Potenz von 2 
teilen. Das kann der µC sehr gut durch Shiften erledigen.

Ein Beispiel:

Messwert     = 2047
Temperatur_1 = 34,79(00)
Temperatur_2 = 3479(,00)
Temperatur_3 = 3479(,30) d.h. +0,0086% Fehler

Und jetzt die Multiplikation * 100 vom Anfang beachten.

Vorkomma  = Temperatur_3 / 100
Nachkomma = Temperatur_3 % 100

von Bernd (Gast)


Lesenswert?

Vielen Dank für euer Kopfzerbrechen,
wir reden aber aneinander vorbei. Daher gehe ich mal davon das meine 
Frage schlecht gestellt war. Ich möchte aus einem ADC_WERT von 84 => 0°C 
bis 1018 => 100°C die Temperatur mit 2 Vorkomma und 2 Nachkomma Stellen 
berechnen.

t = ADC_WERT [ADC_CANNEL];
t = t / 5;    // Ich mache 5 Messungen und addiere sie, daher teile
          ich erst einmal durch 5
t = t - 84;    // ADC_WERT  84 => 0°C,  dann 84 Abziehen (Offset)
t = t * 100;
x = t / 934;    // ADC_WERT  100°C => 1018 – 84 = 934, also durch 934
         teilen
ADC_TEMP [z] = x;  // Vorkommastellen speichern
t = t % 934;    // Hier sollten die Nachkommastellen rauskommen
x = t;
ADC_TEMP [z + 1] = x;

Die Aufteilung in die ganzen Einzelschritte hab ich nur gemacht um 
meinen Fehler besser einkreisen zu können. Das Problem liegt nur an der 
Zeile „ t = t % 934; “ Mit dem Taschenrechner erhalte ich als Nachkomma 
Stellen 0x4F = 79, mein Programm bekommt aber als Ergebnis 0xE8 = 232 
heraus.


von Oliver (Gast)


Lesenswert?

Erklär mal die Zeile

t = t * 100;

Oliver

von Bernd (Gast)


Lesenswert?

Wenn ich diese Zeile weglasse, kommt bei der Division durch 934 ein wert 
kleiner 0 heraus. Ich hab diese Berechnung schon in einem anderen 
Programm, in Assembler verwendet aber ohne Nachkomma und wollte dort 
halt auch nur mit ganzen Zahlen rechnen.

von Peter D. (peda)


Lesenswert?

Bernd wrote:

> Die Aufteilung in die ganzen Einzelschritte hab ich nur gemacht um
> meinen Fehler besser einkreisen zu können. Das Problem liegt nur an der
> Zeile „ t = t % 934; “ Mit dem Taschenrechner erhalte ich als Nachkomma
> Stellen 0x4F = 79, mein Programm bekommt aber als Ergebnis 0xE8 = 232
> heraus.


Warum liest Du nicht einfach mal die Antworten ?

Es ist völlig egal, was bei „ t = t % 934; “ rauskommt, es ist in jedem 
Fall Mumpitz.

Es kommt irgend ne Zahl von 0..933 raus und keine Dezimalstellen.
Und in ein Byte paßt es auch nicht.


Nochmal:

Wenn Du Dezimalstellen willst, mußt Du durch die entsprechende 
Zenerpotenz teilen, also /100 und %100 für 2 Dezimalstellen.


Und bei Integerrechnung gilt immer, erst alle Multiplikation, dann die 
Divisionen (Überlauf beachten !).

Was Du einmal an Stellen wegdividiert hast, kannst Du nicht mehr wieder 
hervorzaubern.


Peter

von Peter (Gast)


Lesenswert?

>es ist in jedem Fall Mumpitz.

DU bist Mumpitz!!!!!!!!!!!!!

von Bernd (Gast)


Lesenswert?

Hallo Peter Dannegger,

hab die Antworten schon gelesen, villeicht nicht alles verstanden.
Hab's jetzt so gemacht:

  t = ADC_WERT [ADC_CANNEL];

  t = t / 5;
  t = t - 84;
  t = t * 10000;
  t = t / 934;
  x = t / 100;
  ADC_TEMP [z] = x;
  x = t % 100;
        ADC_TEMP [z + 1] = x;

und es funktioniert. Sorry noch mal Peter Dannegger hab's nicht so mit 
Komplizierter rechnerei und bin villeicht auch manchmal etwas schwer von 
begriff. Noch mal vielen Dank für die Hilfe und Denkanstösse.

von Christian (Gast)


Lesenswert?

Hallo!

An deiner Stelle würde ich die Mathematik noch etwas vereinfachen:

> t = t / 5;
> t = t - 84;
> t = t * 10000;
> t = t / 934;

in:
1
t -= 420;              // 84*5
2
t = (t * 137) / 64;    // 137/64 = 2.14 = 10000/934/5  (zumindest etwa)

Falls die Genauigkeit nicht reicht z.B. (t*8771)/2^12 rechenen. Dabei 
aber bitte immer unbedingt Überläufe überprüfen!

Viel Erfolg!
Grüße
 Christian

von Christian (Gast)


Lesenswert?

Hoppla, erst denken, dann posten! :-(

Vergesse bitte ganz schnell die Rechnung oben. So geht's besser:
1
t = (t * 137) / 64;
2
t -= 899;   // 84*10000/934

Grüße,
 Christian

von Christian (Gast)


Lesenswert?

Heute ist einfach nicht mein Tag :-(

Beide Lösungen funktionieren, da es ja nur eine lineare Rechnung ist. 
Meine erste Rechnung ist sogar etwas genauer.

von µ-C (Gast)


Lesenswert?

>Beide Lösungen funktionieren, da es ja nur eine lineare Rechnung ist.

Quatsch. Gar nix linear. Er scheint integer-Variablen zu verwenden, und 
(int)(x/const) ist stark nichtlinear.

>Meine erste Rechnung ist sogar etwas genauer.

Genau das ist euer Problem. Berndt gibt zu, daß er dumm wie Brot ist, 
Christian hat nie heute seinen Tag, der eine will keine genaue Rechung, 
der andere kapierts halt nicht.

von Benjamin K. (benjaminklimmek)


Lesenswert?

Hallo Zusammen,

ich habe gerade mal nichts zu diesem Thema zu sagen, aber ich finde es 
erschreckend wie agressiv hier die "Anfänger" angegriffen werden. Wobei 
"Bernd (Gast)" noch nicht einmal ein Anfänger sein muss... ich finde so 
ein Forum ist da um solche Fragen zu klären und nicht um sich 
beschimpfen zu lassen!? Kann man nicht die IP-Adresse desjenigen sperren 
lassen??? Denn, wenn ich das so nachvollziehe heißt "Peter (Gast)" jetzt 
"u-C (Gast)".... aber die IP wird die gleiche sein!! Dieser "Experte" 
scheint sich nicht im klaren zu sein, dass man seine IP nachverfolgen 
und ihn anzeigen kann. Sowas halte ich schon für einen 
Persönlichkeitsangriff.... Vorstrafen zeichnen sich bei keinem 
Arbeitgeber gut aus!!

Ich kann solche Leute auf den Tot nicht leiden!!

Gruß

von Oliver (Gast)


Lesenswert?

Genauer als:
1
uint16_t C = (uint16_t)(((t-420)*1000UL)/467);
wird es nunmal nicht. Das da die Integerrechnung zusätzliche Fehler 
verursacht, ist halt so.

Wobei ich bei einer Eigenbautemperaturmessung die zweite Nachkommastelle 
sowieso als reines Zufallsprodukt ansehen würde, aber das ist ein 
anderes Thema...


Oliver

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.