Collection of uLisp functions to interface to popular sensors


I’m proposing to start a collection of uLisp programs to interface to a selection of popular sensors. They would be listed on the uLisp site.

I’m hoping to include: temperature sensors, accelerometers, pressure sensors, light sensors, and magnetometers.

Please post any code you’d like to contribute to this thread.

Please also suggest any specific sensors that you would like to see included.


MCP9808 Temperature Sensor

Here to get the ball rolling is a routine to return the temperature as a floating-point number from a Microchip MCP9808 I2C temperature sensor:

(defun mcp9809 ()
  (with-i2c (str 31) 
    (write-byte 5 str)
    (restart-i2c str 2)
    (let* ((hi (read-byte str))
           (lo (read-byte str))
           (tmp (+ (* (logand hi #x0f) 16) (/ lo 16))))
      (if (= (logand hi #x10) #x10) (- 256 tmp) tmp))))

The temperature is returned to an accuracy of 0.0625°C, and it can read between -40°C and 125°C. It assumes the default I2C address, 31, which you get by tying all the address lines high.

A breakout is available from Adafruit:

MCP9808 High Accuracy I2C Temperature Sensor Breakout Board


I think this is a very good idea.
I have some DS1631 and SHT11 i2c temperature sensors lying around (and I’m sure I’ll find others sensors too ;-) ), I will try to write a ulisp function to read it (should be rather similar to your mcp9809 example).
As a (u)lisp novice I think this is a real-world task that shouldn’t be too complicated to do…


HMC5883L Triple-Axis Magnetometer

Here’s a function to read the HMC5883L Triple-Axis Magnetometer:

(defun hmc5883 ()
  (let (yzx)
    (with-i2c (str 30) 
      (write-byte 2 str)
      (write-byte 1 str)
      (restart-i2c str 6)
      (dotimes (i 3)
        (push (logior (ash (read-byte str) 8) (read-byte str)) yzx)))

It returns a list of the values for the three axes, (y z x).

Although Adafruit and Sparkfun have discontinued their HMC5883L breakout boards, there are several Chinese boards available on eBay:


Si7021 Temperature and Humidity Sensor

Here are uLisp functions to reset and read temperature and relative humidity from an I2C Si7021 temperature/humidity sensor:

(defun si7021-reset ()
  (with-i2c (s #x40)
    (write-byte #xFE s))
  (delay 50)
(defun si7021-temperature ()
  (with-i2c (s #x40)
    (write-byte #xF3 s))
  (delay 25)
  (with-i2c (s #x40 3)
    (let* ((hi (read-byte s))
           (lo (read-byte s))
           (ckecksum (read-byte s))
           (raw-temp (float (logior (ash hi 8) (logand lo #xFF)))))
      (- (/ (* raw-temp 175.72) 65536.0) 46.85))))
(defun si7021-humidity ()
  (with-i2c (s #x40)
    (write-byte #xF5 s))
  (delay 25)
  (with-i2c (s #x40 3)
    (let* ((hi (read-byte s))
           (lo (read-byte s))
           (ckecksum (read-byte s))
           (raw-temp (float (logior (ash hi 8) (logand lo #xFF)))))
      (- (/ (* raw-temp 125.0) 65536.0) 6.0))))

Thanks to Dave Astels for permission to reproduce these from his article about uLisp on the Adafruit site.

An Si7021 Temperature and Humidity Sensor breakout board is available from Adafruit:


Adafruit Si7021 Temperature & Humidity Sensor Breakout Board


SHT31-D Temperature and Humidity Sensor

Here is a uLisp function to read the temperature and relative humidity from an I2C SHT31-D sensor which provides an accuracy of ±2% RH and ± 0.3°C:

(defun sht31-temp-humid ()
  (let ((rdword 
         (lambda (s)
           (logior (ash (read-byte s) 8) (read-byte s)))))
    ; High repeatability mode
    (with-i2c (s #x44)
      (write-byte #x24 s)
      (write-byte #x00 s)
      (delay 20)
      (restart-i2c s 5)
      (let* ((temp (rdword s))
             (checksum (read-byte s))
             (humid (rdword s)))
       (- (/ (* temp 175) 65535) 45)
       (/ (* humid 100) 65535))))))

It returns the values as a list of two floating-point numbers. For example:

>  (sht31-temp-humid)
(20.132 38.1659)

The last two lines of the routine could probably be rewritten to return 16-bit fixed-point values, to make it compatible with 16-bit uLisp platforms.

The sensor also incorporates a heater, to combat condensation. Here’s a routine to enable or disable the heater:

(defun sht31-heater (on)
  (with-i2c (s #x44)
    (write-byte #x30 s)
    (write-byte (if on #x6D #x66) s)))

An SHT31-D Temperature and Humidity Sensor breakout board is available from Adafruit:


Adafruit Sensirion SHT31-D Temperature & Humidity Sensor Breakout