Forum: Mikrocontroller und Digitale Elektronik ATTINY84A ADC Werte sind gleich


von Primex (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Uwe (de0508)


Lesenswert?

Sag mal was soll den das laufend:
1
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.

von Primex (Gast)


Lesenswert?

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?

von Eduard S. (schneehase)


Lesenswert?

Das hier ist wohl nicht ganz richtig.
1
ADMUX &= ~(1<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (1<<MUX0); //CLEAR ADC

sollte wohl eher das hier sein
1
ADMUX &= ~(  (1<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (1<<MUX0)  ); //CLEAR ADC

von Karl H. (kbuchegg)


Lesenswert?

Wahnsinn.
Dabei könnte das mit den Tutorial-Routinen alles so einfach sein
1
int main()
2
{
3
4
  ADC_Init();
5
6
  while( 1 )
7
  {
8
    uint16_t wert1 = ADC_Read( 0 );
9
    uint16_t wert2 = ADC_Read( 1 );
10
11
    ... mach was mit wert1 und wert2
12
  }
13
}

fertig.

: Bearbeitet durch User
von Achim K. (aks)


Lesenswert?

Zusätzlich zu den anderen Antworten/Anmerkungen:
1
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.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Primex (Gast)


Lesenswert?

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)

von Primex (Gast)


Lesenswert?

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.

von Achim K. (aks)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Primex (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Achim K. (aks)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Achim K. (aks)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
   MUX setzen
4
   ADSC setzen
5
   while( ADSC gleich 1)
6
     ;
7
   ADC auslesen
8
9
   mach was mit dem gelesenen
10
 }

kann man das ja auch modifizieren
1
 MUX setzen
2
 ADSC setzen
3
4
 while( 1 )
5
 {
6
   while( ADSC gleich 1 )
7
     ;
8
   ADC auslesen
9
10
   MUX setzen
11
   ADSC setzen
12
13
   mach was mit dem gelesenen
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.

: Bearbeitet durch User
von Primex (Gast)


Lesenswert?

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!

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.