Forum: Mikrocontroller und Digitale Elektronik MCP3551 Delta-Sigma-ADC Ungenau


von Manuel H. (manu77)


Angehängte Dateien:

Lesenswert?

Ich habe ein Problem mit dem MCP3551. Er ist wie im Anhang beschrieben 
verschaltet. Bei Messungen erhalte ich jetzt allerdings ein Toleranzband 
von 1 - 2.5°C ohne Mittelwertbildung bei einem 100 Ohm Widerstand bei 
konstanter Temperatur. Gibt es Möglichkeiten diese Schaltung weiter zu 
Entstören?

MfG,
Manuel

von Jens (Gast)


Lesenswert?

Passt deine Samplerate? Du kannst in etwa 13,75mal pro Sekunde Messen 
mit genauen ergebnissen.
Was wird an dem Widerstand gemessen? Temperatur? Passt die Umrechnung?
Du kannst noch zwischen IN+ und IN- einen Kondensator (1nF-10nF) 
schalten um Störungen besser blocken zu können.
Am besten auch mal den Sourcecode posten. Sonst sind das nur 
Mutmaßungen.

Gruß, Jens

von Manuel H. (manu77)


Lesenswert?

Die Schaltung soll einen PT100 auf 0.1 °C genau messen.

Mainschleife:
1
PTCoolDown++;
2
    
3
    // PT100 Test:
4
    if(PTCoolDown >= 100)
5
    {    
6
      if(!SEN_PT100_MessungLaeuft)
7
      {
8
        // Wenn alle Teilmessungen erledigt, neue Messreihe starten:
9
      
10
        // PT100 Messung anregen:
11
        mcp3551_StosseMessungAn();
12
      
13
        SEN_PT100_MessungLaeuft = 1;      
14
      }
15
      else if(BerechnePT100Temperatur(&SEN_DeciTemperatur))
16
      {      
17
        if(tmin > SEN_DeciTemperatur)
18
          tmin = SEN_DeciTemperatur;
19
      
20
        if(tmax < SEN_DeciTemperatur)
21
          tmax = SEN_DeciTemperatur;
22
      
23
        SEN_PT100_MessungLaeuft = 0;      
24
        PTCoolDown = 0;
25
      }
26
    }
27
28
uint8_t stelle;
29
    
30
    if((SEN_DeciTemperatur % 10) < 0)
31
      stelle = (SEN_DeciTemperatur % 10) * -1;
32
    else
33
      stelle = (SEN_DeciTemperatur % 10); 
34
    
35
    sprintf(Str, "PT100: %d.%d C", (SEN_DeciTemperatur / 10), stelle);      
36
    Ft_Gpu_CoCmd_Text(Ft_DispWidth/2 + 150, 30, 27,OPT_RIGHTX|OPT_CENTERY,Str);  
37
    
38
    if((tmin % 10) < 0)
39
      stelle = (tmin % 10) * -1;
40
    else
41
      stelle = (tmin % 10); 
42
    
43
    sprintf(Str, "min: %d.%d C", (tmin / 10), stelle);      
44
    Ft_Gpu_CoCmd_Text(Ft_DispWidth/2 + 150, 55, 27,OPT_RIGHTX|OPT_CENTERY,Str);  
45
    
46
    if((tmax % 10) < 0)
47
      stelle = (tmax % 10) * -1;
48
    else
49
      stelle = (tmax % 10); 
50
    
51
    sprintf(Str, "max: %d.%d C", (tmax / 10), stelle);      
52
    Ft_Gpu_CoCmd_Text(Ft_DispWidth/2 + 150, 80, 27,OPT_RIGHTX|OPT_CENTERY,Str);  
53
54
_delay_ms(1);

