2 Potis an ADC gegenseitige Beeinflussung

Gast #1891213
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
Angehängte Dateien:
Gast #1891221
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.
#1891231
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.
#1891244
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.
#1891250
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.
Gast #1891252
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ß
Gast #1891256
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.
#1891258
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.
Moderator (Firma: Titel) Persönliche Seite #1891264
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
Gast #1891275
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!
Gast #1891310
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ß

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren