Forum: Mikrocontroller und Digitale Elektronik ATTiny44 ADC driftet über längere Zeit nach oben


von Johannes H. (jhuebner)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe ein Problem mit der Messschaltung aus dem Anhang. Sie benutzt 
sehr hochohmige Spannungteiler um die Spannungen an 6 in Reihe 
geschalteten Akkus zu messen. Das funktioniert auch gut, sowohl in der 
Tiefkühltruhe als auch im Ofen.
Allerdings läuft einige Zeit nach dem Einschalten (5-10Min. nicht 
konstant) immer ein oder zwei Kanäle einige Digits (bis jetzt 3-6) nach 
oben weg, während die anderen Kanäle stabil bleiben. Bis jetzt waren das 
immer Kanal 3 und 6.
Wenn ich die Spannung in dem entsprechenden Pin messe, messe ich 
natürlich Mist weil mein Multimeter ja auch einen Eingangswiderstand 
hat. Das Problem ist danach auch erstmal weg. Gleiches gilt, wenn ich 
mit einer Brücke den Eingang kurz auf Masse ziehe.

Der Tiny läuft mit 1MHz und der ADC mit 1/128 MHz. Damit ist er 
offiziell untertaktet, aber wenn ich ihn höher takte besteht das Problem 
immer noch.

Der ADC läuft im single shot Modus und wird durch ein Sleep getriggert:
1
   set_sleep_mode(SLEEP_MODE_IDLE);
2
   do {
3
      sleep_cpu(); //This also starts the A/D conversion
4
   } while ((ADCSRA & (1 << ADSC)) > 0);
(SLEEP_MODE_ADC funktioniert irgendwie nicht, aber das soll hier nicht 
das Problem sein).

In der ISR passiert folgendes:
1
ADC_ISR
2
{
3
   uint8_t chan = GET_ADC_CHAN();
4
5
   if (chan < NUM_INPUTS)
6
   {
7
      filtered[chan] = IIRFilter(ADC, filtered[chan]);
8
      chan++;
9
      if (NUM_INPUTS == chan)
10
      {
11
         chan = CHAN_TEMP;
12
         USE_INT_VREF();
13
      }
14
   }
15
   else if (CHAN_TEMP == chan)
16
   {
17
      temp = IIRFilter(ADC, temp);
18
      chan = 0;
19
      USE_EXT_VREF();
20
   }
21
22
   SET_ADC_CHAN(chan);
23
}
Nachdem die 6 Spannungen gemessen wurden wird also auf die interne Vref 
und den Temperatursensor umgeschaltet. Alle Werte werden durch einen 
IIR-Filter geschleust
1
static uint16_t IIRFilter(uint16_t newVal, uint16_t lastVal)
2
{
3
   // filtered = (2*newVal + ((2^C) - 1) * lastVal) / 2^C
4
   return (newVal + (lastVal << IIR_FILTER_CONST) - lastVal) >> IIR_FILTER_CONST;
5
}

Während dem stromintensiven Senden mit der IR Diode findet keine Messung 
statt.

Es scheint irgendwie so, als ob der Eingangs-C sich etwas höher auflädt 
als er soll und sobald ich ihn einmal entlade ist das Problem ein paar 
Minuten lang weg.

Sieht jemand was, was ich nicht sehe?

Danke und Gruß
Johannes

von Karl H. (kbuchegg)


Lesenswert?

>    SET_ADC_CHAN(chan);

und in SET_ADC_CHAN startest du die nächste Messung?

Gib dem ADC nach dem Umschalten des Eingangs ein wenig Zeit. Im ADC ist 
selbst wieder ein Kondensator verbaut, der sich erst mal umladen muss. 
Und das dauert eben seine Zeit. Atmel geht sogar soweit, die Empfehlung 
auszusprechen, das erste Messergebnis nach dem Wechsel des Eingangs zu 
verwerfen.

: Bearbeitet durch User
von Johannes H. (jhuebner)


Lesenswert?

Karl Heinz Buchegger schrieb:
>>    SET_ADC_CHAN(chan);
>
> und in SET_ADC_CHAN startest du die nächste Messung?
>
> Gib dem ADC nach dem Umschalten des Eingangs ein wenig Zeit. Im ADC ist
> selbst wieder ein Kondensator verbaut, der sich erst mal umladen muss.
> Und das dauert eben seine Zeit.

Hallo und danke!

SET_ADC_CHAN schaltet nur den Mux um:
1
#define SET_ADC_CHAN(c)  (ADMUX = (ADMUX & (uint8_t)~0x2f) | c)

Die nächste Messung wird mit dem sleep gestartet sobald das ADSC-Flag 
gelöscht ist.

Wann wird das eigentlich gelöscht? Beim Eintritt in den Handler? Soll 
ich mal irgendwo testweise ein delay hinmachen?

von Johannes H. (jhuebner)


Lesenswert?

Also ich hatte erst noch die Eingangspuffer deaktiviert (DIDR=0x3f) was 
aber nichts geändert hat.
Dann hatte ich noch ein Delay hinter das sleep gemacht, hat aber auch 
nichts geändert.

