App Notes

Download zip archive

Key Ideas 

  • Using the temperature sensor on the Kiwi Multi-Sensor.
  • Using a OneWire device.
  • Writing a driver.

Description

 This app note uses the temperature sensor on Samraksh's Kiwi Multi-Sensor to sense temperature. 

Compatibility

.NOW 1.0, eMote version 4.3.0.9+.

Complexity Level

Intermediate 

Setup

Connect the Kiwi Multi-Sensor to a .NOW as follows:

Kiwi   .NOW
Pin Desc Number   Pin Desc Number
Temp J2/4   GPIO J11/3
Other Power J2/9   GPIO J11/4
Gnd J2/11   Ground J12/10
Vin J2/12   VOut J11/1

For more details, see the product pinouts & connection maps documentation. Connect the .NOW to your PC in the usual way and run the program. You can monitor output using MFDeploy. See the FAQ for more information.

Discussion

The Kiwi includes a temperature sensor that is connected via the OneWire interface, a simple, low-speed way to connect to peripherial devices. In this app note we discuss how to write a driver to sense temperature data. You can use these ideas to implement your own OneWire device.

In the app note's Utility folder you'll find the TemperatureSensor class. The Kiwi currently uses a Maxim DS18S20 temperature sensor component but the class also accomodates the DS18B20 sensor. Although OneWire is a bus so that there could potentially be several devices on it, the class is designed for the case that there is exactly one of the two Maxim devices. See http://www.maximintegrated.com/datasheet/index.mvp/id/2815 and http://www.maximintegrated.com/datasheet/index.mvp/id/2812 for datasheets.

When the class loads, it calculates the IsLittleEndian value for the processor. Some processors store binary values as in order from low to high and some from high to low and this makes a difference in how byte data is combined into other types such as integers. See http://en.wikipedia.org/wiki/Endianness for a discussion.

The constructor for the class takes GPIO pin designation as the argument and throws an exception if NONE is specified. Given the pin specified, it uses the OneWire class to find all the devices. This returns an array of byte arrays, one entry per device found. If there are no devices or if there are more than one, it throws an exception. Next it checks the first (and only) entry and gets the device family code as the first byte in the entry. If it is neither of the supported temperature sensors, it throws an exception. Otherwise, the constructor completes normally.

The main method in the class is Sense, which takes a boolean as an argument to indicate whether the CRC8 of sensed data should be checked or not. As you'll see when you run the app note, this adds about 77% additional processing time. Sensing the temperature is a multi-step process. See http://www.maximintegrated.com/app-notes/index.mvp/id/27 for a discussion of CRC8.

  1. Initiate conversion. This uses the OneWire class to send a Touch Reset command to make sure the sensor is in an initial state. This is followed by a Skip ROM, which indicates that we want to hear from all devices on the OneWire bus. In this case, there is only one, so it's safe to use it. Finally, the ConvertT command begins the sensing and conversion. 

  2. Wait for 750 ms. The sensor needs some time to do the sensing and load up the internal scratch pad registers with the result.

  3. Set up to read the scratch pad registers. This follows the same sequence as the first except that the Read Scratch Pad command is used.

Now we're ready to begin reading the results. The scratch pad has 8 registers. We can read all 8 and afterwards make one more read to get the CRC8. If the Sense method's argument is true, then we begin to do this. We use the OneWire ReadByte method to get the next byte from the scratch pad and do this iteratively until we've read all 8. As we do so, we calculate the CRC8, XORing the CRC8 value so far with the last byte read and indexing on a table to get the new CRC8 value. The CRC8 calculation is fairly complex and implementing it directly in C# would be prohibitive in terms of processing time, so we use a table instead. At the end, we make the 9th read and compare the CRC8 calculated by the sensor with the value we've calculated. If they differ, the method throws an exception.

If we are skipping the CRC8 check, we just read the first two values from the scratch pad. In either case, the first two scratch pad values give us the low and high-order bytes respectively of the 16 bit temperature value. 

The TemperatureBytes array is assigned values depending on whether the processor is big or little endian, and is then converted to a double. After this, we adjust for precision. The DS18B20 records temperature in 1/16 of a degree Celsius whereas the DS18S20 records it in 1/2 of a degree. It's possible to get better precision from the DS18S20, but the class here does not implement it. Finally, the result is assigned to the temperature value, after which it can be read in Celsius or Farenheit.

There are three other methods.

  1. TemperatureC gets the value in Celsius. Note the use of locking; this is to prevent corruption of the value in the event that one thread is executing Sense while another thread is executing TemperatureC.

  2. TemperatureF gets the value in Farenheit.

  3. SensorDelay gets the delay value used between the ConverT and ReadScratchPad. It's provided so we can tell how much actual CPU time was used by the Sense method.

When the app note is run, it periodically senses the temperature twice: once with a CRC8 check and another time without. Here are typical results:

Skip CRC: 11.81200000000001184 ms required; 24.00000000000000000C / 75.20000000000000284F

Check CRC: 20.96280000000001568 ms required; 24.00000000000000000C / 75.20000000000000284F

Skipping saves 9.15080000000000382 ms

Hence including CRC8 check adds about 9 ms of CPU time, about 77% more. If your application can tolerate the risk of mis-reading data from the sensor, then eliminating will make your application more efficient.

Suggestions

The TemperatureSensor class includes a Thread.Sleep between the ConvertT and the ReadScratchPad commands. This blocks the calling thread. Try implementing a SenseAsync method that returns immediately after the ConvertT is sent, and let the user subscribe to a SenseCompleted event that is raised after the delay. This way the user program can do other things while waiting for the sensing data to be ready.