CCS811 Air Quality Breakout Hookup Guide

Contributors: MTaylor
Favorited Favorite 3

Arduino Library and Usage

Getting the CCS811 Arduino Library

To get the Arduino library, download from GitHub or use the Arduino Library Manager.

Download the GitHub repository

Visit the GitHub repository to download the most recent version of the library, or click the button below:

Use the Library Manager or install in the Arduino IDE

For help installing the library, check out our Installing an Arduino Library tutorial.

If you don't end up using the manager, you'll need to move the SparkFun_CCS811_Arduino_Library folder into a libraries folder within your Arduino sketchbook. If you downloaded the zip, you can remove "master" from the name, but it's not required.

Using the Library

The library is fairly normal to use compared with our other sensors. You'll have to include the library, create a sensor object in the global space, and then use functions of that object to begin and control the sensor. With this one, pass the I2C address to the object during construction.

To get the library included, and to take care of all the gritty compiler stuff, place the following at the beginning of the sketch before void setup()

#include <SparkFunCCS811.h>

#define CCS811_ADDR 0x5B //Default I2C Address
//#define CCS811_ADDR 0x5A //Alternate I2C Address

CCS811 myCCS811(CCS811_ADDR);

Now, functions of the object named myCCS811 can be called to set up and get data, while all the wire stuff is kept under the hood.

To make the sensor get ready during program boot, myCCS811.begin() must be called. Here's an example of the minimal usage of begin.

Error Status: The .begin() returns a simple bool but the .beginWithStatus() function has a special feature: it returns the status of the function call! If there was a problem during begin, it will return a non-zero code indicating what happened. It's optional, and is described in the "Custom Types and Literals" section below.
void setup()

Then, in the main loop of the program, call sensor functions such as mySensor.readAlgorithmResults() to operate the sensor. The following snippet shows a simple check for data, to call on the sensor to calculate and get values, and to access those values. It doesn't do anything with the data, though! Check out the examples for fully functional code.

void loop()
  if (myCCS811.dataAvailable())
    int tempCO2 = myCCS811.getCO2();
    int tempVOC = myCCS811.gettVOC();
  else if (myCCS811.checkForStatusError())

  delay(1000); //Wait for next reading

Function Reference

The following functions exist for the CCS811 object.

Functions with scoped return type CCS811Core::status report an error state as defined in the literals section below. It is optional and can be used to determine success or failure of call.

  • bool begin( TwoWire = Wire ) --- Checks the ID register, checks for valid app data, starts the app, and establishes a drive mode.

  • CCS811Core::status beginWithStatus( TwoWire = Wire ) --- Checks the ID register, checks for valid app data, starts the app, and establishes a drive mode. Returns the status.

  • const char *CCS811::statusString(CCS811_Status_e stat) --- Returns a printable string of the status value.

  • CCS811Core::status readAlgorithmResults( void ) --- Call to cause the sensor to read its hardware and calculate TVOC and eCO2 levels.

  • bool checkForStatusError( void ) --- Returns true if there is an error pending. This checks the status register.

  • bool dataAvailable( void ) --- Returns true if a new sample is ready and hasn't been read.

  • bool appValid( void ) --- Returns true if there is a valid application within the internal CCS811 memory.

  • uint8_t getErrorRegister( void ) --- Returns the state of the ERROR_ID register.

  • uint16_t getBaseline( void ) --- Returns the baseline value.

  • CCS811Core::status setBaseline( uint16_t ) --- Apply a saved baseline to the CCS811.

  • CCS811Core::status enableInterrupts( void ) --- Enables the interrupt pin for data ready.

  • CCS811Core::status disableInterrupts( void ) --- Disables the interrupt pin.

  • CCS811Core::status setDriveMode( uint8_t mode ) --- Sets the drive mode (mode can be 0 through 4).

    • 0: Measurement off
    • 1: Measurement every 1 second
    • 2: Measurement every 10 seconds
    • 3: Measurement every 60 seconds
    • 4: Measurement every 0.25 seconds --- for use with external algorithms
  • CCS811Core::status setEnvironmentalData( float relativeHumidity, float temperature ) --- Sets the environmental conditions for compensation.

    • relativeHumidity in units of %, 0.00 through 100.0
    • temperature in degrees C, -25.0 through 50.0
  • void setRefResistance( float ) --- If you've changed the thermistor pull-up, call this to give the sensor the new resistor value. Otherwise, it will be 10000.

  • CCS811Core::status readNTC( void ) --- Cause the CCS811 to get and calculate a temperature from the thermistor input.

  • uint16_t getTVOC( void ) --- Collect the last calculated TVOC value, in parts per billion (ppb).

  • uint16_t getCO2( void ) --- Collect the last calculated eC02 value, in parts per million (ppm).

  • float getResistance( void ) --- Collect the last calculated resistance value of the NTC terminals.

  • float getTemperature( void ) --- Collect the last calculated temperature.

Custom Types and Literals

The CCS811 library defines the following special data type to deal with error states of functions. In most places the library can be used without paying attention to the function return types, but if they are needed, here are the values the data type status can hold:

// Return values 
typedef enum
} CCS811_Status_e;

To avoid the possibility of multiple libraries using the same status name, the enum is actually inside the scope of the CCS811 object, buried in the CCS811Core, which is the base class. Phew, don't worry about that too much; just place CCSCore:: before the status name when you want to use it, and use it like a regular enum (e.g., CCS811Core::CCS811_Status_e myLocalReturnStatus;). This just tells the compiler that the variable name is in a specific place. You'll also have to add the scope operator to the enum names.

Here's an example that shows how the status enum can be used:

CCS811Core::CCS811_Status_e returnCode = mySensor.beginCore();
Serial.print("beginCore exited with: ");
switch ( returnCode )
case CCS811Core::CCS811_Stat_SUCCESS:
case CCS811Core::CCS811_Stat_ID_ERROR:
case CCS811Core::CCS811_Stat_I2C_ERROR:
case CCS811Core::CCS811_Stat_INTERNAL_ERROR:
case CCS811Core::CCS811_Stat_GENERIC_ERROR:
  Serial.print("Unspecified error.");

The library also defines names for CCS811 registers, if you're using direct read and write functions. These are globally scoped and can be used anywhere.

//Register addresses
#define CSS811_STATUS 0x00
#define CSS811_MEAS_MODE 0x01
#define CSS811_ALG_RESULT_DATA 0x02
#define CSS811_RAW_DATA 0x03
#define CSS811_ENV_DATA 0x05
#define CSS811_NTC 0x06
#define CSS811_THRESHOLDS 0x10
#define CSS811_BASELINE 0x11
#define CSS811_HW_ID 0x20
#define CSS811_HW_VERSION 0x21
#define CSS811_FW_BOOT_VERSION 0x23
#define CSS811_FW_APP_VERSION 0x24
#define CSS811_ERROR_ID 0xE0
#define CSS811_APP_START 0xF4
#define CSS811_SW_RESET 0xFF