Try these files. From my working files.
.cpp
#include "Adafruit_CCS811.h"
bool Adafruit_CCS811::begin(uint8_t addr)
{
_i2caddr = addr;
_i2c_init();
SWReset();
delay(100);
//check that the HW id is correct
if(this->read8(CCS811_HW_ID) != CCS811_HW_ID_CODE)
return false;
//try to start the app
this->write(CCS811_BOOTLOADER_APP_START, NULL, 0);
delay(100);
//make sure there are no errors and we have entered application mode
if(checkError()) return false;
if(!_status.FW_MODE) return false;
disableInterrupt();
//default to read every second
setDriveMode(CCS811_DRIVE_MODE_1SEC);
return true;
}
void Adafruit_CCS811::setDriveMode(uint8_t mode)
{
_meas_mode.DRIVE_MODE = mode;
this->write8(CCS811_MEAS_MODE, _meas_mode.get());
}
void Adafruit_CCS811::enableInterrupt()
{
_meas_mode.INT_DATARDY = 1;
this->write8(CCS811_MEAS_MODE, _meas_mode.get());
}
void Adafruit_CCS811::disableInterrupt()
{
_meas_mode.INT_DATARDY = 0;
this->write8(CCS811_MEAS_MODE, _meas_mode.get());
}
bool Adafruit_CCS811::available()
{
_status.set(read8(CCS811_STATUS));
if(!_status.DATA_READY)
return false;
else return true;
}
uint8_t Adafruit_CCS811::readData()
{
if(!available())
return false;
else{
uint8_t buf[8];
this->read(CCS811_ALG_RESULT_DATA, buf, 8);
_eCO2 = ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]);
_TVOC = ((uint16_t)buf[2] << 8) | ((uint16_t)buf[3]);
if(_status.ERROR)
return buf[5];
else return 0;
}
}
void Adafruit_CCS811::setEnvironmentalData(uint8_t humidity, double temperature)
{
/* Humidity is stored as an unsigned 16 bits in 1/512%RH. The
default value is 50% = 0x64, 0x00. As an example 48.5%
humidity would be 0x61, 0x00.*/
/* Temperature is stored as an unsigned 16 bits integer in 1/512
degrees; there is an offset: 0 maps to -25�C. The default value is
25�C = 0x64, 0x00. As an example 23.5% temperature would be
0x61, 0x00.
The internal algorithm uses these values (or default values if
not set by the application) to compensate for changes in
relative humidity and ambient temperature.*/
uint8_t hum_perc = humidity << 1;
float fractional = modf(temperature, &temperature);
uint16_t temp_high = (((uint16_t)temperature + 25) << 9);
uint16_t temp_low = ((uint16_t)(fractional / 0.001953125) & 0x1FF);
uint16_t temp_conv = (temp_high | temp_low);
uint8_t buf[] = {hum_perc, 0x00,
(uint8_t)((temp_conv >> 8) & 0xFF), (uint8_t)(temp_conv & 0xFF)};
this->write(CCS811_ENV_DATA, buf, 4);
}
//calculate temperature based on the NTC register
double Adafruit_CCS811::calculateTemperature()
{
uint8_t buf[4];
this->read(CCS811_NTC, buf, 4);
uint32_t vref = ((uint32_t)buf[0] << 8) | buf[1];
uint32_t vntc = ((uint32_t)buf[2] << 8) | buf[3];
//from ams ccs811 app note
uint32_t rntc = vntc * CCS811_REF_RESISTOR / vref;
double ntc_temp;
ntc_temp = log((double)rntc / CCS811_REF_RESISTOR); // 1
ntc_temp /= 3380; // 2
ntc_temp += 1.0 / (25 + 273.15); // 3
ntc_temp = 1.0 / ntc_temp; // 4
ntc_temp -= 273.15; // 5
return ntc_temp - _tempOffset;
}
void Adafruit_CCS811::setThresholds(uint16_t low_med, uint16_t med_high, uint8_t hysteresis)
{
uint8_t buf[] = {(uint8_t)((low_med >> 8) & 0xF), (uint8_t)(low_med & 0xF),
(uint8_t)((med_high >> 8) & 0xF), (uint8_t)(med_high & 0xF), hysteresis};
this->write(CCS811_THRESHOLDS, buf, 5);
}
void Adafruit_CCS811::SWReset()
{
//reset sequence from the datasheet
uint8_t seq[] = {0x11, 0xE5, 0x72, 0x8A};
this->write(CCS811_SW_RESET, seq, 4);
}
bool Adafruit_CCS811::checkError()
{
_status.set(read8(CCS811_STATUS));
return _status.ERROR;
}
void Adafruit_CCS811::write8(byte reg, byte value)
{
this->write(reg, &value, 1);
}
uint8_t Adafruit_CCS811::read8(byte reg)
{
uint8_t ret;
this->read(reg, &ret, 1);
return ret;
}
void Adafruit_CCS811::_i2c_init()
{
Wire.begin();
}
void Adafruit_CCS811::read(uint8_t reg, uint8_t *buf, uint8_t num)
{
uint8_t value;
uint8_t pos = 0;
//on arduino we need to read in 32 byte chunks
while(pos < num){
uint8_t read_now = min(32, num - pos);
Wire.beginTransmission((uint8_t)_i2caddr);
Wire.write((uint8_t)reg + pos);
Wire.endTransmission();
Wire.requestFrom((uint8_t)_i2caddr, read_now);
for(int i=0; i<read_now; i++){
buf[pos] = Wire.read();
pos++;
}
}
}
void Adafruit_CCS811::write(uint8_t reg, uint8_t *buf, uint8_t num)
{
Wire.beginTransmission((uint8_t)_i2caddr);
Wire.write((uint8_t)reg);
Wire.write((uint8_t *)buf, num);
Wire.endTransmission();
}
.h
#ifndef LIB_ADAFRUIT_CCS811_H
#define LIB_ADAFRUIT_CCS811_H
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h>
/*=========================================================================
I2C ADDRESS/BITS
-----------------------------------------------------------------------*/
#define CCS811_ADDRESS (0x5A)
/*=========================================================================*/
/*=========================================================================
REGISTERS
-----------------------------------------------------------------------*/
enum
{
CCS811_STATUS = 0x00,
CCS811_MEAS_MODE = 0x01,
CCS811_ALG_RESULT_DATA = 0x02,
CCS811_RAW_DATA = 0x03,
CCS811_ENV_DATA = 0x05,
CCS811_NTC = 0x06,
CCS811_THRESHOLDS = 0x10,
CCS811_BASELINE = 0x11,
CCS811_HW_ID = 0x20,
CCS811_HW_VERSION = 0x21,
CCS811_FW_BOOT_VERSION = 0x23,
CCS811_FW_APP_VERSION = 0x24,
CCS811_ERROR_ID = 0xE0,
CCS811_SW_RESET = 0xFF,
};
//bootloader registers
enum
{
CCS811_BOOTLOADER_APP_ERASE = 0xF1,
CCS811_BOOTLOADER_APP_DATA = 0xF2,
CCS811_BOOTLOADER_APP_VERIFY = 0xF3,
CCS811_BOOTLOADER_APP_START = 0xF4
};
enum
{
CCS811_DRIVE_MODE_IDLE = 0x00,
CCS811_DRIVE_MODE_1SEC = 0x01,
CCS811_DRIVE_MODE_10SEC = 0x02,
CCS811_DRIVE_MODE_60SEC = 0x03,
CCS811_DRIVE_MODE_250MS = 0x04,
};
/*=========================================================================*/
#define CCS811_HW_ID_CODE 0x81
#define CCS811_REF_RESISTOR 100000
class Adafruit_CCS811 {
public:
//constructors
Adafruit_CCS811(void) {};
~Adafruit_CCS811(void) {};
bool begin(uint8_t addr = CCS811_ADDRESS);
void setEnvironmentalData(uint8_t humidity, double temperature);
//calculate temperature based on the NTC register
double calculateTemperature();
void setThresholds(uint16_t low_med, uint16_t med_high, uint8_t hysteresis = 50);
void SWReset();
void setDriveMode(uint8_t mode);
void enableInterrupt();
void disableInterrupt();
uint16_t getTVOC() { return _TVOC; }
uint16_t geteCO2() { return _eCO2; }
void setTempOffset(float offset) { _tempOffset = offset; }
//check if data is available to be read
bool available();
uint8_t readData();
bool checkError();
private:
uint8_t _i2caddr;
float _tempOffset;
uint16_t _TVOC;
uint16_t _eCO2;
void write8(byte reg, byte value);
void write16(byte reg, uint16_t value);
uint8_t read8(byte reg);
void read(uint8_t reg, uint8_t *buf, uint8_t num);
void write(uint8_t reg, uint8_t *buf, uint8_t num);
void _i2c_init();
/*=========================================================================
REGISTER BITFIELDS
-----------------------------------------------------------------------*/
// The status register
struct status {
/* 0: no error
* 1: error has occurred
*/
uint8_t ERROR: 1;
// reserved : 2
/* 0: no samples are ready
* 1: samples are ready
*/
uint8_t DATA_READY: 1;
uint8_t APP_VALID: 1;
// reserved : 2
/* 0: boot mode, new firmware can be loaded
* 1: application mode, can take measurements
*/
uint8_t FW_MODE: 1;
void set(uint8_t data){
ERROR = data & 0x01;
DATA_READY = (data >> 3) & 0x01;
APP_VALID = (data >> 4) & 0x01;
FW_MODE = (data >> 7) & 0x01;
}
};
status _status;
//measurement and conditions register
struct meas_mode {
// reserved : 2
/* 0: interrupt mode operates normally
* 1: Interrupt mode (if enabled) only asserts the nINT signal (driven low) if the new
ALG_RESULT_DATA crosses one of the thresholds set in the THRESHOLDS register
by more than the hysteresis value (also in the THRESHOLDS register)
*/
uint8_t INT_THRESH: 1;
/* 0: int disabled
* 1: The nINT signal is asserted (driven low) when a new sample is ready in
ALG_RESULT_DATA. The nINT signal will stop being driven low when
ALG_RESULT_DATA is read on the I²C interface.
*/
uint8_t INT_DATARDY: 1;
uint8_t DRIVE_MODE: 3;
uint8_t get(){
return (INT_THRESH << 2) | (INT_DATARDY << 3) | (DRIVE_MODE << 4);
}
};
meas_mode _meas_mode;
struct error_id {
/* The CCS811 received an I²C write request addressed to this station but with
invalid register address ID */
uint8_t WRITE_REG_INVALID: 1;
/* The CCS811 received an I²C read request to a mailbox ID that is invalid */
uint8_t READ_REG_INVALID: 1;
/* The CCS811 received an I²C request to write an unsupported mode to
MEAS_MODE */
uint8_t MEASMODE_INVALID: 1;
/* The sensor resistance measurement has reached or exceeded the maximum
range */
uint8_t MAX_RESISTANCE: 1;
/* The Heater current in the CCS811 is not in range */
uint8_t HEATER_FAULT: 1;
/* The Heater voltage is not being applied correctly */
uint8_t HEATER_SUPPLY: 1;
void set(uint8_t data){
WRITE_REG_INVALID = data & 0x01;
READ_REG_INVALID = (data & 0x02) >> 1;
MEASMODE_INVALID = (data & 0x04) >> 2;
MAX_RESISTANCE = (data & 0x08) >> 3;
HEATER_FAULT = (data & 0x10) >> 4;
HEATER_SUPPLY = (data & 0x20) >> 5;
}
};
error_id _error_id;
/*=========================================================================*/
};
#endif