Forum: Mikrocontroller und Digitale Elektronik keine Temp. über 32°C per Funk


von Kolja L. (kolja82)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von Bernd K. (prof7bit)


Lesenswert?

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
von x-post (Gast)


Lesenswert?


von Bernd K. (prof7bit)


Lesenswert?

Ich würde zu eurem Projekt einen Programmierer hinzuziehen wenn da 
Programmiertätigkeiten anfallen. Der findet den Fehler, dafür ist er da.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Kolja L. (kolja82)


Lesenswert?

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

von x-post (Gast)


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

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
von Joachim K. (joko)


Lesenswert?

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

von Bernd K. (prof7bit)


Lesenswert?

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
von Joachim K. (joko)


Lesenswert?

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

von Wolfgang A. (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von Peter X. (peter_x)


Lesenswert?


von Kolja L. (kolja82)


Lesenswert?

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

von Wolfgang A. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.