Über den Beitrag
Im letzten Beitrag hatte ich den 24-Bit, 4-Kanal A/D-Wandler ADS1220 und meine zugehörige Bibliothek vorgestellt. In dieser Fortsetzung möchte ich euch anhand praktischer Beispiele zeigen, wie ihr den ADS1220 einsetzt, um seine Vorzüge zu nutzen.
Dabei orientiere ich mich an den Beispielen im Datenblatt. Um den Blick auf das Wesentliche zu lenken, habe ich die Schaltungen vereinfacht. Vor allem habe ich die vielen RC-Glieder weggelassen, die für Einsteiger etwas verwirrend sein können. Auch ohne sie habe ich ausgezeichnete Ergebnisse erzielt. Wenn ihr Rauschen und Störimpulse aber noch weiter reduzieren wollt, dann lohnt ein Blick in das Datenblatt.
Die folgende Anwendungen schauen wir uns an:
Thermoelement (Typ K) mit dem ADS1220 ansteuern
Wie funktioniert ein Thermoelement?
In aller Kürze: Thermoelemente bestehen aus zwei Drähten unterschiedlicher Metalle, die an einem ihrer Enden verbunden sind. Bei einer Temperaturdifferenz entlang der Leiter könnt ihr eine Spannung zwischen den freien Enden messen. Das ist der Seebeck-Effekt. Unterschiedliche Metallpaarungen haben unterschiedliche Temperatur-Spannungs-Kennlinien. Sie haben aber gemein, dass sie über einen weiten Bereich fast linear sind. Grundsätzlich ist der Effekt, also die Spannungsänderung pro Grad, ziemlich gering.
Ihr könnt im Netz an vielen Stellen Temperatur-Spannungstabellen für die unterschiedlichen Thermoelemente finden. Dabei ist die Bezugstemperatur grundsätzlich 0° C. Ein Nachteil der Thermoelemente ist, dass ihr nur Temperaturdifferenzen messen könnt. Die Temperatur an der Stelle, an der ihr die Spannung messt, muss bekannt sein.
Sehr weit verbreitet ist der Typ K, der aus der Paarung Nickel / Nickel-Chrom besteht. Bei ihm beträgt die Spannungsänderung ungefähr 40 Mikrovolt pro Grad, sprich ca. 4 Millivolt pro 100 °C. Das ist nicht wirklich viel. Und deshalb brauchen wir hier einen hochauflösenden, rauscharmen und mit hoher Verstärkung ausgestatteten A/D-Wandler. Also eine ideale Herausforderung für den ADS1220.
Die Schaltung am ADS1220
Wir erinnern uns (und falls nicht, dann schaut in den letzten Beitrag): Um den PGA, also den Verstärker des ADS1220, nutzen zu können, muss die Ausgangsspannung des PGA mindestens 200 Millivolt oberhalb von AVSS und maximal 200 Millivolt unterhalb von AVDD liegen. Ihr dürft also keine „single-ended“ Messungen gegen AVSS durchführen. Zumindest dann nicht, wenn ihr eine Verstärkung größer 4 anwenden wollt.
Idealerweise arbeitet ihr mit Eingangsspannungen, die in der Nähe von (AVSS+AVDD)/2 liegen. Das erreicht ihr mit der folgenden Schaltung:
Die zwei 10 Megaohm Widerstände zwingen die Spannung in den mittleren Bereich. Ihre Größe verhindert, dass größere Ströme über das Thermoelement fließen und das Ergebnis verfälschen. Das Datenblatt des ADS1220 empfiehlt Widerstandswerte zwischen 1 und 50 Megaohm.
Die 5 Volt Spannung sind willkürlich gewählt. Genauso könntet ihr mit 3.3 Volt arbeiten. Und anstelle der Eingänge AIN0 und AIN1 wären die anderen Eingänge gleichermaßen geeignet.
Hier noch einmal die Schaltung in der vollständigen Fritzing Version:
Fällt euch auf, dass hier 1 Megaohm Widerstände abgebildet sind? Der schlichte Grund ist, dass ich keine 10 Megaohm Widerstände bei Fritzing gefunden habe. Tatsächlich kamen aber 10 Megaohm Widerstände zum Einsatz.
Ausgleichsgeraden und -polynome für die Kennlinien
Im Folgenden werden wir Thermospannungen messen und daraus die Temperatur errechnen. Um das zu ermöglichen, habe ich die Thermospannung / Temperaturwerte für das Thermoelement K in Excel kopiert und daraus Ausgleichsfunktionen errechnet. Dabei habe ich mich auf den Bereich zwischen -20 und +110 °C beschränkt. Die Ausgleichsfunktionen sind nur für diesen Bereich gültig.
Wie ihr seht, ist der lineare Ansatz für diesen relativ kleinen Temperaturbereich schon nicht schlecht. Noch besser passt allerdings die quadratische Funktion rechts. Wenn ihr größere Temperaturbereiche abdecken wollt, dann solltet ihr mindestens mit einer quadratischen Funktion arbeiten. Ich spiele hier beides durch.
Linearer Ansatz
Der lineare Ansatz ist einfach. Ihr messt die Umgebungstemperatur mit dem internen Thermometer des ADS1220 oder einem anderen Temperatursensor. Aus der gemessenen Spannung errechnet der Sketch den Temperaturunterschied und addiert ihn zur Umgebungstemperatur.
Da die zu erwartenden Spannungen nur wenige Millivolt betragen, können wir bedenkenlos eine Verstärkung von 128 anwenden und die interne Spannungsreferenz (+/- 2.048 Volt) nutzen.
#include <ADS1220_WE.h> #include <SPI.h> #define ADS1220_CS_PIN 7 // chip select pin #define ADS1220_DRDY_PIN 6 // data ready pin ADS1220_WE ads = ADS1220_WE(ADS1220_CS_PIN, ADS1220_DRDY_PIN); void setup(){ Serial.begin(9600); if(!ads.init()){ Serial.println("ADS1220 is not connected!"); while(1); } ads.setCompareChannels(ADS1220_MUX_0_1); ads.setGain(ADS1220_GAIN_128); } void loop(){ float ambTemp = 0.0; float deltaTemp = 0.0; // thermocouple temperature minus ambient temperature float tCTemp = 0.0; // thermocouple temperature float tCV = 0.0; // thermocouple voltage ads.enableTemperatureSensor(true); ambTemp = ads.getTemperature(); ads.enableTemperatureSensor(false); Serial.print("Ambient Temperature [°C]: "); Serial.println(ambTemp); tCV = ads.getVoltage_muV(); // get result in millivolts deltaTemp = 0.0244821*tCV + 0.106873; Serial.print("Thermocouple T vs. ambient T [°C]: "); Serial.println(deltaTemp); tCTemp = ambTemp + deltaTemp; Serial.print("Thermocouple Temperature [°C]: "); Serial.println(tCTemp); Serial.println(); delay(2000); }
Für die folgende Ausgabe habe ich das Thermoelement in einen Becher mit warmem Wasser gesteckt. Man sieht schön, wie das Wasser abkühlt. Zur Überprüfung kam ein Vergleichsthermometer mit einer garantierten, maximalen Abweichung von 0.2 °C zum Einsatz. Davon wichen die mit dem Thermoelement ermittelten Werte nur um wenige zehntel Grad ab.
Polynom-Ansatz
Bei der Polynom Methode wird es ein wenig komplizierter, denn hier wir müssen berücksichtigen, dass die Kennlinie auf 0 °C bezogen ist. Wir messen die Umgebungstemperatur wieder mit dem ADS1220, aber errechnen daraus zunächst die auf 0 °C bezogene Thermospannung. Dazu brauchen wir ein weiteres Ausgleichspolynom mit vertauschten Achsen (x = Temperatur, y = Thermospannung). Das drucke ich hier nicht noch einmal ab. Diese errechnete Spannung (voltage correction „vC“) addieren wir zu der gemessenen Thermospannung und setzen das Ergebnis in das Ausgleichspolynom ein.
Hier der Sketch:
#include <ADS1220_WE.h> #include <SPI.h> #define ADS1220_CS_PIN 7 // chip select pin #define ADS1220_DRDY_PIN 6 // data ready pin ADS1220_WE ads = ADS1220_WE(ADS1220_CS_PIN, ADS1220_DRDY_PIN); void setup(){ Serial.begin(9600); if(!ads.init()){ Serial.println("ADS1220 is not connected!"); while(1); } ads.setCompareChannels(ADS1220_MUX_0_1); ads.setGain(ADS1220_GAIN_128); } void loop(){ float ambTemp = 0.0; float tCTemp = 0.0; // thermocouple temperature float tCV = 0.0; // thermocouple voltage float vC = 0.0; // voltage correction (deviation from 0°C) ads.enableTemperatureSensor(true); ambTemp = ads.getTemperature(); ads.enableTemperatureSensor(false); Serial.print("Ambient Temperature [°C]: "); Serial.println(ambTemp); vC = 1.16946*pow(ambTemp,2)*pow(10,-2) + 39.8013*ambTemp + 2.5078; Serial.print("Voltage Compensation [µV]: "); Serial.println(vC); tCV = ads.getVoltage_muV(); // get result in millivolts Serial.print("Thermocouple Voltage [µV]: "); Serial.println(tCV); tCV += vC; Serial.print("Corr. Thermocouple Voltage [µV]: "); Serial.println(tCV); tCTemp = -1.71627*pow(tCV,2)*pow(10,-7) + 2.51112*pow(10,-2)*tCV - 0.0664632; Serial.print("Thermocouple Temperature [°C]: "); Serial.println(tCTemp); Serial.println(); delay(2000); }
Und so sah die Ausgabe bei mir aus:
Dabei kam wieder ein Becher mit heißem Wasser zum Einsatz.
Widerstandsthermometer
Im Gegensatz zu den Thermoelementen, die eine temperaturabhängige Spannung liefern, ändern Widerstandsthermometer ihren Widerstand mit der Temperatur. Ihr Vorteil ist, dass ihr die Temperaturen absolut, d.h. ohne Vergleichstemperatur ermitteln könnt.
In der Familie der Widerstandsthermometer gibt es die NTCs und die RTDs. NTC steht für „Negative Temperature Coefficient Thermistor“. Das heißt, der Widerstand nimmt mit der Temperatur ab. Im Deutschen werden die NTCs auch als Heißleiter bezeichnet. NTCs zeichnen sich durch vergleichsweise hohe Widerstandswerte aus, da sie aus Metalloxiden bestehen.
RTD steht für „Resistance Temperature Detector“. Insofern würde man vermuten, dass ein NTC auch ein RTD ist. Allerdings werden üblicherweise nur diejenigen Thermometer als RTDs bezeichnet, deren Widerstand mit steigender Temperatur abnimmt. Dazu gehören die bekannten „PT100“ und „PT1000“. Man bezeichnet sie auch als PTCs oder Kaltleiter. Die Zahl steht dabei für den Widerstand bei 0 °C, und das „PT“ für das verwendete Material, nämlich Platin.
Nach dem Ohmschen Gesetz lässt sich der Widerstand über einen bekannten Strom ermitteln, den der ADS1220 liefern kann. Alternativ setzt ihr einen Vergleichswiderstand ein, den ihr mit dem Widerstandsthermometer in Reihe schaltet. Aber eins nach dem anderen.
NTCs (Heißleiter) mit dem ADS1220 ansteuern
Kennlinie des NTC
NTCs werden nach ihrem Widerstandswert bei 25 °C klassifiziert. Ich betrachte hier ein 10 kOhm Modell. Idealerweise geben die Hersteller den sogenannten B-Wert an, mit dem ihr den Widerstand R bei einer bestimmten Temperatur T gegenüber der Referenztemperatur Tref errechnen könnt:
Bei meinem 10 kΩ NTC war kein B-Wert aufgeführt, dafür aber eine Wertetabelle. Ich habe verschiedene Ausgleichsfunktionen in Excel ausprobiert. Für ein zufriedenstellendes Ergebnis musste ich den Wertebereich dreiteilen. Es gibt sicherlich bessere Mathematik-Programme, die passendere Funktionen implementiert haben. Aber auf Excel hat fast jeder Zugriff.
Messung mit dem ADS1220
Vorab: die hier beschriebene Methode ist nicht die genaueste. Ein paar Probemessungen zeigten aber Abweichungen, die deutlich unter einem Grad lagen. Außerdem ist die Methode simpel. Eine Fehlerbetrachtung folgt noch. Besser ist es, Referenzwiderstände einzusetzen. Das zeige ich am Beispiel der PTCs.
Zur Messung des temperaturabhängigen Widerstandes nutzen wir die IDAC Funktion des ADS1220. Mein betrachteter Messbereich beginnt bei 0 °C. Dort beträgt der Widerstand 32.69 Kiloohm. Mit einem Strom von 50 Mikroampere ergibt das eine Spannung von ~1.63 Volt. Das lässt sich noch gut mit der internen Referenz des ADS1220 messen und der Wert liegt noch deutlich unter der Grenze von AVDD – 0.9 Volt. Als Verstärkungsfaktor müssen wir 1 wählen.
Der niedrigste Widerstand beträgt ~0.5 Kiloohm. Bei einem IDAC von 50 Mikroampere beträgt die Spannung am NTC dann 25 Millivolt. Da der Verstärkungsfaktor 1 ist, wäre das auch die untere Grenze für die Ausgangsspannung des PGA. Das ist unterhalb der Grenze von AVSS + 200 Millivolt. Deshalb müssen wir den PGA abschalten.
Ich habe den folgenden, einfachen Aufbau verwendet:
Der Sketch dazu ist auch recht schlicht:
#include <ADS1220_WE.h> #include <SPI.h> #define ADS1220_CS_PIN 7 // chip select pin #define ADS1220_DRDY_PIN 6 // data ready pin ADS1220_WE ads = ADS1220_WE(ADS1220_CS_PIN, ADS1220_DRDY_PIN); void setup(){ Serial.begin(9600); if(!ads.init()){ Serial.println("ADS1220 is not connected!"); while(1); } ads.setCompareChannels(ADS1220_MUX_0_3); ads.setGain(ADS1220_GAIN_1); ads.bypassPGA(true); // true disables PGA, false enables PGA ads.setIdacCurrent(ADS1220_IDAC_50_MU_A); ads.setIdac1Routing(ADS1220_IDAC_AIN0_REFP1); } void loop(){ float result = 0.0; float resistanceInKiloOhm = 0.0; float temperature = 0.0; result = ads.getVoltage_mV(); // get result in millivolts Serial.print("Voltage [mV]: "); Serial.println(result,3); resistanceInKiloOhm = result / 50.0; Serial.print("Resistance [kOhm]: "); Serial.println(resistanceInKiloOhm,3); if(resistanceInKiloOhm > 9.0){ temperature = -21.41273 * log(resistanceInKiloOhm) + 74.34754; } else if(resistanceInKiloOhm > 2.2){ temperature = -25.75517 * log(resistanceInKiloOhm) + 83.366685; } else{ temperature = -31.55286 * log(resistanceInKiloOhm) + 87.9482; } Serial.print("Temperature [°C]: "); Serial.println(temperature); Serial.println(); delay(2000); }
Und so sah die Ausgabe aus:
Fehlerbetrachtung
Das Datenblatt gibt für den IDAC eine typische Abweichung von +/- 1 % an. Dieser Fehler wirkt sich direkt proportional auf den ermittelten Widerstandswert aus. Bei 25 °C liegt der Widerstand bei 10 kΩ. Was, wenn wir nur 9.9 kΩ ermitteln würden? Eingesetzt in die Ausgleichsfunktion ergäbe sich eine Temperatur von ~25.26 °C. Der Fehler ist kleiner, als vielleicht manch einer gedacht hätte. Hier kommt uns die nicht lineare Kennlinie entgegen.
Als maximale Abweichung des IDACs gibt das Datenblatt allerdings +/- 6 % an. Bei 9.4 kΩ betrüge die Temperatur 26.37 °C. Wie wahrscheinlich es jedoch ist, dass diese maximalen Abweichungen des IDACs tatsächlich auftreten, vermag ich nicht zu sagen.
Auch der Fehler der Referenzspannung geht direkt proportional ein. Das Datenblatt gibt 2.045 – 2.051 Volt als Spanne an. Das entspricht ungefähr +/- 0.15 %, ist also ein eher kleiner Fehler.
Hinzu kommt ein durch den Leitungswiderstand bedingter Fehler. Bei 25 °C (= 10 kΩ NTC-Widerstand) spielt das keine große Rolle. Bei 150 °C liegt der Widerstand allerdings nur noch bei 180 Ohm laut der Tabelle des Herstellers. Da kann eine längere Leitung das Ergebnis beeinflussen.
RTDs (Kaltleiter) mit dem ADS1220 ansteuern
PT1000
Der PT1000 hat ein fast lineare Kennlinie. Um die Widerstands-/Temperaturwerte aber noch besser zu treffen, habe ich eine quadratische Ausgleichskurve gewählt:
Direkte Messung mit dem ADS1220
Zunächst bin ich wie beim NTC vorgegangen. Das ist für PT1000 nicht wirklich zu empfehlen, aber ich möchte den Unterschied zeigen.
Für den von mir betrachteten Temperaturbereich ist der Widerstand des PT100 maximal ~1.5 kΩ. Deswegen können wir hier einen höheren IDAC Strom und eine höhere Verstärkung wählen. Der PGA muss aber weiterhin umgangen werden. Mit einem IDAC von 250 µA, einer Verstärkung von 4 und einem maximalen Widerstand von 1.5 kΩ ist die maximale Spannung (nach Verstärkung) 1.5 Volt, sodass die interne Referenz verwendet werden kann.
#include <ADS1220_WE.h> #include <SPI.h> #define ADS1220_CS_PIN 7 // chip select pin #define ADS1220_DRDY_PIN 6 // data ready pin ADS1220_WE ads = ADS1220_WE(ADS1220_CS_PIN, ADS1220_DRDY_PIN); void setup(){ Serial.begin(9600); if(!ads.init()){ Serial.println("ADS1220 is not connected!"); while(1); } ads.setCompareChannels(ADS1220_MUX_0_3); ads.setGain(ADS1220_GAIN_4); ads.bypassPGA(true); // true disables PGA, false enables PGA ads.setIdacCurrent(ADS1220_IDAC_250_MU_A); ads.setIdac1Routing(ADS1220_IDAC_AIN0_REFP1); } void loop(){ float result = 0.0; float resistanceInOhm = 0.0; float temperature = 0.0; float ambTemp = 0.0; ads.enableTemperatureSensor(true); ambTemp = ads.getTemperature(); ads.enableTemperatureSensor(false); Serial.print("Ambient Temperature [°C]: "); Serial.println(ambTemp); result = ads.getVoltage_mV(); // get result in millivolts Serial.print("Voltage [mV]: "); Serial.println(result,3); resistanceInOhm = result / 0.25; Serial.print("Resistance [kOhm]: "); Serial.println(resistanceInOhm); temperature = 1.01564*pow(10,-5)*pow(resistanceInOhm,2) + 0.235489*resistanceInOhm - 245.646; Serial.print("Temperature [°C]: "); Serial.println(temperature); Serial.println(); delay(2000); }
Und hier ist die Ausgabe. Ich habe zum Vergleich gegen den internen Temperatursensor des ADS1220 gemessen.
Fehlerbetrachtung
Durch die fast lineare Form der Kennlinie machen sich Fehler im IDAC erheblich stärker bemerkbar als beim NTC. Eine Abweichung von nur einem Prozent schlägt mit in einer Abweichung von 2.6 °C zu Buche. Vor diesem Hintergrund sind meine obigen Messwerte schon ziemlich gut.
Messung mit dem ADS1220 über einen Referenzwiderstand
Um die Abhängigkeit von Abweichungen des IDACs zu eliminieren, lassen wir den Strom nach Durchgang durch den RTD durch einen Referenzwiderstand fließen und nehmen diese Spannung als Referenzspannung:
Nach dem Ohmschen Gesetz gilt
Die Referenzspannung muss mindestens so groß wie die zu messende Spannung sein. Das heißt, dass der Referenzwiderstand mindestens so groß wie der größte Widerstand von RTD sein muss. Ich habe meine Schaltung für RTD-Widerstandswerte bis 1.5 kΩ ausgelegt und einen entsprechenden Widerstand gewählt. Eine Messung mit meinem Multimeter ergab einen Wert von 1.483 kΩ.
Bei einem IDAC von 1 mA und einem Gesamtwiderstand von ~3 kΩ ergibt sich eine maximale Spannung an AIN1 von 3 Volt. Wenn ihr eine Versorgungsspannung (AVDD) von 5 Volt verwendet, dann ist das weit unter dem Limit von AVDD minus 0.9 Volt. Verwendet ihr kleinere Versorgungsspannungen wie 3.3 Volt, dann müsst ihr den IDAC entsprechend reduzieren.
Im folgenden Sketch wird REFP0/REFN0 als Vergleichsspannung eingestellt. Der genaue Wert, den wir für die Vergleichsspannung angeben, spielt keine Rolle. Die ermittelte Spannung am RTD ist proportional zu dieser Festlegung. Und da wir die Spannungen zur Ermittlung von RRTD gemäß der obigen Gleichungen durcheinander teilen, wird der Faktor weg gekürzt. Wenn euch das verwirrt, dann könnt ihr alternativ mit den Rohdaten (getRawData()
) anstelle der Spannungen arbeiten.
Der PGA muss nicht umgangen werden, da wir uns nicht dem unteren Limit von AVSS plus 0.2 Volt nähern.
#include <ADS1220_WE.h> #include <SPI.h> #define ADS1220_CS_PIN 7 // chip select pin #define ADS1220_DRDY_PIN 6 // data ready pin #define VREF 2.0 // Reference Voltage, value does not matter ADS1220_WE ads = ADS1220_WE(ADS1220_CS_PIN, ADS1220_DRDY_PIN); void setup(){ Serial.begin(9600); if(!ads.init()){ Serial.println("ADS1220 is not connected!"); while(1); } ads.setCompareChannels(ADS1220_MUX_1_0); ads.setGain(ADS1220_GAIN_1); ads.setVRefSource(ADS1220_VREF_REFP0_REFN0); ads.setVRefValue_V(VREF); // exact value doesn't matter! ads.setIdacCurrent(ADS1220_IDAC_1000_MU_A); ads.setIdac1Routing(ADS1220_IDAC_AIN1); } // end of setup() void loop(){ float result = 0.0; float resistanceInOhm = 0.0; float temperature = 0.0; float ambTemp = 0.0; ads.enableTemperatureSensor(true); ambTemp = ads.getTemperature(); ads.enableTemperatureSensor(false); Serial.print("Ambient Temperature [°C]: "); Serial.println(ambTemp); ads.setCompareChannels(ADS1220_MUX_REFPX_REFNX_4); result = ads.getVoltage_mV(); Serial.print("Reference Voltage [mV]: "); Serial.println(result * 4.0); ads.setCompareChannels(ADS1220_MUX_1_0); result = ads.getVoltage_mV(); // get result in millivolts resistanceInOhm = result * 1.483 / VREF; Serial.print("Resistance [Ohm]: "); Serial.println(resistanceInOhm); temperature = 1.01564*pow(10,-5)*pow(resistanceInOhm,2) + 0.235489*resistanceInOhm - 245.646; Serial.print("Temperature [°C]: "); Serial.println(temperature); Serial.println(); delay(2000); }
Und so sah meine Ausgabe aus:
Die mit dem PT1000 ermittelten Temperaturen stimmen hervorragend mit denen des internen Thermometers („Ambient Temperature“) überein. Und beide wiederum wichen bei verschiedenen Messungen nicht mehr als zwei oder drei Zehntel von meinem guten Vergleichsthermometer ab.
Die Ausgabe der Referenzspannung dient übrigens nur zur Prüfung, ob die Dinge so funktionieren, wie berechnet. Der Wert geht nirgendwo ein. Theoretisch müsste die Referenzspannung 1.483 Volt betragen. Vielleicht kommt hier die typische 1 % Abweichung des IDAC zum Tragen. Außerdem ist die Messung der externen Referenz laut Datenblatt keine Präzisionsmessung.
PT100
Das Messprinzip: 3-Leiter und 4-Leiter
Der Widerstand des PT100 beträgt bei 0 °C lediglich 100 Ohm. Dadurch bedingt kommt hier anderer Fehler verstärkt zum Tragen, und zwar der Leitungswiderstand RLEAD. Um den Fehler zu kompensieren, gibt es 3-Leiter- oder 4-Leiter-PT100 (und PT1000!). Beim 3-Leiter-PT100 ist eine Zuleitungen doppelt ausgeführt. Beim 4-Leiter-PT100 sind hingegen beide Zuleitungen doppelt ausgeführt. Die doppelten Leitungen sind jeweils vor dem Sensor kurzgeschlossen. Durch geeignete Schaltungen lässt sich der Leitungseinfluss kompensieren.
3-Leiter-Schaltung
Für den 3-Leiter PT100 ist folgende Schaltung geeignet:
Um die Spannungen AIN1 und AIN0 zu errechnen, müssen wir nur die Ströme mit der Summe der Widerstände, durch die sie fließen, multiplizieren. Die Spannungsdifferenz zwischen AIN1 und AIN0 ist:
Da IDAC1 gleich IDAC2 ist und wir davon ausgehen, dass die Leitungswiderstände alle gleich sind, gilt nach dem Auflösen der Klammern:
Die Leitungswiderstände fallen damit weg.
Für die Referenzspannung gilt:
Teilt man die letzten beiden Gleichungen durcheinander und löst nach RPT100 auf, ergibt das die folgende, einfache Formel:
RREF ist bekannt, die Spannungen können wir messen, und für die Umrechnung von RPT100 in die Temperatur kam wieder ein Ausgleichspolynom zum Einsatz:
Als Referenz habe ich einen 2.4 kΩ Widerstand gewählt (exakt: 2.403 kΩ). IDAC1 und IDAC2 betrugen je 500 Mikroampere. Damit liegt die Referenzspannung bei ca. 2.4 Volt. In dem von mir betrachteten Temperaturbereich ist der PT100 Widerstand größer als 90 Ω und kleiner als 150 Ω. UAIN1-AIN0 liegt damit zwischen 90 Ω x 500 µA und 150 Ω x 500 µA, also zwischen 45 mV und 75 mV. Bei einem Gainfaktor von 32 sind die Grenzen der PGA-Ausgangsspannung damit 1.44 V und 2.4 V. Passt alles!
Sketch und Ausgabe
#include <ADS1220_WE.h> #include <SPI.h> #define ADS1220_CS_PIN 7 // chip select pin #define ADS1220_DRDY_PIN 6 // data ready pin #define VREF 2.0 // Reference Voltage, value does not matter ADS1220_WE ads = ADS1220_WE(ADS1220_CS_PIN, ADS1220_DRDY_PIN); void setup(){ Serial.begin(9600); if(!ads.init()){ Serial.println("ADS1220 is not connected!"); while(1); } ads.setCompareChannels(ADS1220_MUX_1_0); ads.setGain(ADS1220_GAIN_32); ads.setVRefSource(ADS1220_VREF_REFP0_REFN0); ads.setVRefValue_V(VREF); // value doesn't matter, the ratio is important ads.setIdacCurrent(ADS1220_IDAC_500_MU_A); ads.setIdac1Routing(ADS1220_IDAC_AIN1); ads.setIdac2Routing(ADS1220_IDAC_AIN0_REFP1); } // end of setup() void loop(){ float result = 0.0; float pt100ResistanceInOhm = 0.0; float leadResistanceInOhm = 0.0; float temperature = 0.0; float ambTemp = 0.0; ads.enableTemperatureSensor(true); ambTemp = ads.getTemperature(); ads.enableTemperatureSensor(false); Serial.print("Ambient Temperature [°C]: "); Serial.println(ambTemp); ads.setCompareChannels(ADS1220_MUX_REFPX_REFNX_4); result = ads.getVoltage_mV(); Serial.print("Reference Voltage [mV]: "); Serial.println(result * 4.0); ads.setCompareChannels(ADS1220_MUX_1_0); result = ads.getVoltage_mV(); // get result in millivolts pt100ResistanceInOhm = result * 2.0 * 2.403 / VREF; // Reference resistor: 2.403 kOhm Serial.print("Resistance PT100 [Ohm]: "); Serial.println(pt100ResistanceInOhm); temperature = 1.01898*pow(10,-3)*pow(pt100ResistanceInOhm,2) + 2.35443*pt100ResistanceInOhm - 245.633; Serial.print("Temperature [°C]: "); Serial.println(temperature); Serial.println(); delay(2000); }
Und hier noch die Ausgabe:
Die mit dem PT100 ermittelte Temperatur stimmte wieder gut mit den Messungen des internen Thermometers des ADS1220 („Ambient Temperature“) und meinem präzisen Vergleichsthermometer überein.
Auch hier ist die Referenzspannung wieder ein kleines bisschen höher als erwartet. Aber wie schon beim vorherigen Beispiel spielt das keine Rolle, sofern der Fehler IDAC-bedingt ist. Ich sollte aber noch erwähnen, dass IDAC1 und IDAC2 laut Datenblatt zwar bis zu 6 Prozent vom Soll abweichen können, die Differenz zwischen IDAC1 und IDAC2 beträgt aber maximal 0.3 Prozent. Erst das macht die Messung hinreichend genau.
Und noch ein Hinweis: Wenn ihr dieses Beispiel selbst ausprobiert, indem ihr alles auf dem Breadboard zusammensteckt und den PT100 mit Krokodilklemmen anschließt, dann seid euch bewusst, dass ihr damit eine ganze Reihe ungewollter Widerstände erzeugt. Wenn euer ermittelter PT100 Widerstand um ein Ohm abweicht, schlägt das mit drei Grad Temperaturabweichung zu Buche! Der PT1000 ist diesbezüglich wesentlich weniger empfindlich.
4-Leiter-Schaltung
Noch genauer sind 4-Leiter RTDs. Mit der folgenden Schaltung wird der Einfluss der Zuleitungen eliminiert:
Die Berechnung ist noch einfacher, da wir nur einen IDAC verwenden.
Bei 5 Volt Versorgungsspannung könntet ihr z.B. einen 4.7 kΩ Widerstand als RREF und 500 Mikroampere als IDAC wählen. Einen Sketch dazu müsstet ihr jetzt auch selbst erstellen können. Mangels eines 4-Leiter-PTCs habe ich die Schaltung nicht ausprobiert.
Wheatstone Brücken mit dem ADS1220
Als letztes Anwendungsbeispiel schauen wir uns Wheatstonesche Brückenschaltungen an. Diese nutzt man zur Bestimmung kleiner Widerstände bzw. kleiner Widerstandsdifferenzen, z.B. bei der Verwendung von Dehnungsmessstreifen. Vielleicht habt ihr schon damit gearbeitet, ohne es zu wissen. Viele Wägezellen basieren auf Wheatstone Brücken aus Dehnungsmessstreifen. Auf die Theorie gehe hier aber nicht weiter ein, denn das würde zu weit führen.
Die Schaltung ist denkbar einfach:
Die Versorgungsspannung der Brücke ist zugleich die Referenzspannung. Die Ausgangsspannung der Brücke messt ihr als Differenz zwischen zwei Eingängen des ADS1220. Das Coole daran ist, dass die Ausgangsspannung proportional zur Eingangsspannung und damit auch zur Referenzspannung ist. Schwankungen in der Versorgungsspannung spielen deshalb keine Rolle.
Und hier kommt jetzt auch der Low Side Switch zum Einsatz. Wenn ihr die Funktion aktiviert, dann schließt der Low Side Switch bei einer Messung. Ansonsten ist er offen und verhindert so, dass die Brücke unnötig Strom verbraucht.
Zum Testen habe ich mein Biegeblech mit Wheatstone Brücke aus dem Beitrag über Dehnungsmessstreifen wieder hervorgekramt:
Der zugehörige Sketch ist einfach:
#include <ADS1220_WE.h> #include <SPI.h> #define ADS1220_CS_PIN 7 // chip select pin #define ADS1220_DRDY_PIN 6 // data ready pin /* Create your ADS1220 object */ ADS1220_WE ads = ADS1220_WE(ADS1220_CS_PIN, ADS1220_DRDY_PIN); void setup() { Serial.begin(9600); if (!ads.init()) { Serial.println("ADS1220 is not connected!"); while (1); } ads.setCompareChannels(ADS1220_MUX_1_2); ads.setGain(ADS1220_GAIN_128); ads.setVRefSource(ADS1220_VREF_REFP1_REFN1); ads.setVRefValue_V(5.0); // The exact value doesn't matter! // ads.setRefp1Refn1AsVefAndCalibrate(); // That will not work here!! ads.setLowSidePowerSwitch(ADS1220_SWITCH); } void loop() { float result = 0.0; result = ads.getVoltage_mV(); // get result in millivolts Serial.print("Bridge Voltage [mV]: "); Serial.println(result, 3); delay(2000); }
Die Verstärkung kann in diesem Fall auf 128 eingestellt werden, da die Ausgangsspannung der Brücke nur wenige Millivolt beträgt. Der PGA muss nicht umgangen werden, da keine Gefahr droht, dass wir uns AVDD oder AVSS auf 200 Millivolt annähern.
So sah die Ausgabe aus, wenn ich das Biegeblech heruntergedrückt habe und es danach wieder entspannen ließ:
Ich habe mal versuchsweise die Brückenspannung auf von 5 Volt auf 3.3 Volt reduziert, ohne den Sketch zu ändern. Die Messwerte änderten sich nicht. Natürlich stimmen die ausgegebenen Spannungen dann nicht mehr. Aber das müssen sie auch nicht, da Werte für bestimmte Dehnungen bzw. (Gewichts-)Kräfte stehen. Und die sollen ja unabhängig von der Schwankungen der Brückenspannung sein.
Wenn euch das stört oder verwirrt, dann könnt ihr genauso gut mit den Rohwerten (über getRawData()
) anstelle der Spannungen arbeiten.