Nabend Wir haben ein merkwürdiges Problem. Unser Messaufbau besteht aus DS18b20 Temperatursensoren, ATtiny84 und RFM12b Modulen. Jetzt haben wir festgestellt, dass Temperaturen über 32°C als negative Werte ausgegeben werden. Und es ist nicht einfach nur ein Minus vor dem Wert! An den Sensoren selbst kann es nicht liegen, denn wenn diese direkt am PC angeschlossen sind, messen sie ganz normal (bis 100°C getestet). Unser einziger Verdacht ist das es was mit der Anzahl der Stellen bei der Integer Variable zu tun hat. Gesendet werden die Werte ohne Kommata, d.h. 32000 sind 32,00°C. Und die Integerlänge bei 32Bit sind genau das doppelte. Sind wir auf der richtigen Spur, oder hat unsere Vermutung damit nix zu tun? Gruß Kolja
Kolja L. schrieb: > Unser einziger Verdacht ist das es was mit der Anzahl der Stellen bei > der Integer Variable zu tun hat. > Gesendet werden die Werte ohne Kommata, d.h. 32000 sind 32,00°C. 3 Nachkommastellen? Welchen Sinn soll das haben? > Und die Integerlänge bei 32Bit sind genau das doppelte. Kopfschüttel. 32 Bit für einen popeligen Temperaturwert, der sowieso nicht genauer als ein halbes Grad ist. Oder meintest du nicht eher 16 Bit? > oder hat unsere Vermutung damit nix zu tun? Code zeigen.
:
Bearbeitet durch User
Kolja L. schrieb: > 32000 sind 32,00°C. > Und die Integerlänge bei 32Bit sind genau das doppelte. 16bit wolltest Du sagen. Google mal nach dem Wertebereich von int16_t und wie da die negativen Werte dargestellt werden. Stell stattdessen alles auf int32_t um oder (besser) verzichte stattdessen einfach auf eine Nachkommastelle, wahrscheinlich kannst Du sogar auf 2 Nachkommastellen verzichten für ein gewöhnliches Außenthermometer, genauer wirds eh kaum sein. 32,0°C wären dann 320, das ist wahrscheinlich genau genug.
:
Bearbeitet durch User
http://www.forum-raspberrypi.de/Thread-ds18b20-negative-werte-nach-temperaturanstieg ... und da auch nur eine vage beschreibung....
Ich würde zu eurem Projekt einen Programmierer hinzuziehen wenn da Programmiertätigkeiten anfallen. Der findet den Fehler, dafür ist er da.
x-post schrieb: > http://www.forum-raspberrypi.de/Thread-ds18b20-negative-werte-nach-temperaturanstieg > > ... und da auch nur eine vage beschreibung.... Na ja. Es ist aber klar was hier passiert. Eine signed 16 Bit Berechnung läuft irgendwo über. Die einzige offene Frage lautet: wo im Code ist die bewusste Stelle? Ohne Code allerdings schwer zu raten. Mit Code eine Sache auf ein paar Minuten.
Ich bin zumindest kein Programmierer :-) Hier mal unser Code:
1 | //-------------------------------------------------------------------------------------- |
2 | // TempTX-tiny ATtiny84 Based Wireless Temperature Sensor Node |
3 | // By Nathan Chantrell http://nathan.chantrell.net |
4 | // Updated by Martin Harizanov (harizanov.com) to work with DS18B20 |
5 | // To use with DS18B20 instead of TMP36, a 4K7 resistor is needed between the Digital 9 and Digital 10 of the ATTiny (Vdd and DQ) |
6 | // To get this to compile follow carefully the discussion here: http://arduino.cc/forum/index.php?topic=91491.0 |
7 | // GNU GPL V3 |
8 | //-------------------------------------------------------------------------------------- |
9 | // modified by meigrafd @ 10.05.2014 |
10 | //------------------------------------------------------------------------------ |
11 | //#include <JeeLib.h> // https://github.com/jcw/jeelib |
12 | #include "pins_arduino.h" |
13 | #include <RFM12B.h> |
14 | #include <avr/sleep.h> |
15 | #include <OneWire.h> |
16 | #include <DallasTemperature.h> |
17 | //------------------------------------------------------------------------------ |
18 | #define NODEID 4 // RF12 node ID in the range 1-30 |
19 | #define NETWORKID 210 // RF12 Network group |
20 | #define FREQ RF12_433MHZ // Frequency of RFM12B module |
21 | #define GATEWAYID 22 // the node ID we're sending to |
22 | |
23 | #define ACK_TIME 2000 // Number of milliseconds to wait for an ack |
24 | #define SENDDELAY 30000 // wait this many ms between sending packets |
25 | #define requestACK true // request ACK? (true/false) |
26 | //------------------------------------------------------------------------------ |
27 | // PIN-Konfiguration |
28 | //------------------------------------------------------------------------------ |
29 | // SENSOR pins |
30 | #define ONE_WIRE_BUS 10 // DS18B20 Temperature sensor is connected on D10/ATtiny pin 13 |
31 | #define ONE_WIRE_POWER 9 // DS18B20 Power pin is connected on D9/ATtiny pin 12 |
32 | // LED pin |
33 | #define LEDpin 8 // D8, PA2 (ATtiny pin 11) - set to 0 to disable LED |
34 | //------------------------------------------------------------------------------ |
35 | /* |
36 | +-\/-+ |
37 | VCC 1| |14 GND |
38 | (D0) PB0 2| |13 AREF (D10) |
39 | (D1) PB1 3| |12 PA1 (D9) |
40 | RESET 4| |11 PA2 (D8) |
41 | INT0 PWM (D2) PB2 5| |10 PA3 (D7) |
42 | PWM (D3) PA7 6| |9 PA4 (D6) |
43 | PWM (D4) PA6 7| |8 PA5 (D5) PWM |
44 | +----+ |
45 | */ |
46 | |
47 | //encryption is OPTIONAL |
48 | //to enable encryption you will need to: |
49 | // - provide a 16-byte encryption KEY (same on all nodes that talk encrypted) |
50 | // - to call .Encrypt(KEY) to start encrypting |
51 | // - to stop encrypting call .Encrypt(NULL) |
52 | //#define KEY "ABCDABCDABCDABCD" |
53 | |
54 | //------------------------------------------------------------------------------ |
55 | |
56 | // Need an instance of the Radio Module |
57 | RFM12B radio; |
58 | |
59 | // Setup a oneWire instance to communicate with any OneWire devices |
60 | // (not just Maxim/Dallas temperature ICs) |
61 | OneWire oneWire(ONE_WIRE_BUS); |
62 | |
63 | // Pass our oneWire reference to Dallas Temperature. |
64 | DallasTemperature sensors(&oneWire); |
65 | |
66 | // Temperatur-String zum Versand per 433 Mhz |
67 | char msg[60]; |
68 | int nrOfDevices; |
69 | DeviceAddress tempDeviceAddress; |
70 | uint8_t* ids[10]; |
71 | //######################################################################################################################## |
72 | |
73 | static void activityLed (byte state, byte time = 0) { |
74 | if (LEDpin) { |
75 | pinMode(LEDpin, OUTPUT); |
76 | if (time == 0) { |
77 | digitalWrite(LEDpin, state); |
78 | } |
79 | else { |
80 | digitalWrite(LEDpin, state); |
81 | delay(time); |
82 | digitalWrite(LEDpin, !state); |
83 | } |
84 | } |
85 | } |
86 | |
87 | // blink led |
88 | static void blink (byte pin, byte n = 3) { |
89 | if (LEDpin) { |
90 | pinMode(pin, OUTPUT); |
91 | for (byte i = 0; i < 2 * n; ++i) { |
92 | delay(100); |
93 | digitalWrite(pin, !digitalRead(pin)); |
94 | } |
95 | } |
96 | } |
97 | |
98 | //-------------------------------------------------------------------------------------------------- |
99 | // Read current supply voltage |
100 | //-------------------------------------------------------------------------------------------------- |
101 | long readVcc() { |
102 | bitClear(PRR, PRADC); |
103 | ADCSRA |= bit(ADEN); // Enable the ADC |
104 | long result; |
105 | // Read 1.1V reference against Vcc |
106 | #if defined(__AVR_ATtiny84__) |
107 | ADMUX = _BV(MUX5) | _BV(MUX0); // For ATtiny84 |
108 | #else |
109 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega328 |
110 | #endif |
111 | delay(2); // Wait for Vref to settle |
112 | ADCSRA |= _BV(ADSC); // Convert |
113 | while (bit_is_set(ADCSRA,ADSC)); |
114 | result = ADCL; |
115 | result |= ADCH<<8; |
116 | result = 1126400L / result; // Back-calculate Vcc in mV |
117 | ADCSRA &= ~ bit(ADEN); |
118 | bitSet(PRR, PRADC); // Disable the ADC to save power |
119 | return result; |
120 | } |
121 | |
122 | void setup() { |
123 | |
124 | //setup light. Check if tiny works |
125 | if (LEDpin) {activityLed(1, 2500);} |
126 | |
127 | |
128 | pinMode(ONE_WIRE_POWER, OUTPUT); // set power pin for DS18B20 to output |
129 | digitalWrite(ONE_WIRE_POWER, HIGH); // turn DS18B20 sensor on |
130 | // |
131 | |
132 | // Start up the library |
133 | sensors.begin(); |
134 | |
135 | // Grab a count of devices on the wire |
136 | // nrOfDevices = sensors.getDeviceCount(); |
137 | nrOfDevices = 0; |
138 | |
139 | // Loop through each device, print out temperature data |
140 | for(int i=0; i<10; i++) |
141 | { |
142 | // Search the wire for address |
143 | if(sensors.getAddress(tempDeviceAddress, i)) |
144 | { |
145 | // ids[i] = tempDeviceAddress; |
146 | nrOfDevices++; |
147 | |
148 | //if (LEDpin) { |
149 | // blink(LEDpin, 1); |
150 | //} |
151 | } |
152 | |
153 | }//for |
154 | |
155 | |
156 | radio.Initialize(NODEID,FREQ,NETWORKID); // Initialize RFM12 with settings defined above |
157 | #ifdef KEY |
158 | radio.Encrypt((byte*)KEY); |
159 | #endif |
160 | radio.Control(0xC040); // Adjust low battery voltage to 2.2V |
161 | radio.Sleep(); // Put the RFM12 to sleep |
162 | |
163 | |
164 | PRR = bit(PRTIM1); // only keep timer 0 going |
165 | ADCSRA &= ~ bit(ADEN); |
166 | bitSet(PRR, PRADC); // Disable the ADC to save power |
167 | |
168 | |
169 | digitalWrite(ONE_WIRE_POWER, LOW); // turn Sensor off to save power |
170 | pinMode(ONE_WIRE_POWER, INPUT); // set power pin for Sensor to input before sleeping, saves power |
171 | |
172 | } |
173 | |
174 | void loop() { |
175 | |
176 | |
177 | int supplyV = readVcc(); // Get supply voltage |
178 | strcpy(msg,"v="); |
179 | itoa(supplyV,&msg[strlen(msg)],10); |
180 | |
181 | pinMode(ONE_WIRE_POWER, OUTPUT); // set power pin for DS18B20 to output |
182 | digitalWrite(ONE_WIRE_POWER, HIGH); // turn DS18B20 sensor on |
183 | |
184 | delay(50); // Allow 50ms for the sensor to be ready |
185 | |
186 | // Start up the library |
187 | sensors.begin(); |
188 | sensors.requestTemperatures(); // Send the command to get temperatures |
189 | |
190 | // Loop through each device, print out temperature data |
191 | |
192 | for(int i=0; i<nrOfDevices; i++) //nrOfDevices |
193 | { |
194 | // Search the wire for address |
195 | if(sensors.getAddress(tempDeviceAddress, i)) |
196 | { |
197 | |
198 | // float tempC = sensors.getTempC(tempDeviceAddress)*100; |
199 | int tempC = sensors.getTempCByIndex(i)*1000; |
200 | strcat(msg,"_"); |
201 | for (uint8_t a = 6; a < 8; a++){ |
202 | if (tempDeviceAddress[a] < 16) strcat(msg,"0");//Serial.print("0"); |
203 | itoa(tempDeviceAddress[a],&msg[strlen(msg)],16);//Serial.print(deviceAddress[i], HEX); |
204 | } |
205 | strcat(msg,"="); |
206 | itoa(tempC, &msg[strlen(msg)],10); |
207 | |
208 | } |
209 | //else strcat(msg,"ghost device!"); //Check your power requirements and cabli |
210 | } |
211 | |
212 | strcat(msg,"*"); |
213 | |
214 | digitalWrite(ONE_WIRE_POWER, LOW); // turn Sensor off to save power |
215 | pinMode(ONE_WIRE_POWER, INPUT); // set power pin for Sensor to input before sleeping, saves power |
216 | |
217 | // Send data via RF |
218 | radio.Wakeup(); |
219 | |
220 | radio.Send(GATEWAYID, (uint8_t *)msg, strlen(msg), requestACK); |
221 | radio.SendWait(2); //wait for RF to finish sending (2=standby mode) |
222 | radio.Sleep(); |
223 | |
224 | if (LEDpin) { |
225 | blink(LEDpin, 2); |
226 | } |
227 | |
228 | delay(SENDDELAY); |
229 | } |
Danke fürs Anschauen! Kolja
Karl Heinz schrieb: > Na ja. > Es ist aber klar was hier passiert. Eine signed 16 Bit Berechnung läuft > irgendwo über. > Die einzige offene Frage lautet: wo im Code ist die bewusste Stelle? des wegen ja "vage" - kein aufbau - kein code - d18b20 einfach so in wasser stecken... vielleicht wäre für den ts besser mal eine genaue projektbeschreibung zu veröffentlichen, statt hinz und kunz mit seiner vagen definition über foren (x+n) an zu triggern. ich mag so was nicht!
Bingo
1 | int tempC = sensors.getTempCByIndex(i)*1000; |
sobald die Temperatur 32.767 Grad übersteigt, ergibt das einen satten Überlauf. Lasst doch den Blödsinn mit 3 Nachkommastellen! Mindestens 2 davon sind doch sowieso gelogen! 1 Nachkommastelle, die dafür gerundet, reicht völlig für den Hausgebrauch. Denn ob diese 1 überhaupt irgendwas mit der Realität zu tun hat, steht mehr als nur in den Sternen. Der Hersteller gibt selber an, dass die Sensoren nicht genauer als +-0.5°C sind. Was ihr hier betreibt sind Taschenspielertricks. Vortäuschen einer höheren Genauigkeit.
:
Bearbeitet durch User
Hallo! Das sieht so aus, als wenn Du den float -Wert mit der Temperatur in einen int hineinschreibst; der ist nur 16 bit groß und damit bist Du bei Temperaturen > 32 Grad automatisch in den dann negativen Bereich gerutscht. mit uint32_t funktioniert es (ich habe ein ähnliches Modul hier laufen) VG Joachim
int Na also. Auf dem Arduino ist das nämlich, man höre und staune: 16bit! Auf dem Arm und dem x68 wäre er 32 Bit aber hier ist er eben nur 16 bit. Zielstrebig in die Falle getappt. wenn ihr 32 bit wollt dann nehmt explizit einen 32 bit Datentyp, nehmt int32_t und meidet diese mal-so-mal-so-weiis-nicht-genau-kommt-drauf-an typen wie int wie der Teufel das Weihwasser. nehmt von nun an nur noch diese hier: int32_t uint32_t int16_t uint16_t int8_t uint8_t und und lasst die Finger von dem eingebauten platformabhängigen C-Fossil int, das bringt nur Unglück. Nur Unglück. Finger weg davon.
:
Bearbeitet durch User
Ups, da war karl heinz mal wieder schneller..... Ansonsten pflichte ich ihm bei: Nachkommastellen höchstens in den Bereich der Meßgenauigkeit legen. Alles andere ist sinnfrei
Karl Heinz schrieb: > Lasst doch den Blödsinn mit 3 Nachkommastellen! Mindestens 2 davon sind > doch sowieso gelogen! Dann guck dir mal Temperaturverläufe an, die mit dem DS18B20 gemessen wurden. Die Auflösung des Sensor beträgt 1/16°C und die Standardabweichung des Rauschens der Rohdaten im Sensor liegt deutlich darunter. Da sind im Dezimalsystem zwei Nachkommastellen doch wohl angemessen, um die Daten zu übertragen. Bei Fixkommaübertragung bräuchte man allerdings nur vier "Nachkomma"-Bits.
Wolfgang A. schrieb: > Karl Heinz schrieb: >> Lasst doch den Blödsinn mit 3 Nachkommastellen! Mindestens 2 davon sind >> doch sowieso gelogen! > > Dann guck dir mal Temperaturverläufe an, die mit dem DS18B20 gemessen > wurden. Die Auflösung des Sensor beträgt 1/16°C Du kennst den Unterschied zwischen Auflösung und Genauigkeit? Der Hersteller gibt SELBST an, dass die Sensoren nicht genauer als plus minus ein HALBES GRAD sind! Auflösung hin oder her. Edit: zum mitmeisseln. Wenn dann am Display steht 23.458°C, dann könnten das auch 22.97° sein, wenn man mit einem geeichtem Präzisionsthermometer nachmisst. Es könnten aber auch 23.8° sein. Oder 23.95°. Oder irgendein anderer Wert dazwischen. Sehr sinnvoll, dann 3 Nachkommastellen auszugeben. Mal ganz davon abgesehen, das sich bezweifle, dass die Wassertemperatur am Ort des Sensors bis auf die 3. Nachkommstelle mit der Wassertemperatur 3 Zentimeter davon entfernt übereinstimmt.
:
Bearbeitet durch User
Heijeijei, was ist denn hier los:-) Danke erstmal für den Hinweis mit den 3 Nachkommastellen. Werds aber erst morgen ändern können. Zur Genauigkeit: Uns reicht locker ein halbes Grad. Eigentlich auch ein Grad. Aber weil die "Dinger" das können, haben wir die 3. Nachkommastelle bis in die Datenbank gerettet. Um dort zu runden <- ist Quatsch, wissen wir jetzt auch. Wir hatten die Sensoren aber auch schon bei uns im Uni-Labor im Kallibrator (Venus irgendwas..). Und aus der Messreihe wissen wir, wenn ein plausibler Wert übertragen wird (damals nur über Kabel an GPIO) ist der bis 80°C auf 0,5°C genau. Im Bereich bis 50°C sogar noch genauer. Wenn ich mal Zeit habe, kann ich ja nochmal ne Messreihe durchfahren lassen. Das Ergebnis poste ich dann hier. Ist aber nicht wirklich interessant, steht ja schon im Datenblatt. Gruß Kolja
Karl Heinz schrieb: > Du kennst den Unterschied zwischen Auflösung und Genauigkeit? Deswegen habe ich geschrieben Auflösung ;-) Ich habe hier genug von den DS18B20 für Differenzmessungen laufen. Nach eigener Kalibrierung ist es ziemlich egal, was der Hersteller als garantierte Genauigkeit über seinen Prozess angibt, solange die Sensoren stabil genug arbeiten, i.e. kalibrierfähig sind. > Mal ganz davon abgesehen, das sich bezweifle, dass die Wassertemperatur > am Ort des Sensors bis auf die 3. Nachkommstelle mit der > Wassertemperatur 3 Zentimeter davon entfernt übereinstimmt. Dann guck dir mal an, wie Temperatursensoren für die Ozeanographie kalibriert werden - und da sind mK gefragt. SBE verspricht für sein Kalibrierbad eine Homogenität auf 0.2mK
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.