www.mikrocontroller.net

Forum: Compiler & IDEs ADC-Umrechnung-dtostre()


Autor: Crash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe einen Sensor und möchte nun die 0-4V Ausgangsspannung per ADC
ans LCD schicken.
Aber ich habe ein leichtes Verständnisproblem, meine ADC funktion sieht
folgendermassen aus (im free running mode):

unsigned int ad_wert;

void adc(void){

outp((1<<ADEN)|(1<<ADSC)|(1<<ADFR)|(1<<ADIE)|(1<<ADPS0)|(1<<ADPS2),ADCSR 
);
outp(0x00,ADMUX);        //ADC0

while (bit_is_clear (ADCSR,ADIF));  //bis ADIF 1
ad_wert=ADCH*256+ADCL;          //Wert der Wandlung
}

Mein Überlegungsproblem ist jetzt folgendes:
1.ad_wert liefert mir den Wert aus dem ADC Register als Ganzzahl, also
integer
2.Für weitere Umrechnung muss ich noch ad_wert mit dem Auflösungsfaktor
multiplizieren, das ist aber ein Float-Wert, bzw. das Ergebnis.
Faktor wäre dann: f= Vref/1024 (bei 10bit) = 0,00488..
Volt=f*ad_wert;

1.Frage: Muss ich jetzt "Volt" als integer oder float definieren,
wenn ich Kommastellen ausgeben möchte?

Jetzt meine Frage:
Als Ergenis erhalte ich dann 2,325V.
Ich habe in der Suche nachgeschaut und dtostr() gefunden, die in
stdlib.h steht:
extern char *dtostre(double __val, char *__s, unsigned char __prec,
             unsigned char __flags);


dtostre(Volt, *Ausgabe, 3, 0);
2.Frage:Habe ich die Parameter jetzt richtig verstanden?
Volt=2,325235
Ausgabe="2,325 *10^0"

In der Hilfe fand ich noch den Artikel
http://www.mikrocontroller.net/forum/read-2-17038.html#17053
da schrieb Joerg, dass man noch nach libm.a linken muss, stimmt das
wirklich? (3.Frage)

Wäre schön wenn mir jemand antworten könnte, vielleicht kann es
irgendwann mal jemand wieder brauchen.

Autor: Crash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1. Kann ich mir jetzt selber beantworten. Typ double wird gebraucht.
3. auch, libm.a muss angegeben werden.

Autor: Crash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
2. kann ich auch beantworten:
Ausgabe am LCD "0.000e+00"

Leider muss ich dazusagen.
Scheinbar ist mein Wert Volt noch Null, also funktioniert der ADC nicht
richtig. (AT90s4433)

Habe jetzt studenlang die Funktion überarbeitet aber ausser "0.000"
will sich nichts tun. Habe jetzt Free running rausgenommen.

void adc(void)
  {
  char *Ausgabe;
  unsigned int ad_wert;
  double Volt;

  outp(0x00,DDRC);
  outp((1<<ADEN)|(1<<ADSC)|(1<<ADPS0)|(1<<ADPS2),ADCSR);
  while (bit_is_clear (ADCSR,ADSC));

  while(1){
  outp(0x00,DDRC);
  outp ((1<<PINC0), ADMUX);
  outp(inp(ADCSR) | BV(ADSC), ADCSR);
  while (bit_is_clear (ADCSR,ADSC));

  ad_wert=ADCL+ADCH*256;
  Volt=ad_wert*0,005;
  //Volt=2,345;
  dtostre(Volt, Ausgabe, 3, 0);

  lcd_goto(5,2);
  lcd_write_string(Ausgabe);
  }
}

Problem ist wahrscheinlich, da ich auf dem Display sehen kann, dass die
Schleife korrekt durchläuft, dass ich keine Werte aus ADCL und ADCH
bekomme. ad_wert muss richtig sein, der Faktor auch (5V ref).

Wie übernehme ich die Werte für ADCL und ADCH richtig?

Danke schon mal

Autor: Crash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht sollte ich noch dazusagen, dass an Vref sowie AVcc 5V
anliegen und AVcc über einen 100nF an GND.
An PC0 liegen 3,8V an.

Autor: Crash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Punkt, Punkt, Komma, Strich, fertig ist das Mondgesicht.

Volt=ad_wert*0,005;

