Hallo Leute, ich spiele im Moment mit dem AD-Wandler meines Atmega32 rum und habe dazu ein paar fragen. Ich möchte gerne eine LED leuchten lassen, wenn die Versorgungsspannung unter eine bestimmte Grenze fällt. Nun zum Problem: Im Datenblatt steht, dass bei einer Single Conversation das Ergebniss in ADC steht. ADC= (Vin *1024)/Vref. D.h. das dort das Ergebnis in Dezimal steht oder? Also z.b. x*1024. Ist dieser Wert dann schon meine diskrete Spannung die ich messen möchte, also Volt oder Millivolt? Dann gibt es ja noch die Möglichkeit, das das Ergebniss in ADCL und ADCH steht. Aber wie bekomme ich es daraus oder wie kann ich damit was anfangen? D.h. wie bekomme ich die Zweierkomplementdarstellung wieder aufgelöst. Ich kann damit leider nicht viel anfangen. Ich würde halt gerne schreiben: if (ADwert<=2500)...tue etwas Die 2500 sollen millivolt sein. Wie kann ich das anstellen? Hat jemand mein Problem verstanden und kann mir helfen?
Das Ergebnis steht in binär drin (oder in hex, wie man's nimmt). Werte von 0h bis 3ffh, also von 0d bis 1023d. Der C-Compiler kann aber implizit umwandeln, also wenn Du z.B. ne Abfrage machst if(ADC < 1000) versteht der das auch. ADC ist lediglich ein anderer Name für die beiden (hintereinander stehenden) 8-Bit-Register ADCL und ADCH, was eine einfachere Abfrage ermöglicht. Der Messwert in ADC errechnet sich je nach der Referenzspannung: 1 LSB entspricht VAREF/1024. Der uC kann mit "dezimal", "Volt" oder "Millivolt" nix anfangen. Sind alles nur Nullen und Einsen, und wenn man die in Vierergrüppchen zusammenfasst kriegt man die (erheblich besser lesbare) Hexadezimal-Darstellung. Am besten mal in einem Programmierhandbuch oder Grundlagenbuch nachlesen. Gruß Johnny
Vielleicht noch zum besseren Verständnis: Vmess = (VAREF/1024) * ADC. Bei VAREF = 5 V ist ein LSB (also VAREF/1024) 4,88 mV. Wenn's genau sein soll, musste in Fließkomma (float) rechnen. Das wäre dann z.B. #define VAREF 5000 //VAREF in mV #define LSB VAREF/1024.0 //Variable deklarieren: float spannung; //...anderes Zeug... spannung = (float) ADC * LSB; //Das wäre jetzt der Wert in mV if(spannung < 2500) { //LED einschalten oder irgendwas anderes machen.... } Immer dran denken: Wenn man in Integer (also ganzzahlig) rechnet, geht u.U. Information verloren. Wenn man die Controller-interne Referenzspannung von 2,56 V benutzt hat man bei 10 Bit ADC-Auflösung genau 2,5 mV pro LSB, kann dann aber auch nur Spannungen bis 2,56 V messen. Bei geringeren Ansprüchen an die Genauigkeit gehts natürlich auch sparsamer, wenn man (bei 5 V VAREF) LSB als 5 mV annimmt. dann kannste alles in int rechnen: #define LSB 5 //Variable deklarieren: unsigned int spannung; //...anderes Zeug... spannung = ADC * LSB; //Das wäre jetzt der ungefaehre Wert in mV if(spannung < 2500) { //LED einschalten oder irgendwas anderes machen.... }
wenn du die iom16.h z.b. von winavr-c anschaust, hast du die unten angegebenen möglichkeiten: #define ADC _SFR_IO16(0x04) ist 16 bit #define ADCW _SFR_IO16(0x04) ist 16 bit #define ADCL _SFR_IO8(0x04) ist 8 bit l #define ADCH _SFR_IO8(0x05) ist 8 bit h
> Wenn's genau sein soll, musste in Fließkomma (float) rechnen
Davon würde ich abraten.
Eingabe ist immer ein Integer. Beim ADC sogar mit nur 10 bit.
Wenn man dann mit float weiterrechnet, bekommt man eine sehr genaue
Darstellung der Rechenungenauigkeiten ;-)
Rechne bis zu dem Punkt, an dem Du eine Ausgabe brauchst, die in einer
gebräuchlichen Einheit gemacht werden muß, mit int16.
Man muß beim Programmieren ein bischen mitdenken und hat an anderer
Stelle viel Speicher, wo wirklich mal float gebraucht wird (was mir
noch nicht passiert ist) oder eine Optimierung viel aufwendiger wäre.
Gruß,
Falk
Danke für die Antworten. Das was ihr geschrieben habt, war mir ja schon klar. Mir ging es vielmehr darum, wie man eine Zweikomponentendarstellung so umwandelt, damit ich damit was anfangen kann. Ich meine das folgendermassen: ADWert += (ADCH<<8) ADWert = ADWert +ADCL Wisst ihr jetzt was ich meine?
> ADWert += (ADCH<<8) > ADWert = ADWert +ADCL Das geht in die Hose, weil ADWert immer nur ADCL sein wird. Wie wäre es damit: ----------------------- uint16_t Messwert; Messwert=ADCL+(ADCH<<8); ----------------------- Oder hast Du Probleme mit dem "If differential channels are used, the result is presented in two?s complement form." aus dem Handbuch? Das trifft nur zu, wenn Du diesen Modus aktiviert hast. Sonst: ADC=(Vin *1024)/Vref. Und damit kann ADC nur 0...1023 annehmen. Gruß, Falk P.S.: Es ist vielleicht einfacher, als Du denkst?
>P.S.: Es ist vielleicht einfacher, als Du denkst?
Das kann sein.
Aber jetzt kommen wir zu meinem Problem: Wieso kann ADC nur 0...1023
annehmen? Wenn z.B. Vin=3Volt und Vref=2,5 Volt dann ist ADC= 1228,8
Genau darin liegt mein Problem :)
Es kann keine Spannung höher als VAREF gewandelt werden. Ein 10-Bit AD-Wandler unterteilt die Referenzspannung in 2^10 - 1 Schritte, das sind 1023! Das Setzen von VAREF ist gleichzeitig ein setzen des höchsten Messwertes. Gruß Johnny
@Susi: Ach ja, und '1228,8' kann eh nicht sein, da ADC nur ganzzahlige Werte annehmen kann... Bei den Einstellungen von oben (VAREF = 2,5 V und VIN = 3 V) wird der max. Wert 1023d (oder 3ffh, wie man's nimmt) ausgegeben, und das gilt für alle Vin > VAREF. OK, bei über 5 V zerlegt's dann irgendwann den ADC... Gruß Johnny
Ja das mit 1229 is klar...wollte dir nur den genauen Wert aufschreiben ;).OK dann habe ich jetzt ein neues Problem...aber schönen Danke johnny :)
> Wieso kann ADC nur 0...1023 annehmen? Weil Atmel den Chip so gebaut hat. > Wenn z.B. Vin=3Volt und Vref=2,5 Volt dann ist ADC= 1228,8 Nö. Ein Thermometer, das bis 150° anzeigen kann, zeigt bei 200° nichts oder Unsinn oder 150° an. Falk P.S.: Die Handbücher zu den AVR beschreiben die Funktion des ADC recht gut.
Wieso Problem? Einfach Deine 3,3V Versorgungsspannung an den VAREF-Pin vom Controller legen, interne VREF abschalten. Dann haste 3,3 V als Maximalwert. Das gibt für ADC (oder ADCW) 930 für die 3V. ich glaub fast, Du hast da irgendwie VREF und VIN verwechselt... VIN ist eigentlich die Spannung, die Du messen willst... Ich hoffe, das hilft Dir weiter:-) Gruß Johnny
Also in den Datnblatt steht das nicht direkt drin! Ich dachte halt, der kann auch größere Spannungen als Vref messen...
Also in dem Datenblatt steht das nicht direkt drin! Ich dachte halt, der kann auch größere Spannungen als Vref messen...
Hallo, also ich denke grundlegende Überlegungen zum Thema ADC sollten VOR einer evtl. Programmierung gemacht werden... Die Referenzspannung ist die Spannung, die maximal gewandelt bzw. erkannt werden kann. So wie ich das sehe ist das hier ein kompletter Denkfehler. Wenn ich es richtig verstanden habe soll hier die Versorgungsspannung des µC selbst überwacht werden und das soll mit eben diesem zu überwachenden µC passieren. Das kann nur dann funktionieren, wenn die "Unterspannung" reicht, um den µC noch fehlerfrei funktionieren zu lassen und die Referenzspannung mindestens so groß ist wie die Fehlerspannung. Wenn jetzt aber Referenzspannung und Versorgungsspanung des µC die aus der gleichen Quelle kommen. Geht das nicht! Wie auch?! Die Referenz muss in diesem Fall also von einer anderen Quelle kommen, oder die Differenz zwischen Referenz und Versorgungsspannung rechnerisch ausgeglichen werden. Der richtige und übliche Weg, wäre der Einsatz eines geeigneten Überwachungsbausteins - auch watchdog genannt :-) VG Tobi
Stimmt natürlich... Hatte nicht so genau hingeschaut und hab irgendwie nicht geschnallt, dass Susi die eigene Versorgungsspannung messen will... Für ne Spannungsüberwachung haben die AVR übrigens ne eingebaute Brown out detection... Vielleicht mal im Handbuch nachlesen, ob sich damit was machen lässt. Gruß Johnny
Doch doch das was ich vorhabe geht schon. Ich habe je eine Spannungsstabilisierung an Vcc und AVcc. D.h. beide werden maximal bis 3,3 Volt versorgt, also kann ich bis 3,3 Volt messen. Wenn meine Verorgungsspannung nun unter die 3,3 Volt sinkt, dann leuchtet halt die LED(Unter 3,3 Volt funktioniert meine Schaltung eh nicht mehr ganz korrekt). Also werde ich anstatt der 2,5 Volt Referenzspannung 3,3 Volt nehmen. Damit müsste dann ja alles so funktionieren wie ich es möchte.
Die welt ist schon komisch...es geht natürlich nicht. Gibt es eine maximale AVref die ich anlegen darf? Mit den 2,5 Volt von vorhin hat es funktioniert. Aber jetzt mit 3,3 Volt geht es nicht. Hat jemand eine Erklärung?
Erklaerung hab ich keine (ohne ins Datenblatt zu schauen) Aber eine andere Moeglichkeit. Anstatt die AVref anzuopassen kannst Du ja auch die Spannung die du messen willst ueber einen Spannungsteiler in den Messbereich bringen.
> Gibt es eine maximale AVref die ich anlegen darf? Ja klar, siehe Datenblatt: Vcc. Höhere Spannungen können den AVR töten. Vielleicht solltest du dich an die Grundlagen der Elektrotechnik und Dinge wie einen Spannungsteiler erinnern?
Nee, das geht doch net. Wenn Du als Versorgungsspannung keine 3,3 V mehr hast, geht auch deine externe Referenzspannung runter, weil Du da ja die Versorgungsspannung benutzt. Du kannst mit dem ADC keine Spannungen messen, die höher als Dein VCC bzw. AVCC sind, bzw. wenn das Ereignis eintritt, das Du eigentlich erfassen willst, ist Deine Referenzspannung nicht mehr korrekt. Du könntest eine kleinere Referenzspannung nehmen (z.B. über eine Shunt-Spannungsreferenz, 1,25 V oder so (z.B. REF1112 von BB/TI)) und deine Versorgungsspannung mit nem Spannungsteiler runterteilen, so dass Du bei den normalen 3,3 V grade so bei 1,25 V liegst und bei 3 V entsprechend drunter. Durch die Shuntreferenz haste auch bei 3 V noch ne stabile Referenzspannung. Die interne Referenz von 2,56 V geht ja bei zu niedriger Versorgungsspannung auch in die Knie. Bei 3 V könnte es vielleicht noch klappen. Ausprobieren... Aber sonst wie gesagt mit ner kleinen, festen externen Referenz und nem Spannungsteiler BTW: AVREF (oder VAREF, wie auch immer) darf maximal der Versorgungsspannung entsprechen. Gruß Johnny
Will man VCC überwachen, geht das invers, d.h. man nimmt VCC als UREF und mißt damit die UBG (1,22V). Aus dem Verhältnis kann man dann VCC ausrechnen. Will man aber nur einen Schwellwert testen, überläßt man das Rechnen dem Präprozessor, der dann den richtigen Vergleichswert einträgt. Peter
Tja diese Überlegungen hatte ich auch(Das mit max Aref usw.). Mich wundert halt nur, das es bei 2,5 Volt ging und jetzt bei 3,3 Votl nicht mehr. Es ist ja exakt der gleiche Sachverhalt. nur das beide Spannungen jetzt bei 3,3 Volt liegen. Vorher: AVcc =3,3 Volt AVref =2,5 Volt bei Vin=2,5 Volt sollte die LED leuchten. Jetzt: AVcc =3,3 Volt AVref =3,3 Volt bei Vin=3,3 Volt soll die LED leuchten. Aber das tut sie nicht.Theoretisch müsste das doch gehen, da es bei 2,5 Volt auch ging(Da passte sich ja Aref auch an und ging unter 2,5 Volt snychron mit der Versorgungsspannung runter).D.h. wenn ADC=1023 ist(das Verhältnis von Vin zu Vref=1) müsste die LED leuchten, genauso wie bei 2,5 Volt. Das mit den Spannungsteiler ist mir auch klar aber das wollte ich halt erstmal vermeiden, da es ja theoretisch auch so gehen müsste.
Seit ihr gerade alle beim Mittagessen? :) oder hat keiner eine Idee warum es bei 3,3 V nicht mehr geht?
Vielleicht mal nicht abfragen ob ADC = 1023 sondern ADC >= 1015 oder so. Vielleicht sind irgendwo noch Spannungsabfälle drin, die dafür sorgen, dass Du den eigentlichen Maximalwert gar net erreichst. Sind ja nur ein paar mV pro LSB, die haste schnell mal irgendwo drin. Aber wenn Du nach wie vor deine eigene Versorgungsspannung abfragst, machts immer noch nicht viel Sinn, da in dem Fall die LED so lange leuchtet wie Deine Betriebsspannung ausreicht, damit der uC stabil läuft. Das was Du vorhast geht so nicht, egal wie Du es drehst. Außer eben vielleicht mit der internen Referenz. Wenn Du nen Low Voltage Controller (z.B. ATMega16L) nimmst, sollte der eigentlich noch bei 2,7 V zuverlässig funktionieren, also auch mit 3 V. Gruß Johnny
Ich glaube ich habe jetzt die Lösung meines Problems gefunden. Bei der 2,5 V Variante liefen beide Spannungen über den selben Spannungswandler, was bedeutet, das es möglich war, das beide Spannungen gleich waren! Nun lasse ich aber die zu messende Spannung (Vin) nicht mehr über den Wandler laufen sonder nehme sie direkt von der Quelle. Die Ref-Spannung, die aber noch über den Wandler läuft kann also nie genauso groß sein wie die Vin, da der Wandler ja noch einen internen Spannungsabfall hat, welcher dafür sorgt, das die Ref-Spannung immer kleiner ist als meine zu messende Spannung. Also bleibt mir doch nix anderes über als den Spannungsteiler zu nehmen, schade :(.
Das ist mir jetzt schon ganz schön peinlich aber ich komme mit dem Spannungsteiler nicht klar. Um den Widerständ(den ich ja dazwischen schalten möchte um die Spannung zu halbieren) zu bestimmen, brauche ich doch den Strom oder den Innenwiderstand des Pins. Wie soll ich das denn machen? Peinliche Grüße Susi PS: Irgendwie habe ich gerade den totalen Blackout!!!
Der Eingangswiderstand von so nem ADC bzw. dem Controllerpin ist sehr groß (Achtung! Portregister korrekt programmieren als tristate-Eingang [DDRx.n = 0; PORTx.n = 0]). Müsste auch irgendwo im Handbuch unter 'electrical characteristics' stehen. Wenn Du den Teiler im Bereich 10...100kOhm dimensionierst, kannste den als unbelastet annehmen. Kommt bei der Anwendung ja auch nicht aufs mV an, oder? Wolltest Du es jetzt mit der internen Referenz versuchen? Viel Erfolg
Nein ich wollte es weiterhin mit der externen probieren. ich dachte mir jetzt, dass wenn ich nun die zu messende Spannung "halbiere" müsste das ja funktionieren. Damit wäre Vin ja immer kleiner als Vref und somit messbar. Das Problem was ich nun habe, ich weiß nicht, wie groß ich den Widerstand wählen soll, damit Vin "halbiert" wird also von 3,6 Volt auf 1,8 ...
Ach ja, falls der Blackout wirklich so extrem ist: z.B. 47k nach VCC und 47k nach Masse. Dann haste die halbe Betriebsspannung am Pin:-)
Ups, da hat sich was überschnitten... Also, zum halbieren von Vin s.o.. Aber wo hast Du jetzt Deine Referenzspannung her? Ich hoffe, es ist mittlerweile klar, dass Du auch wenn Du die zu messende Spannung halbierst bei Benutzung von VCC als VREF immer den gleichen Wert messen wirst:-? Musst also auf jeden Fall ne feste Referenz nehmen, also Shuntreferenz oder so (also von der Versorgungsspannung unabhängig!!!). Probier es bei den Spannungen lieber erst mit der internen Referenz aus, dann brauchste erst mal die Schaltung nicht zu ändern. Ansonsten musste ja auch Dein Teilerverhältnis anpassen. Wenn Du mit ner 1,25V-Ref. arbeiten willst muss Dein Teiler die 3,3 V auf 1,25 oder niedriger teilen, also z.B. 68k oben und 33k unten. Dann haste ca. 1,1 V bei voller Spannung.
Nur zur Sicherheit VCC | |R| | -> ADC PIN | |R| | GND Das ist dein Spannungsteiler ,nicht das du als unteren Widerstand den Innenwiderstand des ADC annimmst.
Meinst du so? pin---------[47k]-----Vcc 3,6 V | | | [47k] | _ Damit sollen am Pin dann 1,8 Volt liegen? Ich glaube ich sollte für heute schluss machen, mein Kopf qualmt und ich kapiere nix mehr. Ich danke dir nochmals für deine Mühe...bis morgen ;)
Ich habe den Wald vor lauter Bäumen nicht gesehen!!! Als ich die "Schaltung" von Wolfram sah, viel es mir wie Schuppen aus den Haaren!!! OMG wie kann ich nur so dumm sein...sorry für die nervige Fragerei. Danke an alle!!! Es hat jetzt wieder klick gemacht ;)
@Susi: Genau. Das wär dann für die halbe Spannung. Den Innenwiderstand von ein paar MegaOhm kannste bei den Werten getrost vergessen. Und am besten in ner ruhigen Minute mal ein bisschen 'Grundlagen E-Technik' verinnerlichen:-) Das sind eigentlich elementare Dinge. Aber das mit dem Blackout kenn ich auch... Gute Erholung Gruß Johnny
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.