www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ADC Kalibrierung


Autor: Eric S. (eric996)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag,

um bei einem ATmega16 (ADC) die Messgenauigkeit zu verbessern benutze 
ich folgenden Code:

ADC_Wert = ADC_Wert*0.964; funktioniert, bläht den Code aber auf.

ADC_Wert = ADC_Wert*247/256; das funktioniert nicht (denke das liegt am 
int                               Bereich)
ADC_Wert = (ADC_Wert*247)>>8; das funktioniert nicht (kommt nur murks 
raus)

bei float Deklarierung meckert der Kompiler
Da ich im Weiteren verlauf des Programms mit ADC_Wert als integer 
arbeite darf nicht nach String wandeln.

Da muss es doch einen eleganteren Weg geben?

Danke.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Eric S. (eric996)

>ADC_Wert = ADC_Wert*0.964; funktioniert, bläht den Code aber auf.

Logisch, das ist ja auch ne Float-Multiplikation. Besser geht es mit 
Festkommaarithmetik.

MfG
Falk

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Falk
Genau das möchte er ja.

@Eric
Versuchs mal so:
ADC_Wert = (unsigned long) ADC_Wert*247/256;

Oder auch so:
ADC_Wert = ADC_Wert*247UL/256;

Beides sollte gleichwertig sein.

Autor: Eric S. (eric996)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da habe ich schon mal gelesen, wenn ich das richtig sehe wird aus dem 
Integer ein String gemacht, brauche jedoch einen Zahlenwert.

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
unsigned long ist kein string...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eric S. schrieb:
> Da habe ich schon mal gelesen, wenn ich das richtig sehe wird aus dem
> Integer ein String gemacht, brauche jedoch einen Zahlenwert.

Nein. Da wird kein String daraus gemacht.
Welchen Datentyp hat den ADC_Wert?
Ich vermute mal, das das bei dir ein int ist.

So jetzt nimm einfach mal an, dass ADC_Wert gleich 1024 sei.
1024 * 247 macht 252928

Autsch. Die maximale Zahl, die mit einem int darstellbar ist ist nur 
32767. Das Ergebnis der Multiplikation mit 247 ist also für einen int 
vieeeel zu gross.

Behoben wird das, indem man den Compiler zwingt die Multiplikation im 
Zahlenraum long oder unsigned long zu machen. Dann geht sich das aus.

Autor: Eric S. (eric996)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke !

das hat funktioniert:


ADC_Wert = (unsigned long) ADC_Wert*247/256;

Autor: Jorge (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Verwendung von Kettenbrüchen ermöglicht manchmal eine Verbesserung 
der Performance indem mit kleineren Brüchen, in 8-Bit oder 16- Bit 
Darstellung bei höherer Genauigkeit der Näherung gearbeitet wird.

Beispiel mit JavaScript:
http://www.henked.de/javascript/kettenbrueche.htm

Beispielsweise wird die Skalierung für eine Grafik einmal über einen 
Kettenbruch angenähert und dann kann man alle Elemente damit auf dem 
Display anzeigen. Oder wie im vorliegenden Fall wenn es zeitkritisch 
wäre.

Das Produkt im Zähler muss natürlich zuerst berechnet werden und darf 
keinen Überlauf provozieren. Weil der Kettenbruch konvergiert kann man 
die Genauigkeit wählen - hoffentlich.

Dies ist manchmal besser als einfach mit 100 oder 1000 zu multiplizieren 
was dann zu einem Überlauf führen kann.

>>ADC_Wert = (unsigned long) ADC_Wert*247/256;
Das ist finde ich relativ geschickt /256 und >>8 sollte vom Compiler her 
optimierbar sein, es muss aber
ADC_Wert = ((unsigned long) ADC_Wert*247)/256; heissen, weil "/" eine 
höhere Priorität hat und so die Genauigkeit verschenkt/verloren wird.

Autor: Jorge (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
0.964=241/250

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jorge schrieb:
> es muss aber
> ADC_Wert = ((unsigned long) ADC_Wert*247)/256; heissen, weil "/" eine
> höhere Priorität hat und so die Genauigkeit verschenkt/verloren wird.

Das steht hier aber anders:
http://de.wikibooks.org/wiki/C-Programmierung:_Lis...
Diese Operatoren sind afaik gleichwertig und werden daher von links nach 
rechts ausgewertet.

Autor: Jorge (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Diese Operatoren sind afaik gleichwertig und werden daher von links nach
>rechts ausgewertet.

Gut, dass ich es jetzt endlich auch gelernt habe. Sogar in Pascal ist es 
so. Wo ich das nun wieder herhabe ~:)
Danke dafür!

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Jorge (Gast)

>0.964=241/250

Ja und?

247/256 sind aber rechentechnisch besser, weil /256 = 8 Bit recht 
schieben.

Ändert a) an dem Grundproblem der Festkommaarithmetik wenig und b) 
sollte der OP beim nächsten mal besser lesen. Dort steht ziemlich am 
Anfang was von Überlauf vermeiden.

MfG
Falk

Autor: Jorge (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Falk,


>Ändert a) an dem Grundproblem der Festkommaarithmetik wenig und b)
>sollte der OP beim nächsten mal besser lesen. Dort steht ziemlich am
>Anfang was von Überlauf vermeiden.

Du hast natürlich Recht. Gerade beim AVR, der Multiplikation drauf hat. 
Bei einem kleinen PIC oder wie in meinem Fall einem 386SX ohne 
Coprozessor sieht es anders aus. Mein Ding musste Mehrkanaldaten 
anzeigen (ISA).

27/28  bietet eine gute Näherung (0.9643), man kann die Multiplikation 
mit dem Bruch in Assembler auf Additionen und Subtraktionen zurückführen 
und damit einen Überlauf von vorneherein vermeiden:

- Nenner subtrahieren solange bis das Ergebnis kleiner Null und 
mitzählen
- dann solange den Messwert addieren bis grösser Null und mitzählen

Also am Ende ist der Messwert 27mal addiert worden und der Nenner wurde 
so oft es geht abgezogen, der Rest bleibt. Dabei kommt es nie zu einem 
Überlauf.


Ein 386 schafft die Multiplikation und Division nicht in einem Takt 
sodass das Vorgehen eine mehr als doppelte Geschwindigkeit für die 
Darstellung der Fieberkurven brachte. Der Flaschenhals war dann das 
Löschen des Bildschirms (300ms) was über eine Änderung der Farbpalette 
einer der 16 VGA-Farben entschärft wurde. Das Löschen des gesamten 
Schirms wurde dann in 1/16 Abschnitten "hidden" erledigt.

Es hängt natürlich von der konkreten Anwendung ab, rechts Schieben ist 
wirklich sehr effektiv vor allem mit einem Barrel Shifter.

Gruss

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.