Forum: Mikrocontroller und Digitale Elektronik Temperatur mit MCP9701A und Mega32 messen


von Joul (Gast)


Lesenswert?

Hallo,
ich möchte die Spannung eines aktiven Thermistors MCP9701A von Microchip
mit einem AVR Mega32 messen.
Ich versorge den MCP über einen Portpin des Mega32 mit Spannung um bei
Bedarf Strom zu sparen. Wenn ich nun die Spannung messen will, schalte
ich also den Portpin bzw. die Versorgungsspannung zum MCP ein, warte 1ms
und mache 10 AD Wandlungen, die ich nebenbei mittele.
Das eigentliche Problem ist, dass die Spannung die ich messe im Schnitt
ca. 100mV zu hoch ist. Das heißt bei Zimmertemperatur liegen am Ausgang
des MCP ca. 850mV an (gemessen mit Multimeter), was mit der Temperatur
auch übereinstimmt. Sobald die Wandlung gestartet wird(ADCSRA |=
(1<<ADSC)), erhöht sich die Spannung aber auf ca. 950mV und die messe
ich dann auch mit dem AD-Wandler, was ja aber falsch ist.
Die Ursache ist definitv der AD-Wandler was ich mit einer Messung in
Dauerschleife überprüft habe.
Laut Datenblatt des MCP ist der Anschluss ja denkbar einfach: Vout mit
AD-Eingang verbinden - fertig ggf. noch ein RC-Tiefpass dazwischen.
Ich hab auch schon einen 100k Widerstand auf Masse mit reingeschaltet,
damit der MCP ein bisschen was zu treiben hat - leider ohne Erfolg.

Hat das schon mal jemand mit einem AVR zum Laufen gebracht? Oder sollte
ich doch einen PIC nehmen, falls Microchip Sensoren und AVR's
inkompatibel sind..? Die Kombination MCP mit einem MSP430 funktioniert
jedenfalls!

Bin für jede Anregung dankbar!

von Joul (Gast)


Lesenswert?

Hier noch der Code zum Initialisieren und Messen:
1
void tempMeasInit(void)
2
{
3
  TEMP_DDR  |=  TEMP_VCC;
4
  TEMP_PORT &= ~TEMP_VCC;                       // turn Vcc off
5
6
  ADMUX  = (1<<REFS1)|(1<<REFS0)|TEMP_AD_CH;    // internal 2,56V reference, AD channel
7
8
  ADCSRA = ADCPRESC;                            // 50 - 200kHz 
9
  SFIOR &= 0xF;                                 // free running mode
10
11
}
12
13
14
uint16_t tempMeasRead(void)
15
{
16
  uint8_t i;
17
  div16_t temp;
18
  uint16_t meas = 0;
19
20
  TEMP_PORT |= TEMP_VCC;          // turn Vcc on
21
  ADCSRA |= (1<<ADEN);            // enable ADC
22
  _delay_ms(1);                   // startup time 800us
23
  ADCSRA |= (1<<ADSC);            // start first conversion
24
  while(ADCSRA & (1<<ADSC));      // wait until conversion complete
25
  
26
  temp.byte.high = ADCH;
27
  temp.byte.low  = ADCL;
28
  meas += temp.word;
29
30
  for(i=0; i<9; i++){             // averaging 10 measurements 
31
    _delay_us(5);
32
33
    ADCSRA |= (1<<ADSC);          // start conversion
34
    while(ADCSRA & (1<<ADSC));    // wait until conversion complete
35
36
    temp.byte.high = ADCH;
37
    temp.byte.low  = ADCL;
38
39
    meas += temp.word;
40
    meas >>= 1;
41
  }
42
43
  ADCSRA &= ~(1<<ADEN);
44
  TEMP_PORT &= ~TEMP_VCC;
45
46
  return meas;
47
}

von Anja (Gast)


Lesenswert?

Hallo,

ich würde erst mal schauen ob es wirklich der ADC ist oder nur das aus 
und eingeschalte des Sensors (ergibt laut Datenblatt einen kräftigen 
Überschwinger). Vielleicht ist ja der delay(1ms) zu kurz, sei es der 
Sensor braucht doch etwas mehr oder die Quarzfrequenz stimmt nicht.

