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.
1. Kann ich mir jetzt selber beantworten. Typ double wird gebraucht. 3. auch, libm.a muss angegeben werden.
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
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.
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.
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.
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)?
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.