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


von Crash (Gast)


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.

von Crash (Gast)


Lesenswert?

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

von Crash (Gast)


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

von Crash (Gast)


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.

von Crash (Gast)


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.

von m@is (Gast)


Lesenswert?

[IRONIE]
schön das Du Dir helfen konntest ;-)
[\IRONIE]

Gruß m@is

von Joerg Wunsch (Gast)


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.

von Crash (Gast)


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)?

von Joerg Wunsch (Gast)


Lesenswert?

ad_wert = ADC;

von samo (Gast)


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.

von Crash (Gast)


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.

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.