ADC-Umrechnung-dtostre()

Gast #75682
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.
Gast #75684
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
Gast #75686
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.
Gast #75688
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.
Gast #75689
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)?
Gast #75692
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

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.