Hier lag der Hase begraben! Jetzt habe ich über 4 Std. an einer bereits
fast funktionierenden Funktion gedoktort und über sehen, dass ich ein
"," statt einen "." gesetzt habe.

Ich habe fertich.

Autor: m@is (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
[IRONIE]
schön das Du Dir helfen konntest ;-)
[\IRONIE]

Gruß m@is

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
p.s.: Das Register ADC gibt's auch als fertiges 16-bit Pseudoregister.
Das spart die Mulitpliziererei mit 256.  Nicht daß es ein großer
Unterschied wäre -- der Compiler sollte das gut erkennen und nichts
wirklich multiplizieren, aber es sieht besser aus, gleich den 16-bit
Wert zu nehmen.

Autor: Crash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für den Tip, aber welches Register ist denn das?

Habe hier jetzt die funktionierende Funktion, die mir den Wert von
ADCL/H als String umwaldet und also direkt in einer UART/LCD - Funktion
(hier:lcd_write_string) übernommen werden kann.
Suchmaschine funktioniert ja auch nur, wenn auch jemand mal seine
Fehler dann ausgebessert reinschreibt.

void adc(void)
  {
  char *Ausgabe;
  int ad_wert;
  double Volt;
  int x=0;
  int y=0;

      /*ADC init: ADEN(able), startet ADC, Teilungsfaktor 32*/

  ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADPS0) | (1<<ADPS2);
      loop_until_bit_is_clear (ADCSRA & (1<<ADSC));

  while(1){
  DDRC = 0x00;   //brauche ich diese Zeilen?
  PORTC = 0x00;  //muss ich den Pullup ausschalten?
                 //ändert Pullup ein etwas?
  outp(0,ADMUX);      //ADC-Eingang: Pin0
  ADCSRA |= (1<<ADSC);  //nochmal starten; überflüssig?
  loop_until_bit_is_clear(ADCSR,ADSC);

  x=  inp(ADCL);      //Werte auslesen
  y=  inp(ADCH);

  ad_wert=x+(y*256);   //welches Pseudoregister hilft?

  Volt=ad_wert*0.004829;   //Faktor: Vref/1023

  dtostre(Volt, Ausgabe, 2,0);  //rechnet Volt als String(Ausgabe)
                                    //2 Stellen nach dem Komma
                                    //Vorsicht: libm.a linken!
  lcd_goto(6,2);
  lcd_write_string(Ausgabe);
  }

}


Im Anhang meine Schaltung.

Ich habe jetzt noch eine Überlegungsfrage:
1. Wenn ich jetzt den Mittelwert aus ein paar ADC-Werten bilden
möchte... Wie geht man da am besten vor?
Ich muss mit "Volt" jetzt noch weiterrechnen, was mir dann Werte von
400 bis 1000 liefert. Ist das mit einer Varibel noch sinnvoll, wenn ich
den Mittelwert aus 100-1000 (also max. 1000*1000)Werten bilden möchte.
Bei 65535 ist doch schluss bei 8bit!?
Benutzt man da sinnvoller Weise Eprom, in die man Werte ablegt und dann
später abfrägt. Gibt es sowas wie eine vordefinierte
Mittelwert-Funktion (ähnlich wie dtostr)?

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ad_wert = ADC;

Autor: samo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Schön dass es läuft, damit es so bleibt sollest du den Zeiger
"Ausgabe" noch auf einen gültigen Speigerbereich setzen. Am
einfachsten verwendest du dazu ein Array.

Autor: Crash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1. Wenn ich jetzt den Mittelwert aus ein paar ADC-Werten bilden
möchte... Wie geht man da am besten vor?

Antwort von mir selbst: Mittelwertbilung ist scheisse, wenn man viele
Werte mit wenig Abweichung bekommt und einige die aus der Reihe
tanzen.

[IRONIE]
schön das ich mir helfen konnte ;-)
[\IRONIE]

Eigentlich wollte ich ja jetzt dann mein Progrämmchen das den ADC
ausliest und ans Display und UART Daten verschiedener Typen schickt, in
die Codesammlung stellen, aber wenn hier nicht kommuniziert wird lass
ich es halt.

Nach Alex, funker, Eule, werde ich mir nochmal einen neuen Namen und
dyn. IP zulegen.

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.