Forum: Mikrocontroller und Digitale Elektronik 2 Potis an ADC gegenseitige Beeinflussung


von Alex (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen,

ich betreibe wie im angehängten Schaltplan dargestellt 2 Potis am ADC 
eines ATMega32.
Da ich keine absolute Spannung messen will, habe ich die 1M Potis direkt 
auf Vref gelegt.
Leider habe ich das Problem, dass die Spannung an ADC0 von der 
Potistellung an ADC1 leicht beeinflusst wird und umgekehrt, wohl durch 
die Stromänderung.

Hat jemand eine einfach Idee wie ich das verhindern kann?
Ich denke das Problem ist recht trivial, aber analoge Schaltungstechnik 
ist definitiv nicht meine Stärke ;)

Vielen Dank schonmal,
Alex

von Peter D. (peda)


Lesenswert?

Ist zu 99,99% ein SW-Fehler.


Peter

von Alex (Gast)


Lesenswert?

Hallo Peter, hier mein Code:
1
/* ADC initialisieren */
2
  // externe referenz (AVCC) nutzen und die MSBs in ADCL ablegen
3
  ADMUX |= (1<<REFS0);
4
  // prescaler einstellen (bei 16Mhz zwischen 80 und 240 -> 128 einstellen)
5
  ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
6
  // ADC anschalten
7
  ADCSRA |= (1<<ADEN);
8
9
  while(1)  
10
  {
11
    /* Servo 1 Update an ADC0*/
12
    // Kanal von ADC w�hlen
13
    ADMUX &= ~(1<<MUX0);
14
    // ADC Messung anstossen und warten
15
    ADCSRA |= (1<<ADSC);
16
    while ( !(ADCSRA & (1<<ADIF)));
17
    // Wert an ADC berechnen
18
    tmp = (float)ADC/1023; //ADC: Wert von 0 ... 1023  // 0->1000us, 1023->2000us, 512->1500us
19
    ServoPos1 = (uint16_t)(tmp*250) + 250; // 250 ... 500 mitte 375
20
21
22
    /* Servo 2 Update an ADC1 */
23
    // Kanal von ADC w�hlen
24
    ADMUX |= (1<<MUX0);
25
    // ADC Messung anstossen und warten
26
    ADCSRA |= (1<<ADSC);
27
    while ( !(ADCSRA & (1<<ADIF)));
28
    // Wert an ADC berechnen
29
    tmp = (float)ADC/1023; //ADC: Wert von 0 ... 1023  // 0->1000us, 1023->2000us, 512->1500us
30
    ServoPos2 = (uint16_t)(tmp*250) + 250; // 250 ... 500 mitte 375
31
}

Habe gerade entdeckt dass ich im Schaltplan Aref geschrieben habe, das 
muss AVcc heißen.

von Karl H. (kbuchegg)


Lesenswert?

1
    while ( !(ADCSRA & (1<<ADIF)));

Du verwendest kein Interrupt gesteuertes auslesen. Also lass das ADIF 
Flag in Ruhe.

Du setzt das ADSC Flag um den ADC das Signal zum loslegen zu geben. Der 
ADC löscht das Flag wieder, wenn er fertig ist
1
    while ( ADCSRA & (1<<ADSC))
2
      ;

Das ADIF Flag müsstest du selbst löschen. Es wird nur duch den Aufruf 
einer Interrupt Funktion oder indem du es aus dem Code heraus löscht 
(durch Schreiben eines 1 Bits) zurückgesetzt.
Das ist in den Datenblättern etwas unglücklich ausgedrückt. Einfacher 
ist es, sich an das ADSC Bit zu klemmen um festzustellen, ob eine 
Konvertierung beendet ist.

von Peter D. (peda)


Lesenswert?

Alex schrieb:
> Da ich keine absolute Spannung messen will, habe ich die 1M Potis direkt
> auf Vref gelegt.

Das ist zu hochohmig, nimm mal 10k Potis.
Alternativ kannst Du auch einige Dummy-Messungen nach MUX-Wechsel 
machen, damit sich der ADC umladen kann.


Peter

von Alex (Gast)


Lesenswert?