Die MCP-Funktionen:
1
void mcp3551_init()
2
{
3
  _delay_ms(10);
4
  
5
  // Init:
6
   ConfigureCSPin();
7
  
8
  // Toggle CS one time to init MCP355x
9
  SelectMCP();
10
  _delay_ms(80);
11
  
12
  SPID.DATA = 0;
13
  while(!(SPID.STATUS & 0x80)); 
14
  SPID.DATA = 0;
15
  while(!(SPID.STATUS & 0x80)); 
16
  SPID.DATA = 0;
17
  while(!(SPID.STATUS & 0x80)); 
18
  
19
  DeselectMCP();
20
  _delay_ms(10);
21
}
22
23
void mcp3551_StosseMessungAn()
24
{  
25
  int32_t tmp;
26
  
27
  SelectMCP();  
28
  _delay_us(15);  
29
  
30
  // Wenn RDY auf Low, Messung abholen:
31
  if(IsMCPReady())
32
  {
33
    tmp = mcp3551_getData();
34
    _delay_us(15);
35
    
36
    mcp3551_StosseMessungAn();    
37
  }  
38
  
39
  DeselectMCP();  
40
  _delay_us(15);
41
}
42
43
int32_t mcp3551_getData()
44
{  
45
  // CS low
46
  SelectMCP();
47
  _delay_us(15);
48
  
49
  if(IsMCPReady())
50
  {
51
    // Wenn Messung fertig:  
52
    uint32_t LSByte=0;
53
    uint32_t MSByte=0;
54
    uint32_t HSByte=0;
55
    uint8_t is_neg = 0;  
56
57
    SPID.DATA = 0;
58
    while(!(SPID.STATUS & 0x80)); 
59
    HSByte=(uint32_t)SPID.DATA;
60
    SPID.DATA = 0;
61
    while(!(SPID.STATUS & 0x80)); 
62
    MSByte=(uint32_t)SPID.DATA;
63
    SPID.DATA = 0;
64
    while(!(SPID.STATUS & 0x80)); 
65
    LSByte=(uint32_t)SPID.DATA;    
66
    
67
    // CS high
68
    DeselectMCP();
69
    _delay_us(15);
70
    
71
    uint32_t data = LSByte;
72
    data |= (MSByte<<8);
73
  
74
    if(HSByte & 32)
75
      is_neg = 1;
76
    
77
    HSByte &= 0b00111111;    // Clear OV and DR
78
    data |= (HSByte<<16);
79
  
80
    // Check if sign bit is set
81
    if(is_neg)
82
    {    
83
      // Measure is negative
84
      int32_t ret = 0xFFE00000;
85
    
86
      ret |= data;
87
      return ret;
88
    }
89
    else
90
    {
91
      // Measure is positive
92
      return (int32_t)data;
93
    }    
94
  }
95
  
96
  // CS high
97
  DeselectMCP();
98
  _delay_us(15);
99
  
100
  return 0;
101
}
102
103
// Berechnung der PT100 Temperatur:
104
uint8_t BerechnePT100Temperatur(int16_t *Temperatur)
105
{
106
  int32_t Spannung;
107
  
108
  float Widerstand, delta;
109
  float Berechnung;
110
  float A = (float)3.9083 / pow(10,3);
111
  float B = (float)-5.775 / pow(10,7);
112
  float R0 = (float)100;
113
  
114
  Spannung = mcp3551_getData();
115
      
116
  if(Spannung <= (int32_t)0)
117
    return 0;    
118
  
119
  // Spannung über den Refferenzwiderstand:
120
   delta = (float)2097152 - (float)Spannung;
121
     
122
  // Widerstand berechnen:
123
  Widerstand = ((float)6800 / delta) * (float)Spannung;
124
  Widerstand *= 2;
125
  
126
  // Wenn Temperatur tiefer als -100 °
127
  if(Widerstand < 60)
128
    return 0;
129
  
130
  // Temperatur Polynomial berechnen:
131
  
132
   Berechnung = (sqrt(pow((R0*A),2)-(float)4*B*R0*(R0 - (float)Widerstand))-(A*R0)) / ((float)2*B*R0);
133
   
134
   *Temperatur = (int16_t)(Berechnung*(float)10);
135
  
136
  
137
  return 1;
138
}

