MCP3551 Delta-Sigma-ADC Ungenau

OP #4101504
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
Angehängte Dateien:
Gast #4101539
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
OP #4101628
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).
Gast #4101784
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.
Gast #4101815
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-.
OP #4101836
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
Gast #4101891
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.
Gast #4102519
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
OP #4102830
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.
Gast #4102847
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
Gast #4102856
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.

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