Stimmt, da hat sich ein Fehler eingeschlichen...
Habe ihn soeben behoben, aber das Problem tritt weiterhin auf.

von Peter D. (peda)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du verwendest kein Interrupt gesteuertes auslesen. Also lass das ADIF
> Flag in Ruhe.

Kann er ruhig nehmen, er löscht es ja wieder:
1
ADCSRA |= (1<<ADSC);


Peter

von Alex (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Das ist zu hochohmig, nimm mal 10k Potis.
> Alternativ kannst Du auch einige Dummy-Messungen nach MUX-Wechsel
> machen, damit sich der ADC umladen kann.

Kannst du mir kurz erklären warum die 1M Potis hier Probleme machen?
Ich würde es gerne verstehen

von Helmut L. (helmi1)


Lesenswert?

Alex schrieb:
> Da ich keine absolute Spannung messen will, habe ich die 1M Potis direkt
> auf Vref gelegt.

1MOhm ist viel zu hochohmig.

von Karl H. (kbuchegg)


Lesenswert?

Peter Dannegger schrieb:
> Karl heinz Buchegger schrieb:
>> Du verwendest kein Interrupt gesteuertes auslesen. Also lass das ADIF
>> Flag in Ruhe.
>
> Kann er ruhig nehmen, er löscht es ja wieder:
>
1
> ADCSRA |= (1<<ADSC);
2
>

Ooops. Du hast recht.
Ich würde trotzdem nicht tun. Das wär mir ehrlich gesagt zu implizit und 
zu versteckt. Zumindest hätte es sich einen Kommentar verdient, dass 
hier als Nebeneffekt das ADIF gelöscht wird.

Mein Fehler.

von Helmut L. (helmi1)


Lesenswert?

Alex schrieb:
> Kannst du mir kurz erklären warum die 1M Potis hier Probleme machen?
> Ich würde es gerne verstehen

Dein ADC hat eine Sample und Hold und ein Kapazitives Netzwerk im 
Eingang.
Diese Kapazitaeten muessen erstmal umgeladen werden und das braucht 
Zeit.

von Karl H. (kbuchegg)


Lesenswert?

Alex schrieb:
> Peter Dannegger schrieb:
>> Das ist zu hochohmig, nimm mal 10k Potis.
>> Alternativ kannst Du auch einige Dummy-Messungen nach MUX-Wechsel
>> machen, damit sich der ADC umladen kann.
>
> Kannst du mir kurz erklären warum die 1M Potis hier Probleme machen?
> Ich würde es gerne verstehen

Kurz und vereinfacht gesagt:
Im ADC sitzt ein kleiner Kondensator, der die Spannung konstant halten 
soll, solange der ADC arbeitet.
Dieser Kondensator muss auf die anliegende Spannung aufgeladen werden. 
Dazu braucht er aber Strom. Nicht viel, aber doch.
Strom, der über 1MOhm (bzw. den jeweiligen Anteil) nicht mehr fliessen 
kann, damit er sich in der kurzen Zeit die du ihm gibst, auf den 
Spannungswert aufladen kann.

von Jojo (Gast)


Lesenswert?

Ich glaube auch, daß deine Potis viel zu hochohmig sind. Da misst du ja 
eher das kosmische Rauschen mit :) ...

Nimm 10k-Potis, mach Dummy-Messungen und schau vielleicht nochmal in den 
Code aus dem Tutorial (wg. Abfrage des ADCs und so).