Mit 10nF an V+ / V- hab ich jetzt bei einem 100 Ohm Widerstand (fest) 
als min 1.8 als max. 3.0. In diesem Bereich schwanken meine Messwerte.

Verwendet wird ein XMega128A3u mit 32 MHz getaktet (3V3).

von Manuel H. (manu77)


Lesenswert?

Selbst bei einer Referenz- und Versorgungsspannung (Nur MCP3551) von 
einer Knopfzelle kommt es zu diesen Messfehlern. Wähle ich den 
Referenzwiderstand auf 1k statt den 6k8, so grenzt sich der Fehler in 
der Temperatur auf .4 °C ein. Allerdings liegt dann der Messstrom höher 
(ca. 3 mA).

von Lurchi (Gast)


Lesenswert?

Mit welcher Sample Rate wird gemessen ?

Für den ersten Test sollte man sich die Werte des ADCs direkt ansehen, 
also ohne die Umrechnung in die Temperatur.

Beim Kondensator zwischen In+ und In- muss man ggf. aufpassen, 1-10 nF 
kommen mir zu wenig vor. Ein kleiner Kondensator kann zusätzliche Fehler 
verursachen. Wenn dann eher ein Kondensator im Bereich 220 nF - 1 µF.

Testweise könnte man es mal ohne die dauernde Abfrage ob der ADC fertig 
ist probieren, also einfach ein Delay, dass lang genug ist. Der I2C Bus 
könnte bei schlechtem Layout die Messung ggf. beeinflussen.

Ein Bild vom Layout wäre ggf. auch nicht schlecht.

von Yoschka (Gast)


Lesenswert?

Manuel H. schrieb:
> Selbst bei einer Referenz- und Versorgungsspannung (Nur MCP3551) von
> einer Knopfzelle kommt es zu diesen Messfehlern. Wähle ich den
> Referenzwiderstand auf 1k statt den 6k8, so grenzt sich der Fehler in
> der Temperatur auf .4 °C ein. Allerdings liegt dann der Messstrom höher
> (ca. 3 mA).


Da hast Du es.
Der Eingangswiderstand des ADW ist relativ klein.
Versuch mal 1µ und 10µ am VIN+ gegen VIN-.

von Manuel H. (manu77)


Angehängte Dateien:

Lesenswert?

Mit einem Delay habe ich bereits probiert: Ohne Erfolg. Anbei das 
Layout. Keine nennenswerte Signale in unmittelbarer Nähe.

Der ADC gibt Werte im Intervall [15128; 15208] als Rohdaten.

Die Samplerate liegt bei ca. 5 Samples/s. Variation bringt hier auch 
nichts.

von Manuel H. (manu77)


Lesenswert?

Yoschka schrieb:
> Manuel H. schrieb:
>> Selbst bei einer Referenz- und Versorgungsspannung (Nur MCP3551) von
>> einer Knopfzelle kommt es zu diesen Messfehlern. Wähle ich den
>> Referenzwiderstand auf 1k statt den 6k8, so grenzt sich der Fehler in
>> der Temperatur auf .4 °C ein. Allerdings liegt dann der Messstrom höher
>> (ca. 3 mA).
>
>
> Da hast Du es.
> Der Eingangswiderstand des ADW ist relativ klein.
> Versuch mal 1µ und 10µ am VIN+ gegen VIN-.

Bei zweimal 4.7 µF und einmal 1 µF immernoch Schwankungen von bis zu 0.8 
°C

von W.S. (Gast)


Lesenswert?

Manuel H. schrieb:
> SelectMCP();
>   _delay_ms(80);
>
>   SPID.DATA = 0;
>....
>   DeselectMCP();

