Forum: Compiler & IDEs Verständnisfrage zur Zahlendarstellung


von Anfänger (Gast)


Lesenswert?

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?

von johnny.m (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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....
}

von karlheinz (Gast)


Lesenswert?

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

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

> 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

von Anfänger (Gast)


Lesenswert?

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?

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

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

von Susi (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

@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

von Susi (Gast)


Lesenswert?

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

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

> 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.

von johnny.m (Gast)


Lesenswert?

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

von Susi (Gast)


Lesenswert?

Also in den Datnblatt steht das nicht direkt drin! Ich dachte halt, der
kann auch größere Spannungen als Vref messen...

von Susi (Gast)


Lesenswert?

Also in dem Datenblatt steht das nicht direkt drin! Ich dachte halt, der
kann auch größere Spannungen als Vref messen...

von Susi (Gast)


Lesenswert?

Ups...3 mal posten wollte ich nicht...scheiß Browser!

von Tobi B. (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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

von Susi (Gast)


Lesenswert?

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.

von Susi (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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

von peter dannegger (Gast)


Lesenswert?

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

von Susi (Gast)


Lesenswert?

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.

von Susi (Gast)


Lesenswert?

Seit ihr gerade alle beim Mittagessen? :) oder hat keiner eine Idee
warum es bei 3,3 V nicht mehr geht?

von johnny.m (Gast)


Lesenswert?

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

von Susi (Gast)


Lesenswert?

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 :(.

von Susi (Gast)


Lesenswert?

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!!!

von johnny.m (Gast)


Lesenswert?

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

von Susi (Gast)


Lesenswert?

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 ...

von johnny.m (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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.

von Wolfram (Gast)


Lesenswert?

Nur zur Sicherheit

VCC
 |
|R|
 |
  -> ADC PIN
 |
|R|
 |
GND

Das ist dein Spannungsteiler ,nicht das du als unteren Widerstand den
Innenwiderstand des ADC annimmst.

von Susi (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

Jau, danke für die grafische Unterstützung:-)

von Susi (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

@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
Noch kein Account? Hier anmelden.