Außerdem finden die kleinen AVRs das Rechnen mit floats total doof :( . 
So einfach Kram wie bei dir kann man eigentlich problemlos mit 
Festkommaarithmetik erschlagen...
http://www.mikrocontroller.net/articles/Festkommaarithmetik

Gruß

von Alex (Gast)


Lesenswert?

Ok, vielen Dank euch.
Leider habe ich nur noch ein 10k Poti hier rumfliegen, werde mir 
Nachmittags noch eins besorgen und dann kurz berichten obs geklappt hat.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Alex schrieb:
> Leider habe ich das Problem, dass die Spannung an ADC0 von der
> Potistellung an ADC1 leicht beeinflusst wird und umgekehrt
Was heißt "leicht"?
Der 1MOhm Widerstand ist relativ hoch. Schalt da mal noch einen 
100nF-Kondensator zwischen den Schleiferanschluss und GND.

von U.R. Schmitt (Gast)


Lesenswert?

Alex schrieb:
> Kannst du mir kurz erklären warum die 1M Potis hier Probleme machen?
> Ich würde es gerne verstehen

Der AD Wandler hat eine Sample and Hold Stufe. Das heisst ein kleiner 
Kondensator wird auf die zu messende Spannung aufgeladen und dann der 
Eingang während der eigentlichen Messung vom Messsystem getrennt. So 
vermeidet man Fehlmessungen, die auftreten können wenn sich die 
Messspannung während der Messung ändert.
Zum Aufladen des S/H Kondensators muss aber ein bestimmter Strom 
fliessen, und zwar umso mehr, je weniger Zeit Du dem Kondensator 
zwischen 2 Messungen lässt.
Das müsste auch im Datenblatt des µCs stehen (maximale Eingangsimpedanz 
evt. in Abhängigkeit von der Zeit zwischen dem Umschalten auf einen ADC 
Kanal und der Messung.
Die Potis sind viel zu hochohmig, daß sich der S&H C schnell genug 
umladen kann.

von U.R. Schmitt (Gast)


Lesenswert?

Mal wieder zu langsam :-)

von Karl H. (kbuchegg)


Lesenswert?

Und wie JoJo schon sagte, ändere auch das
1
    tmp = (float)ADC/1023; //ADC: Wert von 0 ... 1023  // 0->1000us, 1023-2000us, 512->1500us
2
    ServoPos2 = (uint16_t)(tmp*250) + 250; // 250 ... 500 mitte 375

Wenn du nicht durch 1023 sondern durch 1024 dividierst (was sowieso 
richtiger ist), dann gibt es eine völlig naheliegende 'Optimierung', die 
deinem µC das Leben wesentlich erleichtert.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ich hatte da wohl zu lange gewartet... ;-)

U.R. Schmitt schrieb:
> Die Potis sind viel zu hochohmig, daß sich der S&H C schnell genug
> umladen kann.
Wie gesagt: probier da mit den Kondensatoren mal. Damit wird der 
dynamische Widerstand des Potis reduziert.

Und das solltest du dir noch mal anschauen:
1
    tmp = (float)ADC/1023; //ADC: Wert von 0 ... 1023  // 0->1000us, 1023->2000us, 512->1500us
2
    ServoPos2 = (uint16_t)(tmp*250) + 250; // 250 ... 500 mitte 375
Das geht garantiert ohne Fließkommazahlen.

EDIT:
> Wenn du nicht durch 1023 sondern durch 1024 dividierst
Und zudem ist es erst dann auch mathematisch richtig.... :-o
Denn der ADC macht ja 1024 Schritte: 0...1023

von Alex (Gast)


Lesenswert?

Festkommaaritmetik hab ich jetzt drin, scheint zu funktionieren.
Der 100n C vom Schleifer zur Masse war wohl der richtige Tipp !

Jetzt kann ich keine Beeinflussung mehr messen.
Vielen Vielen Dank euch allen!

von U.R. Schmitt (Gast)


Lesenswert?

Alex schrieb:
> Der 100n C vom Schleifer zur Masse war wohl der richtige Tipp !

Du musst Dir nur im klaren sein, daß die Spannung am Poiausgang ggf. 
etwas verzögert ändert. Wenn man eine Worstcase Rechnung aufmacht (5*tau 
und fast max. Widerstand kommt man auf knapp 0,5Sekunden bei Mittelwert 
(500KOhm und 5Tau) auf 0,25 Sekunden.
Das heisst als Joystickeingang kann man das nicht benutzen. Für einen 
Poti der moderat langsam verstellt wird ist das OK.
Gruß

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

U.R. Schmitt schrieb:
> 5*tau
Nach 5Tau hat die Spannung erst 99,3% des Endwerts erreicht.
Das reicht für einen 10-Bit-Wandler eigentlich noch nicht ganz... ;-)

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.