Temperature sensor

A good solution to measuring temperature from uLisp is the MCP9808 from Microchip [1]. It provides temperature to a typical accuracy of 0.25°C, and has an I2C interface so it's easy to interface to uLisp:

MCP9808b.jpg 

Three address lines allow you to configure up to eight sensors on the same bus. Although the device is in an MSOP-8 package, Adafruit have a breakout board that you can use to make it compatible with a standard breadboard [2].

The programs will happily run on any of the uLisp platforms, including the Arduino Uno.

Displaying the temperature

Here's a simple uLisp function get() to read the temperature from the chip, and print the temperature to the nearest eighth of a degree:

(defun get ()
  (with-i2c (str 31) 
    (write-byte 5 str)
    (restart-i2c str 2)
    (let* ((hi (read-byte str))
           (lo (read-byte str))
           (sgn (logand (ash hi -4) #x01))
           (deg (logior (ash (logand hi #x0f) 4) (ash (logand lo #xf0) -4)))
           (fra (ash (logand lo #x0f) -1)))
      (unless (zerop sgn) (princ #\-))
      (princ deg)
      (princ #\.)
      (princ (* fra 125)))
    nothing))

It assumes the address of the chip is 31, which is what you get if you tie the three address inputs high via a 10kΩ resistor. The routine selects the ambient temperature register, register 5, and then reads the two bytes into hi and lo. It then extracts the sign of the temperature, sgn, the whole number of degrees, deg, and the fractional degrees, fra. Finally it prints the temperature in a format such as:

24.375

Colour ambient temperature display

Finally, as an example of a simple application of the thermometer the following circuit changes the colour of an RGB LED from blue to red as the ambient temperature rises from 20°C to 35°C. I built it on a prototyping board mounted on an Arduino Uno ProtoShield:

MCP9808.jpg

The blue and red LEDs of the RGB LED are connected to the analogue outputs 10 and 11 respectively. You can see the colour change if you warm the MCP9808 with your finger:

(defvar blu 10)
(defvar red 11)

(defun led ()
  (loop
   (with-i2c (str 31) 
    (write-byte 5 str)
    (restart-i2c str 2)
    (let* ((hi (read-byte str))
           (lo (read-byte str))
           (deg (logior (ash (logand hi #x0f) 4) (ash (logand lo #xf0) -4)))
           (b (max (min (* (- 35 deg) 17) 255) 0))
           (r (max (min (* (- deg 20) 17) 255) 0)))
      (analogwrite blu b)
      (analogwrite red r)
      (delay 500)))))

Obviously this could be extended to provide a visual indication of any temperature measurement, using the full RGB LED for a wider range of colours.


  1. ^ MCP9808 datasheet on Microchip
  2. ^ SMT Breakout PCB for SOIC-8, MSOP-8 or TSSOP-8 on Adafruit.