Ich bin mir völlig sicher, daß du in deiner ADC-Bedienung den Fehler 
hast.
Also, mach das mal etwa so:
Beim Programmstart legst du einfach CS auf LOW und läßt es dort bis zum 
jüngsten Gericht. Der ADC wird nun im kontinuierlichen Modus messen und 
mit jedem Meßende sein Datenpin auf low legen, um dir anzuzeigen, daß es 
was abzuholen gibt. Dann holst du es ab und das Datenpin geht mit dem 
letzten Bit wieder auf High. Und so weiter...

Wenn du dem ADC andauernd auf den Schlips trittst mit deinem 
Selektieren, dann muß er jedesmal seine interne Queue wegschmeißen.

Versuch mal, so einen SigmaDelta-Wandler zu verstehen: Der hat nen 1-Bit 
Wandler, mit dem er die Eingangsspannung moduliert, daraus entsteht ein 
serieller Datenstrom, der dann passend tiefpaßgefiltert wird, um das 
Ergebnis zu liefern. Das ist ein recht kontinuierlicher Prozeß und geht 
eben NICHT so wie bei einem SAR-ADC.

W.S.

von Anja (Gast)


Lesenswert?

Hallo,

1% Widerstandsänderung sind 2.5 Grad Temperatur.
-> ich würde die Toleranz des 6.8K Widerstandes nochmal überdenken.

Gruß Anja

von Manuel H. (manu77)


Lesenswert?

Anja schrieb:
> Hallo,
>
> 1% Widerstandsänderung sind 2.5 Grad Temperatur.
> -> ich würde die Toleranz des 6.8K Widerstandes nochmal überdenken.
>
> Gruß Anja

Erklären sich dadurch die dynamischen Schwankungen? Das müsste doch nur 
in den R0, also Kategorie feste Toleranzen fallen.

von Anja (Gast)


Lesenswert?

Hallo,

80 Digits im Rohwert erklären sich dadurch nicht.
Im Datenblatt sind es "nur" ca 20.

Die 20 sind allerdings bei kurzgeschlossenem Eingang.
In Realität wird es bei realen Spannungen etwas mehr sein.

Aber es scheint so daß irgendwo im Aufbau (Masseverdrahtung 
sternförmig?) etwas faul ist.

Gruß Anja

von Manuel H. (manu77)


Lesenswert?

W.S. schrieb:
> Ich bin mir völlig sicher, daß du in deiner ADC-Bedienung den Fehler
> hast.

Habe verschiedene SPI-Modi und den Continuous Conversion Mode umgesetzt. 
Kein Erfolg. Die SCK-Leitung ging unter dem Chip lang. Gekappt und 
außerhalb verlegt. Kein Erfolg. Die Massefläche geht komplett außen 
herum. Das Einzige, was ich mir jetzt noch vorstellen könnte ist der 
Step-Up LED Treiber für den Touchscreen.

von 4b (Gast)


Lesenswert?

Hallo Manuel,

es gibt einen Punkt, welcher bei diesem ADC wichtig ist, und zwar das Du 
die Versorgung ordentlich Abblockst, am besten mit einem Pi-Filter. Bei 
mir
hat 10u 100nH 1R 3,3u 100n sehr gut geholfen. Du kannst auch die 
Referenz noch etwas abblocken, wobei Du damit das Ratiometrische Prinzip 
verletzt.

Gruß Johannes

von dunno.. (Gast)


Lesenswert?

Guck doch erstmal mit nem Scope, ob der ADC auch "sieht", was er dir 
sagt. Wenns signal schon doof ist, kanns ja am ende nicht schöner sein..
Wenn das signal aufm oskar gut aussieht, liegt der fehler beim adc, emv, 
weißdergeierwas.

von Manuel H. (manu77)


Lesenswert?

4b schrieb:
> hat 10u 100nH 1R 3,3u 100n sehr gut geholfen.

Wie meinst du das genau? Ein Pi-Filter ist doch nur eine Spule mit zwei 
Kondensatoren?

Wenn ich die Touchscreen Komponenten Software seitig ausschalte zappeln 
die Messwerte absolut nicht mehr!

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.