CCS811 Gas Sensor

The CCS811 [1] is a digital gas sensor solution incorporating a metal oxide (MOX) gas sensor to detect a wide range of volatile organic compounds. It will work from 1.8 V to 3.6 V, so you need to add a regulator and logic-level conversion to run it on a 5 V board.

It's available on a breakout from Adafruit [2] (3.3V or 5 V) or a board called CJMCU-811 from AliExpress (3.3 V only):


It has an address input that allows you to select between two I2C addresses; the default address, with the ADDR input low, is 90 or #x5A. Note that to communicate with the board you need to hold the WAK pin low; the simplest approach is to connect it to GND.

Setting the sensor into app mode

The following routine app should be called after powering up the sensor to put it into app mode, ready to take measurements:

(defun app ()
  (with-i2c (s 90)
    (write-byte #xf4 s))) 

Setting the measurement mode

By default the sensor is in mode 0, idle mode. The following routine mde should be called to set the measurement mode; the parameter should be the mode number, 0 to 4:

(defun mde (m)
  (with-i2c (s 90)
    (write-byte #x01 s) ; MEAS_MODE
    (write-byte (ash m 4) s)))

For example, to set constant power mode with a measurement every second:

(mode 1)

See the datasheet for the meaning of the other modes.

Reading the algorithm results

The routine get returns a list of two measurements from the sensor:

  • The equivalent CO2 (eCO2) level, from 400ppm to 8192ppm. Values outside this range are clipped.
  • The Total Volatile Organic Compound (TVOC) level, from 0ppb to 1187ppb. Values outside this range are clipped.
(defun get ()
 (let (data)
   (with-i2c (s 90)
    (write-byte #x02 s) ; Results
    (restart-i2c s 5)
    (let ((co2 (logior (ash (read-byte s) 8) (read-byte s)))
          (voc (logior (ash (read-byte s) 8) (read-byte s))))
      (list co2 voc)))))

For example:

> (get)
(733 50)

To print a sample every second execute:

(loop (print (get)) (delay 1000))

If you try breathing on the sensor you should see the values increase.

Checking the sensor

The following routine chk is not normally necessary, but can be used to check the status of the sensor:

(defun chk ()
  (with-i2c (s 90)
    ; Check HW ID
    (write-byte #x20 s) ; HW_ID
    (restart-i2c s 1)  
    (unless (= (read-byte s) #x81) (print "Wrong HW_ID"))
    ; Check status
    (restart-i2c s)
    (write-byte #x00 s) ; STATUS
    (restart-i2c s 1)
    (let ((sta (read-byte s)))
      (when (zerop (logand sta #x80)) (print "Not in app mode"))
      (when (zerop (logand sta #x10)) (print "No valid app"))
      (when (zerop (logand sta #x08)) (print "No data ready")))))


Thanks to Martin Pennings's CCS811 GitHub repository [3].

  1. ^ CCS811 Datasheet on SparkFun.
  2. ^ Adafruit CCS811 Air Quality Sensor Breakout on Adafruit.
  3. ^ CCS811 on GitHub.