Showing posts with label DallasTemperature. Show all posts
Showing posts with label DallasTemperature. Show all posts

Tuesday, 23 April 2013

Temperature monitoring system V0.2

Here is version 0.2 of my Arduino project of Temperature Monitoring System.
It is based on a JY-MCU basic AVR board with ENC28J60 Ethernet interface and a 1-wire bus to provide a local web server with real time temperature readings of any number of 1-Wire thermometers. In addition, it can be configured to post the readings to COSM data feed.

This is running at my house for quite some time and is posting indoors and outdoors readings every 10 min to the following COSM feed: https://cosm.com/feeds/100389


The hardware description can be found in my other post.
To compile the project download the JY-MCU hardware profile for Arduino and the following libraries:

  1. EtherCard
  2. EEPROMex
  3. OneWire
  4. DallasTemperature
The code can be download from here: TempServer V0.2.ino

The server use DHCP to configure the TCP/IP stack and then start (led 7 remains on while setting up, then led 8 start to blink for normal operation).
The configuration link on the main page will bring up the COSM configuration page where you can configure the posting interval, the feed id and the COSM API key (to reset this configuration, hold switch 1 when the program starts).

In the next versions I am planning to enhance the following (not in a particular order):
  1. Enable to name each sensor for display in the list and for posting the date to COSM.
  2. Log up to 96 past readings in the device EEPROM (every 15 min for 24 hours).
  3. Show the min/max of the logged values.
  4. Show graph of the logged values.
  5. Use network time to make sure date logging and posting is done properly even when the device restarts frequently (currently, the posting of data is done after the device is constantly on for the selected posting time, that is, if the post of data is every 10 min, and the device restart every 7 min for some reason, no data will ever be posted).
  6. Improve the posting code to retry on HTTP errors (currently the code ignore the returned HTTP code and does not check for time out).
The main challenge to accomplish items 1 and 2 is the limitation of the EEPROM size (1KB), but with limiting the name to 15 characters and 10 bit per reading, I can support up to 10 devices on the bus.

Please let me know your thoughts (especially if you willing to give it go).

Friday, 22 February 2013

12bit Result From DS18S20

During my development using the DallasTemperature library to build my temperature web server I noticed that there is no API to get the 12 bit word value of the temperature reading and all you can get is a float value in Celsius or Fahrenheit.
Although most of the time it make sense to get a float value to render, a float value use 32 bit and will reduce the amount of readings I can store in RAM or EEPROM by half (or even more if I use 3 bytes to store two 12 bit values).

Getting the 12 bit value for DS12B20, DS1822 or DS1225 is simple, just combine byte 0 (Temp LSB) and byte 1 (Temp MSB) of the device scratch pad:

int rawTemperature = (((int)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];

However, for the DS18S20, this will return the 9 bit result, and there is additional formula you need to apply to get the 12 bit result as specified in the documentation:

Resolutions greater than 9 bits can be calculated using the data from the temperature, COUNT REMAIN and COUNT PER °C registers in the scratchpad. Note that the COUNT PER °C register is hard-wired to 16 (10h). After reading the scratchpad, the TEMP_READ value is obtained by truncating the 0.5°C bit (bit 0) from the temperature data (see Figure 2). The extended resolution temperature can then be calculated using the following equation:

TEMPERATURE = TEMP_READ - 0.25 +
              (COUNT_PER_C - COUNT_REMAIN)/COUNT_PER_C
This was implemented in the library with the following statement:

return (float)(rawTemperature >> 1) - 0.25 + ((float)(scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) / (float)scratchPad[COUNT_PER_C]);

Apart from the performance impact of floating point calculations (see this), the result is a float number, and not the 12 bit I am looking for.

Let's implement it with integers to calculate the 1/16 of the Celsius degree value, this is the integer result we get from any other device.
  1. Truncating the 0.5 bit - use a simple & mask: raw & 0xFFFE
  2. Convert to 12 bit value (1/16 of °C) - shift left: (raw & 0xFFFE)<<3
  3. Subtracting 0.25 (1/4 °C of 1/16) or 0.25/0.0625 = 4: ((raw & 0xFFFE)<<3)-4
  4. Add the count (count per c - count remain), count per c is constant of 16, and no need to dived by 16 since we are calculating to the 1/16 of °C: +16 - COUNT_REMAIN
Full expression:
((rawTemperature & 0xFFFE) << 3) - 4 + 16 - scratchPad[COUNT_REMAIN]
We can simplify it to:
((rawTemperature & 0xFFFE) << 3) + 12 - scratchPad[COUNT_REMAIN]
The next step is to extend the library with a getTemp function that returns the raw 12 bit temperature value no matter what device you use:

// Construct the integer value
int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];

// For DS18S20, use COUNT_REMAIN to calculate the 12 bit value
if (deviceAddress[0] == DS18S20MODEL) rawTemperature = ((rawTemperature & 0xFFFE) << 3) + 12 - scratchPad[COUNT_REMAIN];

// Retunr a 12 bit value
return rawTemperature; 

Then getTempC is nothing but division by 16:

return (float)getTemp() * 0.0625;

The actual code use static utility functions like rawToCelsius, that one can use to perform the conversion later on after storing the 12 bit raw value.

I will post the updated library later on after some QA.

UPDATE: This is now merged into the DallasTemperature library. Thank you Miles.