phatduinoa personal home automation technology arduino





Temperature sensor

Purpose: Measuring temperature inside and outside

Characteristics: Originally the idea of implementing temperature sensors was the early thought of automating my room climate using electronic window openers and thermostates. Unfortunately the Phatduino does not provide any heat controlling components yet - I had enough work installing the light control components so far.

Nevertheless I had a great time experimenting with different kinds of temperature sensors. I started with a usual LM35 that I got to know by practicing with tutorials of ladyada.net. After a long testing phase I figured out that this sensor was inappropriate to work over long distances. Because it was an analog sensor it worked similar to a resistor changing its resistance dependent on temperature. Due to the long connecting wires (approx. 5 mts, just like the ones of the light sensor) its precision suffered a lot. Despite of that those copper wires change their resistance slightly as their temperature changes, what leads to the problem that a measurement of the outside temperature would also be influenced by the room temperature if the connecting wires are placed inside a room, like in my case. Concerning the experiments I conducted with the LM35 I have to say that only 25% of the measurements seemed to be accurate with a long cable (I faced differences of more than 15 K between two consecutive measurements), but more than 95% seemed to be correct with a short cable.

So I had to go for digital and kept my eyes open for a more precise, digital sensor. Finally I found the Dallas Semiconductor DS18B20 (now placed inside) and DS18S20 (placed outside) that I wanted to try in my project. The difference between those two is the development generation: The DS18B20 calculates much faster (93 ms) than the DS18S20 (750 ms). (Source see here.)

This is how the two temperature sensors should be connected.

They turned out to be a perfect solution to fit in my existing wire network because both Arduino and the sensors were capable of a "1-Wire-Technology" combining power supply and communication channel in one wire so that there would only be two wires (one ground and one for power/communication) needed for two (or even more) sensors.

I got the Arduino code for the sensors at many different forums and adjusted it to my needs. Unfortunately I cannot say that I am satisfied with the implementation of the two sensors (one outside, one inside) because of the following reasons:

  • The measurements do not always come to a good end, sometimes the sensors send a "Not yet finished" message to the Arduino what leads me to the assumption that the software does not give the sensors enough time to let them finish their measurement. I do not want to change this since I implemented a method that checks whether the temperatures received from the sensors have a reasonable value. The method is quite a compromise: Phatduino will not accept 85.00 °C and -1.25 °C as reasonable temperatures. I really do not see this as a problem: Hopefully my environment will never have a temperature of 85.00 °C! (And -1.25 °C will never be an important threshold value for a heater system as well.)
  • The hex code received by Arduino does not seem to be interpreted correctly: The temperature of the outside sensor is always a bit high. I also noticed that the square steel the sensors are placed in (see hardware section) heats up as it is exposured to sun and therefore the sensor heats up as well - certainly an unwanted side effect in outside temperature measurement.

The code

In order to get the following code working you have to make following declarations:

  // Temperature sensor
    
    OneWire  ds(temperaturePin); 
    float ftemp, tempp, ftempb;
    int Whole, Fract, SignBit;
    // Hex-adresses of temperature sensors
    byte outside[8]  = {0x10, 0x0B, 0xD2, 0xED, 0x01, 0x08, 0x00, 0xD7};  
    byte inside[8] = {0x28, 0x23, 0x65, 0xCA, 0x01, 0x00, 0x00, 0xBB};

In order for the DS18B20 (placed outside) to work you have to call prepare_temp(outside) from loop() each time you want to make a measurement.

void prepare_temp(byte* addr){
  byte present = 0;
  byte i;
  byte data[12];
  
  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);
}

This is the function get_temp() for reading the DS18S20:

// Get temperature outside

float get_temp(byte* addr)
{
  byte present = 0;
  byte i;
  byte data[12];
  
  // No preparation needed here as we already told the sensor we would measure
¬ temperature before in prepare_temp()
     present = ds.reset();   ds.select(addr);   ds.write(0xBE); // Read Scratchpad     for ( i = 0; i < 9; i++) { // we need 9 bytes       data[i] = ds.read();     }      int temp;   temp = data[0];                                    // load all 8 bits of the LSB          if (data[1] > 0x80){ // sign bit set, temp is negative       temp = !temp + 1;                                // two's complement adjustment       temp = temp * -1;                                // flip value negative.     }    int cpc; // get hi-rez data    int cr = data[6];    cpc = data[7];         if (cpc == 0)       return -1000;    temp = temp >> 1;                                  // Truncate by dropping bit zero for
¬ hi-rez formula
   ftemp = temp - (float)0.25 + (cpc - cr)/(float)cpc;                                                       // end hi-rez data    float ftempn;        if(ftemp != 85.00 && ftemp != -1.25){ // Simply filters corrupt values       ftempn = ftemp;       ftempb = ftemp;    }else{      ftempn = ftempb;    }       return ftempn; }

Here you will find the code for the DS18B20, placed inside the room:

// Get temperature inside

void get_tempS(byte* addr)
{
  int HighByte, LowByte, TReading, Tc_100, Whole_measured, Fract_measured;
      
  byte present = 0;
  byte i;
  byte data[12];
  
  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);                                 // start conversion, with
¬ parasite power on at the end
      delay(750); // maybe 750ms is enough, maybe not      present = ds.reset();   ds.select(addr);   ds.write(0xBE);      for ( i = 0; i < 9; i++) { // we need 9 bytes     data[i] = ds.read();   }      LowByte = data[0];   HighByte = data[1];   TReading = (HighByte << 8) + LowByte;   SignBit = TReading & 0x8000;                      // test most sig bit   if (SignBit) // negative   {     TReading = (TReading ^ 0xffff) + 1;             // 2's comp   }   Tc_100 = (6 * TReading) + TReading / 4;           // multiply by (100 * 0.0625) or 6.25   Whole_measured = Tc_100 / 100;                             // separate off the whole and
¬ fractional portions
  Fract_measured = Tc_100 % 100;       if(Whole_measured != 0 && Fract_measured != 6){ // Simply filters corrupt values     Whole = Whole_measured;     Fract = Fract_measured;    }    }