mikrocontroller.net

Forum: Compiler & IDEs Divisions Rest wandeln


Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Isaac Newton (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir mal jemand erklären, wie ihr rechnet?

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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 !

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.


Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erklär mal die Zeile

t = t * 100;

Oliver

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>es ist in jedem Fall Mumpitz.

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

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
t -= 420;              // 84*5
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

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hoppla, erst denken, dann posten! :-(

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

Grüße,
 Christian

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: µ-C (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Benjamin Klimmek (benjaminklimmek)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Genauer als:
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.