Testweise habe ich nun folgendes gemacht:
1
if (adcCyc > 30000)
2
{
3
   adcCyc = 0;
4
   DDRA ^= 0x3f;
5
   PORTA = 0;
6
   DDRA ^= 0x3f;
7
}
Alle 30000 A/D-Zyklen (~30s) schalte ich also für einen Takt die Pins 
auf GND und entlade damit die Eingangs C - zumindest ein wenig.

Damit ist das Phänomen erstmal weg, auch wenns das Problem nicht gerade 
an der Wurzel packt.

Ich habe nun eine Theorie: Im S&H Kondensator bildet sich ein Mittelwert 
aus dem vorherigen Kanal und dem aktuellen Kanal - gewichtet mit der 
Kapazität des S&H Kondensators zu der des Eingangskondensators

Wenn das zutrifft würde es vielleicht helfen, den MUX zwischen den 
Kanälen auf GND zu schalten. Dann werden zwar die Eingänge beim samplen 
stärker belastet aber zumindest immer gleich.

Folgende Aufstellung zeigt die Spannung an den Pins, wenn ich die 
Schaltung am Kalibrierer hängen habe (U, Ugeteilt):
4  3,007518797
8  3,0769230769
8  1,8518518519
16  2,8070175439
16  2,4242424242
16  2,0779220779

Das würde erklären warum vorwiegend Kanal 3 und 6 betroffen sind und wie 
ich nun festgestellt habe auch Kanal 5.

: Bearbeitet durch User
von Johannes H. (jhuebner)


Lesenswert?

So, ich führe mal mein Selbstgespräch weiter ;)

Ich habe jetzt die ISR so geändert, dass zwischen den Spannungsmessungen 
einmal VREF (=1,1V) gemessen wird. Also U1,Vref,U2,Vref,U3,....
Ich habe also Vref statt GND genommen, damit der S&H Kondensator nicht 
ganz entladen wird.
Damit ist mein Problem dann auch weg. Meinungen?

1
ADC_ISR
2
{
3
   uint8_t chan = GET_ADC_CHAN();
4
5
   if (CHAN_REF == chan)
6
   {
7
      chan = prevChan + 1;
8
      if (NUM_INPUTS == chan)
9
      {
10
         chan = CHAN_TEMP;
11
         USE_INT_VREF();
12
      }
13
   }
14
   else if (chan < NUM_INPUTS)
15
   {
16
      filtered[chan] = IIRFilter(ADC, filtered[chan]);
17
      prevChan = chan;
18
      chan = CHAN_REF;
19
   }
20
   else if (CHAN_TEMP == chan)
21
   {
22
      temp = IIRFilter(ADC, temp);
23
      chan = 0;
24
      USE_EXT_VREF();
25
   }
26
27
   SET_ADC_CHAN(chan);
28
}

von Oliver (Gast)


Lesenswert?

Probiers halt einfach aus. Mach nach jedem Kanalwechsel testweise nicht 
nur eine Messung, sondern einige dutzend, und schau dir an, was da 
passiert. Sind die Werte konstant, prima, sind sie es nicht, dann nicht.

Bei der hochohmigen Quelle hilft dann nur Zeit. Da sollte aber dich kein 
Problem sein, die AKkuspkannung ist ja nun üblicherseise quasi-statisch.

Oliver

von Johannes H. (jhuebner)


Lesenswert?

Oliver schrieb:
> Probiers halt einfach aus. Mach nach jedem Kanalwechsel testweise nicht
> nur eine Messung, sondern einige dutzend, und schau dir an, was da
> passiert. Sind die Werte konstant, prima, sind sie es nicht, dann nicht.
>
> Bei der hochohmigen Quelle hilft dann nur Zeit. Da sollte aber dich kein
> Problem sein, die AKkuspkannung ist ja nun üblicherseise quasi-statisch.
>
> Oliver

Super! Da habe ich mal wieder die offensichtliche Lösung nicht gesehen. 
Das funktioniert noch besser weil dann die Umladerei zwischen den 
Kanälen wegfällt.

Besten Dank!

von Peter D. (peda)


Lesenswert?

Johannes Hübner schrieb:
> Damit ist mein Problem dann auch weg.

Die Drift ist weg, das Ergebnis bleibt aber falsch.
Nimm mal statt der 10nF besser 100nF.

von Johannes H. (jhuebner)


Lesenswert?

Peter Dannegger schrieb:
> Die Drift ist weg, das Ergebnis bleibt aber falsch.
> Nimm mal statt der 10nF besser 100nF.

Was heißt "falsch"?
Der S&H C hat 14pF, da ist ja 10nF fast 3 Größenordnungen mehr.
Ich hätte gerne 100n genommen, aber dann habe ich am obersten 
Spannungsteiler einen Tiefpass mit T=4,2s. Das ist mir zu langsam.

Ich teste noch ein bißchen...

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.