Ansonsten: ich sehe nicht ob die Pull-ups des AVR wirklich aus sind.
Etwas ungewöhnlich ist auch der Zugriff auf den ADC mit 2 einzelnen 
Bytes: a) Die Reihenfolge ist falsch es muß zuerst das LOW-Byte gelesen 
werden.
b) Wozu gibt es eigentlich das ADCW-Register? Da bräuchte man sich um 
die richtige Reihenfolge keine Gedanken zu machen.

von Joul (Gast)


Lesenswert?

Danke für die Hinweise! Das Makro ADCW kannte ich bisher noch nicht.
Selbst wenn ich den delay nach dem Einschalten auf 100ms setze, ändert 
sich nichts daran, dass der erste Wert zu hoch ist. Laut Datenblatt 
benötigt der MCP 800us zum Einschwingen und mit 1ms warte ich schon um 
ein Viertel länger. Die delays passen, hab ich mit dem Oszi überprüft.
Der Pull-Up war aus. Jetzt schalte ich ihn in der Init aber explizit 
nochmal aus. Daran liegts also auch nicht.

Was mir noch aufgefallen ist:
Wenn ich in der Zeile
1
meas += ADCW;
 einen Breakpoint setze und die 9 Messungen langsam durchstepe, stimmen 
die Ergebnisse. Füge ich allerdings in der for-Schleife einen delay von 
z.B. 100ms mit ein und lass das Programm ohne Breakpoints laufen, 
stimmen die Ergebnisse wieder nicht. Also kanns doch nicht daran liegen, 
dass die Messungen zu schnell nacheinander ablaufen, oder?

Ich komm einfach nicht drauf, woran das liegen könnte. Hier der 
aktualisierte Code:
1
void tempMeasInit(void)
2
{
3
  TEMP_DDR  |=  TEMP_VCC;                       // as output
4
  TEMP_PORT &= ~(TEMP_VCC | (1<<TEMP_AD_CH));   // turn Vcc off, disable pull-up
5
  TEMP_DDR  &= ~(1<<TEMP_AD_CH);                // as input
6
7
  ADMUX  = (1<<REFS1)|(1<<REFS0)|TEMP_AD_CH;    // internal 2,56V reference, AD channel
8
9
  ADCSRA = ADCPRESC;                            // 50 - 200kHz 
10
  SFIOR &= 0xF;                                 // free running mode
11
12
}
13
14
15
uint16_t tempMeasRead(void)
16
{
17
  uint8_t i;
18
  uint16_t meas;
19
20
  TEMP_PORT |= TEMP_VCC;          // turn Vcc on
21
  ADCSRA |= (1<<ADEN);            // enable ADC
22
  _delay_ms(1);                   // startup time 800us
23
  ADCSRA |= (1<<ADSC);            // start first conversion
24
  while(ADCSRA & (1<<ADSC));      // wait until conversion complete
25
  
26
  meas = ADCW;
27
28
  for(i=0; i<9; i++){             // averaging 10 measurements 
29
    ADCSRA |= (1<<ADSC);          // start conversion
30
    while(ADCSRA & (1<<ADSC));    // wait until conversion complete
31
32
    meas += ADCW;
33
    meas >>= 1;
34
  }
35
36
  ADCSRA &= ~(1<<ADEN);
37
  TEMP_PORT &= ~TEMP_VCC;
38
39
  return meas;
40
}

von Pete K. (pete77)


Lesenswert?

Vielleicht heizt sich der Sensor durch die vielen Messungen auf.
Was passiert bei einer Messung von 1x pro Sekunde?

Wie sieht Dein Schaltplan aus? Hast Du genug Kondensatoren verbaut, 
damit die Spannung beim Messen nicht einbricht?

von Anja (Gast)


Lesenswert?

Hallo,

> einen Breakpoint setze und die 9 Messungen langsam durchstepe, stimmen
> die Ergebnisse. Füge ich allerdings in der for-Schleife einen delay von
> z.B. 100ms mit ein und lass das Programm ohne Breakpoints laufen,
> stimmen die Ergebnisse wieder nicht. Also kanns doch nicht daran liegen,
> dass die Messungen zu schnell nacheinander ablaufen, oder?

Das beweist doch gerade daß Dein Problem irgendwas mit Timing zu tun hat
(möglicherweise geht auch nur die 1. Messung schief).

1. Schritt ADC und Temperatursensor dauernd eingeschaltet lassen

