/* Beispielprogramm fuer einfache PT1000-Messung mit einem RP2040 pico. Zunächst die Schaltungsbeschreibung: Der zu messende PT1000-Widerstand liegt mit einem Ende an GND und mit dem anderen Anschluss am Eingang A0 (PT_IN_0). Vom Anschluss ADC_VREF (typ. 3,3 v) des RP204-pico-Boards geht ein Widerstand R_REF 1000 Ohm 0,1% ebenfalls an den Eingang A0. Der PT1000-Widerstand und der 1000 Ohm Widerstand bilden somit einen Spannungsteiler, der bei 0 Grad C die Spannung an AREF genau 1:2 teilt. Zum Programm: Das Programm macht 5 Messungen/s und gibt die ermittelte Temperatur in Grad C per UART1 (an GP0) mit 19200 Baud aus. Zur Vermeidung von Eigenerwaermung wird der PT1000 in den Messpausen spannungslos geschaltet (kurzgeschlossen), indem A0 auf Ausgang mit Pegel '0' geschaltet wird. Nach dem Freigeben von A0 wird die allererste Messung verworfen und erst mit der 2. Messung der Wert des Spannungsteilers verwendet. Mit steigender Temperatur erhoeht sich der PT1000 Widerstand im Bereich -20 bis +100 Grad C mit hier hinreichender Genauigkeit um den Faktor 0,00385. Die beiden Messungen dauern ca. 14 µs, was bei 5 Messungen/s eine Einschaltzeit von 70 µs/s ergibt. Durch dieses kleine Tastverhaeltnis wird dem PT1000 eine vernachlaessigbare Leistung von lediglich < 200 nW zugeführt. Aus dem gemessenen ADC_wert und R_REF wird der Widerstand PT_x ermittelt. Dabei verhalten sich PT_x/R_REF wie ADC_wert/(MAX_ADC-ADC_wert): PT_x = R_REF*ADC_WERT/(ADC_MAX-ADC_wert). Von PT_x muss noch der 0 Grad C Wert R_PT0 und ggf. auch der Zuleitungswiderstand R_ZULEITUNG abgezogen werden. Das ergibt die Abweichung des PT1000 zu 0 Grad C. Zuletzt wird die eff. Temperatur mit PT_FAKTOR errechnet; dieser Faktor ist schon mit R_PT0 (1000.0) skaliert und erledigt die korrekte Umrechnung. Messfehler: Die Aufloesung des ADC ist mit 12 Bit fuer diese Anwendung im Prinzip ausreichend hoch. Die Messwerte des ADCs sind aber mit undokumentierten Fehlern behaftet und R_REF hat mit 0,1% eine Genauigkeitsgrenze. Auf der anderen Seite ist diese Schaltung durch die ratiometrische Messung unabhaengig von einer genauen ADC_VREF. Was noch stört, ist der Offset des Nullpunktes vom ADC. Beim Testaufbau betrug er 16, weshalb die Messwerte und ADC_MAX entsprechend korrigiert werden. Indem man nur PT1000 bestueckt, wird A0 auf GNG gezogen und muß bei korrekt eingestelltem OFFSET einen Ausgangswert des ADC von 0 (+/- 1) ergeben. Zur UART1-Datenausgabe wird der Pegel an TxD1 (GP0) invertiert, sodaß das Ausgangssignal ohne RS232-Treiber einen RS232-USB-Wandler ansteuern kann. Soll auch RxD1 (GP1) verwendet werden, so sollte ein Schutzwiderstand von 3k3 - 10k in Reihe zum Eingang geschaltet werden. Wer es kann und mag, kann sich die Ausgabe auch auf USB umlenken. Fuer weitere Informationen zum PT1000 bietet sich folgende Quelle an: http://de.wikipedia.org/wiki/Platin-Messwiderstand http://www.mino-elektronik.de Alle Angaben ohne Gewaehr ! 2022-03-23 */ #define OFFSET 16 // 0-Offset des ADCs, ext. Messen notwendig #define DEF_BAUDRATE 19200 #define ADC_MAX (4095 - OFFSET) // bei 12 Bit #define PT_IN_0 26 // analog Eingang A0 #define UEBERLAUF 9999 // Fehler bei offenem Eingang #define R_PT0 1000.0 // bei 0 Grad C #define R_REF 1000.0 // ext. Widerstand mit 0,1% #define R_ZULEITUNG 0 // bei laengeren Leitungen unbedingt anpassen #define PT_FAKTOR 3.85 // schon mit 1000.0 skaliert #define IO_BANK0_BASE 0x40014000UL // ist auch schon in addressmap.h definiert #define GPIO0_CTRL (*(volatile unsigned int*)(IO_BANK0_BASE + 0x4u)) #define GPIO1_CTRL (*(volatile unsigned int*)(IO_BANK0_BASE + 0xcu)) #define IO_BANK0_GPIO0_CTRL_OUTOVER_Pos (8UL) /*!< OUTOVER (Bit 8) */ #define IO_BANK0_GPIO1_CTRL_INOVER_Pos (16UL) /*!< INOVER (Bit 16) */ int lese_PT1000(int ad_eingang) // liest den ADC-Eingang und rechnet auf Grad Celsius um { int ADC_wert, n; float temperatur, PT_x; pinMode(PT_IN_0, INPUT); // PT1000 freigeben analogRead(ad_eingang); // dummy ADC_wert = analogRead(ad_eingang); // und Kanal messen pinMode(PT_IN_0, OUTPUT); // PT1000 wieder kurzschließen ADC_wert -= OFFSET; // lokalen, korrigierten Wert testweise ausgeben Serial1.print("ADC: "); Serial1.print(ADC_wert); Serial1.print(" "); if(ADC_wert < ADC_MAX) { // nur gueltige Werte auswerten PT_x = R_REF * ADC_wert / (ADC_MAX-ADC_wert); // Widerstand ausrechnen PT_x = PT_x - R_PT0 - R_ZULEITUNG; // Offset fuer 0 Grad abziehen temperatur = PT_x / PT_FAKTOR; // und auf Grad C skalieren } else temperatur = UEBERLAUF; // falls PT1000-Zuleitung offen return temperatur; } void setup() { Serial1.begin(DEF_BAUDRATE); analogReadResolution(12); // beide Signale TxD1 und RxD1 invertieren GPIO0_CTRL |= (1 << IO_BANK0_GPIO0_CTRL_OUTOVER_Pos); // UART1-Ausgang invertieren GPIO1_CTRL |= (1 << IO_BANK0_GPIO1_CTRL_INOVER_Pos); // UART1-Eingang invertieren } void loop(void) { do { delay(200); // 0,2 Sekunden warten Serial1.print(lese_PT1000(PT_IN_0)); // per UART ausgeben Serial1.println(" \xb0""C"); // Grad-Celsius } while(1); // bis auf Weiteres }