Hallo,
ich öchte mit dem ATTINY84A zwei ADC Werte einlesen. Leider musste ich
feststellen, dass die ADC Werte immer gleich sind, obwohl an den Pins
definitiv unterschiedliche Spannungen anliegen (1V und 3V, VREF=VCC=5V).
Ich habe nun schon probiert, nur den MUX umzuschalten, den ADC per ADEN
abzuschalten - Mux umschalten und wieder einzuschalten und bin dabei mit
den Wartezeiten zum "warmwerden" des ADC bis auf 10ms hochgegangen.
Das Ergebnis ist das gleiche. ADC Werte stimmen überein.
Das habe ich damit überprüft, dass ich die If-Schleife zur
"RECLAIBRATION OF BRIGHTNESS" abfragen lasse, ob die Werte gleich sind.
In diesem Fall wird ein Testcode ausgeführt, den ich hier rausgewofen
habe. Eine LED blinkt. Und sie blinkte sehr zuverlässig. Egal ob sich
die gemessenen ADC Input Werte ändern oder nicht.
Was mache ich noch grundlegend falsch, um vernünftig auf 2 ADC Kanälen
messen zu können?
entweder man will mit dem ADC Arbeiten, dann muss man ihn auch
einschalten !
Des weiteren muss man sich nach dem Datenblatt richten und nach
aktivieren der ADC-Einheit den ersten Messwert verwerfen.
Uwe S. schrieb:> Sag mal was soll den das laufend:> ADCSRA &= ~(1<<ADEN);> entweder man will mit dem ADC Arbeiten, dann muss man ihn auch> einschalten !>> Des weiteren muss man sich nach dem Datenblatt richten und nach> aktivieren der ADC-Einheit den ersten Messwert verwerfen.
Wie oben beschrieben: Ich habe unter anderem, wie Sie sehen, probiert
den ADC nach einer Wandlung und vor dem Kanalwechsel auszuschalten. Den
Kanal zu wechslen und wieder einzuschalten.
Die gemessenen Werte werden in den jeweiligen Variablen abgelegt und die
erste Messung sollte nach einer Wartezeit von 10ms im Betriebsmodus free
running längst verworfen sein :)
Oder etwa nicht?
ADCSRA|=(1<<ADEN)|(1<<ADSC);//Enables ADC and starts conversation
2
_delay_ms(10);
3
4
poti_value=(ADCL|(ADCH<<8));//Write ADC result into poti variable
"_delay_ms" ist meiner Ansicht nach keine gute Idee. Entweder ADC
Interrupt oder ADSC in ADCSRA abfragen, siehe Datenblatt ("ADSC will
read as one as long as a conversion is in progress. When the conversion
is complete,
it returns to zero. Writing zero to this bit has no effect.").
Man muss, wie in den anderen Antworten, dass ADEN nicht ein/ausschalten,
dass stört eher. Wenn Du den MUX setzt und danach die Konvertierung mit
ADSC startest und das Ergebnis über Interrupt oder ADSC ausliest, dann
sollte das tun.
Primex schrieb:> Die gemessenen Werte werden in den jeweiligen Variablen abgelegt und die> erste Messung sollte nach einer Wartezeit von 10ms im Betriebsmodus free> running längst verworfen sein :)
Free Running und mehrere Kanäle verwenden?
Da muss man schon ziemlich gut sein, um das in den Griff zu kriegen.
Achim K. schrieb:> Zusätzlich zu den anderen Antworten/Anmerkungen:>> [code]> ADCSRA |= (1<<ADEN) | (1<<ADSC); //Enables ADC and starts conversation> _delay_ms(10);>> poti_value = (ADCL | (ADCH << 8)); //Write ADC result into poti variable> [/code>>> "_delay_ms" ist meiner Ansicht nach keine gute Idee.
Vor allen Dingen ist es sinnlos.
Der Zweck vom Free Running Modus besteht ja gerade darin, dass man nicht
warten muss, sondern sich das Ergebnis abholt, wenn man gerade im
Programm an der bewussten Stelle ist.
Aber manche glaubens halt einfach nicht und wollen auch nicht hören.
Immer schön mit dem Kopf durch die Wand.
Achim K. schrieb:> "_delay_ms" ist meiner Ansicht nach keine gute Idee. Entweder ADC> Interrupt oder ADSC in ADCSRA abfragen, siehe Datenblatt ("ADSC will> read as one as long as a conversion is in progress. When the conversion> is complete,
Im Datenblatt des Tiny ist in einem Timing DIagram abgebildet, dass im
Free running mode der ADSC sich nicht ändert (bleibt auf High)
Karl Heinz schrieb:> Aber manche glaubens halt einfach nicht und wollen auch nicht hören.> Immer schön mit dem Kopf durch die Wand.
Locker bleiben :)
Ich bin für jeden gut gemeinten Ratschalg dankbar und durch Fehler lernt
man am besten :)
Die Wartezeit soll in diesem Fall eigentlich nur sicherstellen, dass der
ADC nach dem wieder einschalten vernünftig "warmgelaufen" ist. War
ursprünglich mal bei xxus, habe ich dann aber nach und nach hochgezogen,
bevor ich mich hier ans Forum wandt.
Karl Heinz schrieb:> Vor allen Dingen ist es sinnlos.> Der Zweck vom Free Running Modus besteht ja gerade darin, dass man nicht> warten muss, sondern sich das Ergebnis abholt, wenn man gerade im> Programm an der bewussten Stelle ist.>
Ich muss gestehen, dass bei soviel Code ich nicht jedes Bit anschauen
:-).
Das mit dem "Free Running" habe ich schlicht übersehen.
@Primex:
Man muss nicht immer alles aus der Hardware holen. Manchmal reicht ein
"Bruchteil" und dafür robust. Mach kein "Free Running" sondern stosse
die Konvertierungen einzeln an. Also MUX setzten, ADSC setzen, warten
bis ADSC 0 ist, ADC Wert auslesen, Mux auf anderen Kanal usw. Selbst mit
dieser Bremse gehe ich davon aus, dass es insgesamt schnell genug ist.
Oder wie oft soll Dein Programm etwas nachregeln? Alle Sekunde? Oder
10000x pro Sekunde?
Primex schrieb:> Die Wartezeit soll in diesem Fall eigentlich nur sicherstellen, dass der> ADC nach dem wieder einschalten vernünftig "warmgelaufen" ist.
Quatsch.
Die Wartezeit brauchst du aus mehreren Gründen. Unter anderem deshalb,
weil du nicht weißt, mit welcher MUX Einstellung die gerade laufende
Wandlung eigentlich operiert. Sprich nach dem unsynchronisierten
Umstellen der MUX Bits müsstest du 2 Wandlungen abwarten, bis du sicher
gehen kannst, dass das Ergebnis auch vom eingestellten Kanal kommt.
Free-Running und _delay_ms erinnert mich irgendwie an die Bundeswehr. Da
muss auch der Papierkorb so schnell wie möglich ausgeleert werden (am
besten in 2 Zehntel Sekunden), nur damit man dann 3 Stunden lang
Däumchen dreht.
Völlig sinnlos.
Achim K. schrieb:> Oder wie oft soll Dein Programm etwas nachregeln? Alle Sekunde? Oder> 10000x pro Sekunde?
Das Programm regelt die Helligkeit einer LED. Ich füge zum Schluss eh
ein Delay von 25ms ein um der Änderung der Helligkeit etwas Zeit zu
geben sich zu realisieren :)
Ich gehe derzeit also davon aus, dass der Single Conversion Mode hierfür
deutlich besser geeignet ist!?
Muss ich dabei die erste Messung nicht verwerfen und kann direkt die
Kanäle wechseln, auslesen, abwarten auf ADSC=0 und weitermachen?
Sehe ich das richtig?
Achim K. schrieb:> bis ADSC 0 ist, ADC Wert auslesen, Mux auf anderen Kanal usw. Selbst mit> dieser Bremse gehe ich davon aus, dass es insgesamt schnell genug ist.
Wobei in seinem Fall, die 'Bremse' schneller abgearbeitet wird, als der
Käse, den er jetzt hat. Tatsächlich ist in seinem Fall der Free-Running
Modus jetzt zur Bremse geworden.
Primex schrieb:> Achim K. schrieb:>> "_delay_ms" ist meiner Ansicht nach keine gute Idee. Entweder ADC>> Interrupt oder ADSC in ADCSRA abfragen, siehe Datenblatt ("ADSC will>> read as one as long as a conversion is in progress. When the conversion>> is complete,>> Im Datenblatt des Tiny ist in einem Timing DIagram abgebildet, dass im> Free running mode der ADSC sich nicht ändert (bleibt auf High)
Das mit dem "Free Running" hatte ich leider übersehen :-).
Wenn man das wirklich braucht, dann muss man den Interrupt nehmen.
Ich baue meine Programme meist ohne "Free Running" so, dass der
Interrupt die Werte ausliest in eine globale Datenstruktur schreibt, den
MUX anpasst und neu startet. Der nächste Interrupt macht dann wieder das
selbe mit dem nächsten Kanal. Man kann dann noch über eine Maske
signalisieren, dass neue Werte da sind. Ist aber oft nicht nötig.
Je nachdem kann man aber auch ebenfalls ohne "Free Running" einfach auf
das ADSC Bit warten. Kommt drauf an, was das Programm in der Wartezeit
sinnvoll tun kann/muss.
Primex schrieb:> Ich gehe derzeit also davon aus, dass der Single Conversion Mode hierfür> deutlich besser geeignet ist!?
Wie in mehr als 95% aller Fälle.
> Muss ich dabei die erste Messung nicht verwerfen und kann direkt die> Kanäle wechseln, auslesen, abwarten auf ADSC=0 und weitermachen?> Sehe ich das richtig?AVR-GCC-Tutorial
Such nach ADC. Im Tutorial ist ein Link auf einen weiterführenden
Artikel. Dort finden sich entsprechende Funktionen, die du nur noch
verwenden musst.
Primex schrieb:> Achim K. schrieb:>> Oder wie oft soll Dein Programm etwas nachregeln? Alle Sekunde? Oder>> 10000x pro Sekunde?>> Das Programm regelt die Helligkeit einer LED. Ich füge zum Schluss eh> ein Delay von 25ms ein um der Änderung der Helligkeit etwas Zeit zu> geben sich zu realisieren :)>> Ich gehe derzeit also davon aus, dass der Single Conversion Mode hierfür> deutlich besser geeignet ist!?> Muss ich dabei die erste Messung nicht verwerfen und kann direkt die> Kanäle wechseln, auslesen, abwarten auf ADSC=0 und weitermachen?> Sehe ich das richtig?
Du siehst es (so weit ich es sehen kann :-) ) richtig.
Meiner Erfahrung nach muss man nur den 1. Werte nach ADEN verwerfen.
Danach MUX := Kanal, ADSC := 1, warten auf ADSC == 0 und ADC auslesen.
Oder Interrupt Lösung, wenn man die Wartezeit nutzen will/muss.
Achim K. schrieb:> Meiner Erfahrung nach muss man nur den 1. Werte nach ADEN verwerfen.> Danach MUX := Kanal, ADSC := 1, warten auf ADSC == 0 und ADC auslesen.> Oder Interrupt Lösung, wenn man die Wartezeit nutzen will/muss.
Interrupt kann man machen, muss man aber oft nicht.
Anstatt
1
while(1)
2
{
3
MUXsetzen
4
ADSCsetzen
5
while(ADSCgleich1)
6
;
7
ADCauslesen
8
9
machwasmitdemgelesenen
10
}
kann man das ja auch modifizieren
1
MUXsetzen
2
ADSCsetzen
3
4
while(1)
5
{
6
while(ADSCgleich1)
7
;
8
ADCauslesen
9
10
MUXsetzen
11
ADSCsetzen
12
13
machwasmitdemgelesenen
14
}
auch hier arbeitet der ADC parallel zum Codeteil 'mach was mit dem
gelesenen' und man spart sich den ganzen Interrupt Aufsatz.
Wenn man allerdings in der Hauptschleife sowieso ein _delay_ms(25) hat,
dann ist das alles völlig egal. Denn im Vergleich zu diesen 25ms sind
die paar µs, die der ADC braucht, lediglich Peanuts. Macht man halt
anstelle von 25ms nur 24ms, dann hat man die ADC Zeit locker wieder
herinnen.
Habe nun einige gute Ideen durch euch erhalten.
Ich bedanke mich ganz herzlich bei allen Ideengebern und werde mich
nochmal melden, ob es nun geklappt hat und wie ich es umgesetzt habe :)
Danke!