Eventuell liegt es ja an Deiner VAREF-Beschaltung daß die 
Referenzspannung sich zu langsam aufbaut. (laut Datenblatt ist der Pin 
sehr hochohmig)
Du schaltest schließlich nicht nur den Sensor sondern auch den ADC ein.

2. alle Zeiten deutlich vergrößern.

Wenn Du dann einen ordentlichen Zustand hast kannst Du einen Schritt 
nach dem Anderen aufrüsten. Ich würde auch mal alle Messungen in ein 
Array speichern vielleicht sieht man ja einen Trend.

von Anja (Gast)


Lesenswert?

3. Datenblatt lesen:

The first ADC conversion result after switching reference voltage source
may be inaccurate, and the user is advised to discard this result.

von Joul (Gast)


Lesenswert?

Hallo,
ich hab den Sensor und AD-Wandler nun ständig eingeschaltet.
Aber leider bringt das auch nichts. Das die erste Messung nach dem 
Einschalten Müll ist, ok. Hat aber mit meinem eigentlichen Problem in 
erster Linie nicht viel zu tun.
Ich hab mir das Ausgangssignal des Sensors nochmal mit dem Oszi 
angeschaut, wieder einen Breakpoint nach jeder einzelnen Messung gesetzt 
und das Programm durchgestept. Ich kann dabei deutlich erkennen, wie die 
Ausgangsspannung des Sensors um 0,1V steigt sobald eine Messung 
gestartet wird und dann wieder auf den eigentlichen Sollwert abfällt. 
Leider hab ich keinen DSO sonst könnt ich ein Bild vom Signalverlauf 
hier reinstellen. Wenn ich die Messung ohne Breakpoint laufen lasse, ist 
die Ausgangsspannung ständig um 0,1V höher. Ich kann delays einfügen so 
viel ich will und auch Kondensatoren an Vcc und die Ausgangsspannung 
packen. Ändert alles nichts...
Ist es möglich, dass die beiden Stromquellen im analog input circuitry 
des Mega32 (Datenblatt S.217) irgendwie dagegentreiben und so die 
Spannung erhöhen? Wie die Ausgangsstufe des MCP aussieht geht aus dessen 
Datenblatt ja nicht hervor.
Wie schon gesagt, mit dem MSP430 funktioniert die Messroutine 
einwandfrei.

von Ben _. (burning_silicon)


Lesenswert?

irgendwo hab ich gelesen, daß die erste ADC wandlung nach dem 
einschalten des ADC müll ist und weggeschmissen werden sollte. wieso 
machst du das nicht einfach?

von Anja (Gast)


Lesenswert?

>Ist es möglich, dass die beiden Stromquellen im analog input circuitry
>des Mega32 (Datenblatt S.217) irgendwie dagegentreiben und so die
>Spannung erhöhen? Wie die Ausgangsstufe des MCP aussieht geht aus dessen
>Datenblatt ja nicht hervor.

Hallo,

im aktuellen Datenblatt ist das Bild ein paar Seiten vorher.
Das sind aber keine Stromquellen, sondern nur das Ersatzbild für die 
Leckströme. Die sind unter 1uA. Das reicht nicht um den MCP aus dem 
Tritt zu bringen. Der statische Ausgangswiderstand ist 20 Ohm der 
dynamische ca 1 Ohm. Da macht der Leckstrom maximal 20uV. Kritisch wird 
es erst sobald Ströme oberhalb 100uA auftreten, da geht die Endstufe des 
MCP wohl dann in Sättigung. Meiner Meinung bleiben dann nur noch die 
Pull-ups des ATMEGA übrig um einen solchen Fehler zu produzieren. 
(welche andern Programmteile könnten da noch in die Messung 
reinspucken?)

Versuch mal ein paar externe Pull-ups um rauszukriegen welchen 
Widerstand man braucht um exakt denselben Fehler zu produzieren.

von Joul (Gast)


Lesenswert?

Hallo,
wenn ich einen 1,8k Pull-up ranhänge ist die Spannung um den selben Wert 
angehoben. Allerdings kann ich Dir nicht ganz folgen was mir diese 
Erkenntniss jetzt bringt..?
Parallel dazu hab ich den MCP9700A mal ausprobiert. Der hat einen 
anderen Offset und nur 10mV/°C statt 19,5mV/°C. Auf jeden Fall tritt 
dabei der gleiche Fehler auf. Zwar steigt die Spannung nicht um 100mV 
sondern nur um 60mV. Liegt vermutlich an dem kleineren Temperatur 
Koeffizienten.

