Hallo,
um den ADC kennenzulernen habe ich mir das GCC durchgelesen.
Ich habe eigentlich nichts spektakuläres vor, möchte lediglich einen ADC
Wert einlesen und 2 LED's dazu leuchten lassen.
Eine LED soll leuchten, wenn die Spannung größer 0,5V (bzw. 500mV)ist,
aber kleiner 1,1V (bzw. 1100mV). Eine zweite LED soll zusätzlich mit
Leuchten, wenn die eingelesene Spannung größer als 1,1V ist (1100mV).
CPU: Atmega8
AVCC ist mir VCC verbunden
AGND ist mit GND verbunden
zwischen AVCC und AGND ist ein 100nF Kondensator
Poti als Spannungsteiler an 5V und GND, Schleifer auf den ADC0
Eingelesen wird am Pin ADC0 mit dem Quellcode aus dem Tutorial.
In meinem Hauptprogramm wandle ich den ADC Wert nur wieder zurück in
eine Spannung in mV und lasse diese durch die LED's ausgeben.
Leider leuchtet, egal wie ich das Poti einstelle, nur die erste LED.
uint8_ti;// Schleifenzähler für die 4-fach Messung (bildet Durchschnitt)
90
uint16_tresult;// Speichert das Ergebnis der Funktion und gibt dieses zurück. Wert zwischen 0...1023 (10-bit)
91
constuint8_tanzahl_messungen=4;// Hier wird die Anzahl der Messungen, aus denen der Mittelwert gebildet werden soll, festgelegt
92
93
ADMUX=mux;// wird der Funktion übergeben, entspricht dem Kanal der ausgelesen werden soll (0=ADC0, 1ADC1, etc.)
94
ADMUX&=(~(1<<REFS1)|(1<<REFS0));// Spannung am Pin AREF dient als Referenz, es muss VCC anliegen (Beschaltung beachten)
95
96
97
ADCSRA=(1<<ADEN)|(1<<ADPS1)|(1<<ADPS2);// Vorteiler wird eingestellt, ADC wird aktiviert
98
99
100
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
101
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
102
103
ADCSRA|=(1<<ADSC);// startet eine ADC-Wandlung
104
while(ADCSRA&(1<<ADSC)){
105
;// auf Abschluss der Konvertierung warten, das bit im ADSC Register wird nach erfolgreicher Wandlung gelöscht, Schleife somit beendet
106
}
107
result=ADCW;// ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen. (Ergebnis wird im Register ADCW gespeichert)
108
109
/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
110
result=0;// Dummy Readout Messwert verwerfen und result zu 0 setzen für neue Messung
111
112
for(i=0;i<anzahl_messungen;i++)// Schleife für 4 aufeinanderfolgende Werte die in result zunächst aufaddiert werden
113
{
114
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion" startet
115
while(ADCSRA&(1<<ADSC)){
116
;// auf Abschluss der Konvertierung warten
117
}
118
result+=ADCW;// Wandlungsergebnisse aufaddieren
119
}
120
ADCSRA&=~(1<<ADEN);// ADC deaktivieren
121
122
result/=anzahl_messungen;// Summe durch anzahl_messungen teilen = arithm. Mittelwert
123
124
returnresult;// Funktion gibt bei Aufruf die Variable "result" zurück. Diese enthält den Mittelwert aus den ADC Messunge
Hallo,
if (ADCWert >= 500 && ADCWert >= 1100){ // wenn der Wert
zwischen 500mV und 1100 mV liegt leuchtet 1 LED
wenn ADCWert grüßer gleich 500 und größer gleich 1100 ist???? ;-)
PS: ein Computer macht nicht immer, was man will.
Er macht aber immer, was man ihm sagt...
Gruß aus Berlin
Michael
HI
Hälst du es wirklich für sinnvoll, bei jeder Messung den ADC neu zu
initialisieren?
> ADMUX &= (~(1<<REFS1) | (1<<REFS0));
Die Zeile ist sinnlos. Dein ADC dürfte mit externer Referenzspannung
laufen. Ist das gewollt.
MfG Spess
Hallo,
danke spess, das mit der externen Referenz war nicht gewollt.
Habe nun 5V auch an AREF angelegt und siehe da, er misst ziemlich genau.
Bei 0,52V geht die erste LED an und bei 1,04V die 2. LED mit (mit
Multimeter gemessen).
Vielen Dank, Problem geklärt :-)
Hi
>Vielen Dank, Problem geklärt :-)
Nein. Setze REFS1:REFS0 auf 01. Damit wird VCC intern an AREF
geschaltet. Und an das AREF-Pin einen 100nf Kondensator nach Masse.
Dann ist das Problem ordentlich geklärt.
MfG Spess
> ADCWert = ADCWert*RefSpannung/1024*1000; // Berechnung der Spannung in
mV
Rechne dir mal zu Fuß für den ADCWert=200 Aus was da rauskommt,
(du solltest 0 rauskriegen)
bix schrieb:
> Vielleicht weil Du in der while() Schleife in main immer nur> einschaltest, aber nie aus?
Wie meinst du das? Der ADC wird doch von der Funktion aufgerufen,
eingeschaltet und dann nach der Konvertierung (bzw. 1 Dummy Readout+4
zur Mittelwert Bildung) abgeschaltet?
Walter schrieb:
> Rechne dir mal zu Fuß für den ADCWert=200 Aus was da rauskommt,> (du solltest 0 rauskriegen)
Wenn ich für ADCWert 200 einsetze, rechen ich:
200*5/1024*1000=976,56mV
Wie meinst du also das, es sollte 0 herauskommen?
Naja, ich habe es so verstanden.
Deine ADCWert Variable wurde als INT deklariert, dh eine Ganzzahl.
Wenn du nun 200*5=1000 rechnest und dann diese 1000/1024=0,97...
Aber in deinem Integer steht dann 0. Und danach rechnest du 0*1000=0.
Also müsste bei 200 für ADCWert 0 rauskommen.
Sven schrieb:
> Wenn ich für ADCWert 200 einsetze, rechen ich:> 200*5/1024*1000=976,56mV>> Wie meinst du also das, es sollte 0 herauskommen?
Jetzt rechnest du noch einmal.
Aber diesmal machst du es genau gleich, wie es auch dein µC macht:
Nach jedem Rechenschritt lässt du die dabei entstehenden
Nachkommastellen unter den Tisch fallen.
Sven schrieb:
> bix schrieb:>> Vielleicht weil Du in der while() Schleife in main immer nur>> einschaltest, aber nie aus?>> Wie meinst du das? Der ADC wird doch von der Funktion aufgerufen,> eingeschaltet und dann nach der Konvertierung (bzw. 1 Dummy Readout+4> zur Mittelwert Bildung) abgeschaltet?
er redet nicht vom ADC.
Er redet von den LED.
Die werden zwar eingeschaltet, aber nie aus.
Wenn die LED erst einmal leuchtet, dann leuchtet sie immer weiter,
selbst dann wenn sie laut ADC Wert eigentlich schon ausgeschaltet werden
sollte.
PS: Mann muss nicht den ADC Wert in eine Spannung umrechnen.
Man kann auch die Grenzenwerte von einer Spannung in die dazu
notwendigen internen ADC Werte zurückrechnen.
Das hat den Charme, dass diese Grenzen innerhalb eines Programmlaufs
konstant sind und man diese Umrechnung daher nur ein einziges mal machen
muss. Das kann zb auch bedeuten: zu Fuss mit dem Taschenrechner.
Dann muss der µC überhaupt nicht mehr rechnen. Der gemessene ADC Wert
wird mit dem Grenzwert (ausgedrückt in ADC Einheiten) verglichen und
fertig.
Sven schrieb:
> Habe nun 5V auch an AREF angelegt und siehe da, er misst ziemlich genau.> Bei 0,52V geht die erste LED an und bei 1,04V die 2. LED mit (mit> Multimeter gemessen).
Das ist nicht ziemlich genau
Dein ADC kann theoretisch auflösen:
5V / 1024 = 0.0048 Volt
Also 4 Millivolt. OK. Surch Schaltungsaufbau und Messfehler kommt da
noch ein kleiner Fehler dazu. Seis drumm: sagen wir er misst auf 10
Millivolt genau. Das sind 0.010 Volt. Und ich gestehe dir diesen Fehler
sogar +- zu! (Das ist ein riesieger Fehler. Wenn der wirklich so groß
wäre, würde es sich um einen Schätzprügel und nicht um einen 10Bit ADC
handeln)
Deine Vorgabe waren 0.500V genau als Schaltschwelle. D.h. die erwartete
Spannung, bei der der Schaltvorgang ausgelöst wird (erinnere dich an die
10Millivolt), liegt irgendwo zwischen 0.49 und 0.51. Und da hab ich dir
bei der Messung schon einen enormen Fehler zugebillgt!
Die Schwelle kommt bei 0.52 Volt. Das ist weit vom erwarteten Wert
entfernt und sollte dir eigentlich ein Hinweis sein, dass irgendetwas
nicht stimmt!
Fazit: Nicht jeden Wert aus einem Computer oder Taschenrechner kritiklos
übernehmen und glauben, sondern ruhig auch einmal nachrechnen ob der
Wert auch plausibel ist.
Es gibt da draussen schon genug Menschen, die mit der Philosophie leben:
Das hat der Computer ausgespuckt, also muss es auch stimmen. Und wenn
das Navi sagt, da wäre eine Brücke, dann ist da auch eine Brücke! Blöd
nur, wenn die Fähre dann gerade am anderen Ufer steht.
Karl heinz Buchegger schrieb:
> Jetzt rechnest du noch einmal.>> Aber diesmal machst du es genau gleich, wie es auch dein µC macht:>> Nach jedem Rechenschritt lässt du die dabei entstehenden>> Nachkommastellen unter den Tisch fallen.
Ok, also z.B. in float rechnen, dann sollte das klappen mit den
Nachkommastellen.
Karl heinz Buchegger schrieb:
> er redet nicht vom ADC.>> Er redet von den LED.>> Die werden zwar eingeschaltet, aber nie aus.>> Wenn die LED erst einmal leuchtet, dann leuchtet sie immer weiter,>> selbst dann wenn sie laut ADC Wert eigentlich schon ausgeschaltet werden>> sollte.
Ok, das habe ich verstanden.
Karl heinz Buchegger schrieb:
> PS: Mann muss nicht den ADC Wert in eine Spannung umrechnen.>> Man kann auch die Grenzenwerte von einer Spannung in die dazu>> notwendigen internen ADC Werte zurückrechnen.
Das ginge aber nur, wenn ich, wie hier im Beispiel, wirklich feste Werte
als Grenzwerte nehme, oder? Wenn ich etwas "stufenlos" regeln oder
umrechnen möchte, muss ich das mit einer zuvor ermittelten Formel
umrechnen oder nicht?
Beispiel: Wenn ich eine Temperatur messen möchte, die jeden Tag anders
ist und ich diese mit dem ADC und dem Poti einstellen kann. Bei
erreichen der Temperatur soll eine LED angehen. Da ich aber jeden Tag
eine neue Temperatur einstelle und vorher die Temperatur noch nicht
weiß, muss ich es ja zwangsläufig umrechen im µC Programm, oder?
Karl heinz Buchegger schrieb:
> Die Schwelle kommt bei 0.52 Volt. Das ist weit vom erwarteten Wert>> entfernt und sollte dir eigentlich ein Hinweis sein, dass irgendetwas>> nicht stimmt!
Ist dieser Fehler wohl eher hardwareseitig zu vermuten, oder? Ich habe
im Moment keinen Kondensator zwischen AREF und Masse gehabt. Mögliche
Ursache?
Sven schrieb:
> Ok, also z.B. in float rechnen, dann sollte das klappen mit den> Nachkommastellen.
Du kannst auch probehalber die Berechnung umstellen :-)
Du dividierst durch 1024 um dann mit 1000 zu multiplizieren.
Wenn du das umdrehst, also zuerst mal 1000 und erst dann durch 1024, was
passiert dann? (Da muss man dann immer aufpassen, dass die
Zwischenergebnisse nicht zu gross werden).
Oder: Wenn du nicht durch 1024 dividierst, sondern durch 102, brauchst
du auch nicht mal 1000 zu nehmen, sondern nur mal 100. Wie wirkt sich
das auf das Ergebnis aus? Ist dieser Fehler (102 statt 102.4) überhaupt
merkbar?
Oder: Anstatt durch 1024 kann man auch durch 512 dividieren und dann mal
500 anstelle von 1000. Wie wirkt sich diese Änderung aus?
Oder ...
Es gibt viele Möglichkeiten. Das schlimmste was du aber tun kannst, ist
mit einer naiven mathematischen Vorstellung an die Sache ranzugehen,
dass Berechnungen im Computer genauso funktionieren wie in der
Mathematik. In der Mathematik hast du es mit idealisierten Zahlen zu
tun, mit denen man alles machen kann. Im Computer gibt es immer
irgendwelche Einschränkungen, die es zu beachten gilt. Oft kann eine
klitzekleine Umstellung in der Berechnung, die mathematisch betrachtet
ein völlig identisches Ergebnis bringen sollte, im Computer sehr viel
ausmachen.
Als Faustregel kannst du dir merken: Du möchtest in einer Berechnung
Divisionen erst möglichst ganz zum Schluss machen. Denn bei einer
Division verlierst du im Allgemeinen immer Genauigkeit. Ein Computer
kann nun mal nicht beliebig viele Stellen hinter dem Komma bearbeiten.
Sein Speicherplatz ist begrenzt.
>> Man kann auch die Grenzenwerte von einer Spannung in die dazu>>>> notwendigen internen ADC Werte zurückrechnen.>>> Das ginge aber nur, wenn ich, wie hier im Beispiel, wirklich feste Werte> als Grenzwerte nehme, oder?
Warum?
> Wenn ich etwas "stufenlos" regeln oder> umrechnen möchte, muss ich das mit einer zuvor ermittelten Formel> umrechnen oder nicht?
Genau. Aber anstelle den ADC Wert in dir genehme Einheiten umzurechnen
und mit einem Grenzwert zu vergleichen, kann man ja auch den umgekehrten
Weg gehen. Man rechnet die Grenze in ADC Einheiten zurück.
> Beispiel: Wenn ich eine Temperatur messen möchte, die jeden Tag anders> ist und ich diese mit dem ADC und dem Poti einstellen kann. Bei> erreichen der Temperatur soll eine LED angehen. Da ich aber jeden Tag> eine neue Temperatur einstelle und vorher die Temperatur noch nicht> weiß, muss ich es ja zwangsläufig umrechen im µC Programm, oder?
Ja, musst du.
Aber: Du musst nur einmal umrechnen, anstatt dauern den ADC Wert
umzurechnen.
Im Prinzip ist diese Rückrechnung die Umkehrung von oben. Da hast du
schon gesehen, dass dir durch / 1024 * 1000 etas verloren geht.
>> Ist dieser Fehler wohl eher hardwareseitig zu vermuten, oder? Ich habe> im Moment keinen Kondensator zwischen AREF und Masse gehabt. Mögliche> Ursache?
Möglich.
Aber denk noch einmal nach.
Wenn ein ADC Wert von 200 (der ganz sicher nicht 0 Volt entspricht) bei
deiner Berechnung einer Millivoltangabe von 0 entspricht (kommt bei
deiner Rechnerei raus), dann kann in der Umrechnung irgendetwas nicht
stimmen :-) Was, hast du ja bereits gesehen: Dadurch dass du die
Umrechnung von ADC Werten in Millivolt ungeschickt gemacht hast, hast du
unnötigerweise Hausnummern herausbekommen, die zwar im groben deinen ADC
Wert in Millivolt umrechnen, aber genau darf man nicht hinsehen.