von Anja (Gast)


Lesenswert?

Hallo,

>wenn ich einen 1,8k Pull-up ranhänge ist die Spannung um den selben Wert
>angehoben. Allerdings kann ich Dir nicht ganz folgen was mir diese
>Erkenntniss jetzt bringt..?

Deine Vermutung war daß die Leckströme 1uA die Ursache sind.
Meine Vermutung war daß die Pull-ups ca 20-50K also ca 150uA die Ursache 
sind.
1,8k für denselben Fehler bedeutet daß man mehr als 2mA braucht um 
denselben Effekt zu erzielen. Wo kommen die 2mA her?

Bleibt nur noch die Idee daß der Pin (kurzzeitig?) als Ausgang 
konfiguriert wird???
Wie ist eigentlich TEMP_VCC definiert? (Bitposition oder Bitmaske?)

von Joul (Gast)


Lesenswert?

1
#define TEMP_VCC    (1<<PA1)

>Bleibt nur noch die Idee daß der Pin (kurzzeitig?) als Ausgang
>konfiguriert wird???

Das müsste der AVR dann aber selbst machen bzw. gebe ich nirgends den 
Befehl dafür.

Ich werd heut mal den Controller tauschen und mal einen anderen Mega32 
einsetzen.

von Anja (Gast)


Lesenswert?

Tja, falls das nichts hilft bleibt immer noch den Assembler-Code 
anschauen. vielleicht macht der Compiler ja nicht was er soll.

von Joul (Gast)


Lesenswert?

Hallo,
einen Mega32 hatte ich leider nicht mehr zur Hand deswegen hab ich's mal 
mit einem Mega16 probiert. Allerdings tritt bei dem der selbe Fehler 
auf...

Am asm Code fällt mir nichts Außergewöhnliches auf:
1
  meas = 0;
2
3
  for(i=0; i<9; i++){             // averaging 10 measurements 
4
    _delay_ms(1);
5
    ADCSRA |= (1<<ADSC);          // start conversion
6
 3ee:  36 9a         sbi  0x06, 6  ; 6
7
    while(ADCSRA & (1<<ADSC));    // wait until conversion complete
8
 3f0:  36 99         sbic  0x06, 6  ; 6
9
 3f2:  fe cf         rjmp  .-4        ; 0x3f0 <tempMeasRead+0x20>
10
11
    meas += ADCW;
12
 3f4:  84 b1         in  r24, 0x04  ; 4
13
 3f6:  95 b1         in  r25, 0x05  ; 5
14
 3f8:  28 0f         add  r18, r24
15
 3fa:  39 1f         adc  r19, r25

Ich werd's die Tage nochmal mit dem IAR Compiler probieren. Wenn das 
nichts hilft, werd ich wohl einen anderen Sensor nehmen müssen.
Trotzdem wäre ich dankbar wenn jemand diesen Fehler bestätigen könnte..?

von Anja (Gast)


Lesenswert?

> Am asm Code fällt mir nichts Außergewöhnliches auf:
na ja, der Delay-Aufruf wurde "wegoptimiert",
die for-Schleife steht jetzt plötzlich vor dem Delay befehl
Das ganze sieht schon ein bischen merkwürdig aus oder?

von frankman (Gast)


Lesenswert?

Was mir auffällt, ist:

Du schreibst in Deinem Code etwas von Vref=2,56V
Aber sollten die Temperaturfühler nicht mit Vref=2,5V betrieben, bzw. 
berechnet werden?

von Joul (Gast)


Lesenswert?

Also mit IAR ist der Messfehler immer noch da. Hätte mich auch 
gewundert. Denn auch wenn der asm Code in der Tat etwas merkwürdig 
aussieht, zwischen dem Einschalten des ADC
1
    ADCSRA |= (1<<ADSC);          // start conversion
2
 3ee:  36 9a         sbi  0x06, 6  ; 6
und der busy-wait schleife
1
    while(ADCSRA & (1<<ADSC));    // wait until conversion complete
2
 3f0:  36 99         sbic  0x06, 6  ; 6
3
 3f2:  fe cf         rjmp  .-4        ; 0x3f0 <tempMeasRead+0x20>
wird an den Pins nichts geschaltet.

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.