Adafruit_CCS811.cpp (9987B)
1 #include "Adafruit_CCS811.h" 2 3 /**************************************************************************/ 4 /*! 5 @brief Setups the I2C interface and hardware and checks for communication. 6 @param addr Optional I2C address the sensor can be found on. Default is 7 0x5A 8 @returns True if device is set up, false on any failure 9 */ 10 /**************************************************************************/ 11 bool Adafruit_CCS811::begin(uint8_t addr) { 12 _i2caddr = addr; 13 14 _i2c_init(); 15 16 SWReset(); 17 delay(100); 18 19 // check that the HW id is correct 20 if (this->read8(CCS811_HW_ID) != CCS811_HW_ID_CODE) 21 return false; 22 23 // try to start the app 24 this->write(CCS811_BOOTLOADER_APP_START, NULL, 0); 25 delay(100); 26 27 // make sure there are no errors and we have entered application mode 28 if (checkError()) 29 return false; 30 if (!_status.FW_MODE) 31 return false; 32 33 disableInterrupt(); 34 35 // default to read every second 36 setDriveMode(CCS811_DRIVE_MODE_1SEC); 37 38 return true; 39 } 40 41 /**************************************************************************/ 42 /*! 43 @brief sample rate of the sensor. 44 @param mode one of CCS811_DRIVE_MODE_IDLE, CCS811_DRIVE_MODE_1SEC, 45 CCS811_DRIVE_MODE_10SEC, CCS811_DRIVE_MODE_60SEC, CCS811_DRIVE_MODE_250MS. 46 */ 47 void Adafruit_CCS811::setDriveMode(uint8_t mode) { 48 _meas_mode.DRIVE_MODE = mode; 49 this->write8(CCS811_MEAS_MODE, _meas_mode.get()); 50 } 51 52 /**************************************************************************/ 53 /*! 54 @brief enable the data ready interrupt pin on the device. 55 */ 56 /**************************************************************************/ 57 void Adafruit_CCS811::enableInterrupt() { 58 _meas_mode.INT_DATARDY = 1; 59 this->write8(CCS811_MEAS_MODE, _meas_mode.get()); 60 } 61 62 /**************************************************************************/ 63 /*! 64 @brief disable the data ready interrupt pin on the device 65 */ 66 /**************************************************************************/ 67 void Adafruit_CCS811::disableInterrupt() { 68 _meas_mode.INT_DATARDY = 0; 69 this->write8(CCS811_MEAS_MODE, _meas_mode.get()); 70 } 71 72 /**************************************************************************/ 73 /*! 74 @brief checks if data is available to be read. 75 @returns True if data is ready, false otherwise. 76 */ 77 /**************************************************************************/ 78 bool Adafruit_CCS811::available() { 79 _status.set(read8(CCS811_STATUS)); 80 if (!_status.DATA_READY) 81 return false; 82 else 83 return true; 84 } 85 86 /**************************************************************************/ 87 /*! 88 @brief read and store the sensor data. This data can be accessed with 89 getTVOC(), geteCO2(), getCurrentSelected() and getRawADCreading() 90 @returns 0 if no error, error code otherwise. 91 */ 92 /**************************************************************************/ 93 uint8_t Adafruit_CCS811::readData() { 94 if (!available()) 95 return false; 96 else { 97 uint8_t buf[8]; 98 this->read(CCS811_ALG_RESULT_DATA, buf, 8); 99 100 _eCO2 = ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); 101 _TVOC = ((uint16_t)buf[2] << 8) | ((uint16_t)buf[3]); 102 _currentSelected = ((uint16_t)buf[6] >> 2); 103 _rawADCreading = ((uint16_t)(buf[6] & 3) << 8) | ((uint16_t)buf[7]); 104 105 if (_status.ERROR) 106 return buf[5]; 107 108 else 109 return 0; 110 } 111 } 112 113 /**************************************************************************/ 114 /*! 115 @brief set the humidity and temperature compensation for the sensor. 116 @param humidity the humidity data as a percentage. For 55.5% humidity, pass 117 in 55.5 118 @param temperature the temperature in degrees C as a decimal number. 119 For 25.5 degrees C, pass in 25.5 120 */ 121 /**************************************************************************/ 122 void Adafruit_CCS811::setEnvironmentalData(float humidity, float temperature) { 123 /* Humidity is stored as an unsigned 16 bits in 1/512%RH. The 124 default value is 50% = 0x64, 0x00. As an example 48.5% 125 humidity would be 0x61, 0x00.*/ 126 127 /* Temperature is stored as an unsigned 16 bits integer in 1/512 128 degrees; there is an offset: 0 maps to -25°C. The default value is 129 25°C = 0x64, 0x00. As an example 23.5% temperature would be 130 0x61, 0x00. 131 The internal algorithm uses these values (or default values if 132 not set by the application) to compensate for changes in 133 relative humidity and ambient temperature.*/ 134 135 uint16_t hum_conv = humidity * 512.0f + 0.5f; 136 uint16_t temp_conv = (temperature + 25.0f) * 512.0f + 0.5f; 137 138 uint8_t buf[] = { 139 (uint8_t)((hum_conv >> 8) & 0xFF), (uint8_t)(hum_conv & 0xFF), 140 (uint8_t)((temp_conv >> 8) & 0xFF), (uint8_t)(temp_conv & 0xFF)}; 141 142 this->write(CCS811_ENV_DATA, buf, 4); 143 } 144 145 /**************************************************************************/ 146 /*! 147 @brief get the current baseline from the sensor. 148 @returns the baseline as 16 bit integer. This value is not human readable. 149 */ 150 /**************************************************************************/ 151 uint16_t Adafruit_CCS811::getBaseline() { 152 /* baseline is not in a human readable format, the two bytes are assembled 153 to an uint16_t for easy handling/passing around */ 154 155 uint8_t buf[2]; 156 157 this->read(CCS811_BASELINE, buf, 2); 158 159 return ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); 160 } 161 162 /**************************************************************************/ 163 /*! 164 @brief set the baseline for the sensor. 165 @param baseline the baseline to be set. Has to be a value retrieved by 166 getBaseline(). 167 */ 168 /**************************************************************************/ 169 void Adafruit_CCS811::setBaseline(uint16_t baseline) { 170 /* baseline is not in a human readable format, byte ordering matches 171 getBaseline() */ 172 173 uint8_t buf[] = {(uint8_t)((baseline >> 8) & 0xFF), 174 (uint8_t)(baseline & 0xFF)}; 175 176 this->write(CCS811_BASELINE, buf, 2); 177 } 178 179 /**************************************************************************/ 180 /*! 181 @deprecated hardware support removed by vendor 182 @brief calculate the temperature using the onboard NTC resistor. 183 @returns temperature as a double. 184 */ 185 /**************************************************************************/ 186 double Adafruit_CCS811::calculateTemperature() { 187 uint8_t buf[4]; 188 this->read(CCS811_NTC, buf, 4); 189 190 uint32_t vref = ((uint32_t)buf[0] << 8) | buf[1]; 191 uint32_t vntc = ((uint32_t)buf[2] << 8) | buf[3]; 192 193 // from ams ccs811 app note 194 uint32_t rntc = vntc * CCS811_REF_RESISTOR / vref; 195 196 double ntc_temp; 197 ntc_temp = log((double)rntc / CCS811_REF_RESISTOR); // 1 198 ntc_temp /= 3380; // 2 199 ntc_temp += 1.0 / (25 + 273.15); // 3 200 ntc_temp = 1.0 / ntc_temp; // 4 201 ntc_temp -= 273.15; // 5 202 return ntc_temp - _tempOffset; 203 } 204 205 /**************************************************************************/ 206 /*! 207 @brief set interrupt thresholds 208 @param low_med the level below which an interrupt will be triggered. 209 @param med_high the level above which the interrupt will ge triggered. 210 @param hysteresis optional histeresis level. Defaults to 50 211 */ 212 /**************************************************************************/ 213 void Adafruit_CCS811::setThresholds(uint16_t low_med, uint16_t med_high, 214 uint8_t hysteresis) { 215 uint8_t buf[] = {(uint8_t)((low_med >> 8) & 0xF), (uint8_t)(low_med & 0xF), 216 (uint8_t)((med_high >> 8) & 0xF), (uint8_t)(med_high & 0xF), 217 hysteresis}; 218 219 this->write(CCS811_THRESHOLDS, buf, 5); 220 } 221 222 /**************************************************************************/ 223 /*! 224 @brief trigger a software reset of the device 225 */ 226 /**************************************************************************/ 227 void Adafruit_CCS811::SWReset() { 228 // reset sequence from the datasheet 229 uint8_t seq[] = {0x11, 0xE5, 0x72, 0x8A}; 230 this->write(CCS811_SW_RESET, seq, 4); 231 } 232 233 /**************************************************************************/ 234 /*! 235 @brief read the status register and store any errors. 236 @returns the error bits from the status register of the device. 237 */ 238 /**************************************************************************/ 239 bool Adafruit_CCS811::checkError() { 240 _status.set(read8(CCS811_STATUS)); 241 return _status.ERROR; 242 } 243 244 /**************************************************************************/ 245 /*! 246 @brief write one byte of data to the specified register 247 @param reg the register to write to 248 @param value the value to write 249 */ 250 /**************************************************************************/ 251 void Adafruit_CCS811::write8(byte reg, byte value) { 252 this->write(reg, &value, 1); 253 } 254 255 /**************************************************************************/ 256 /*! 257 @brief read one byte of data from the specified register 258 @param reg the register to read 259 @returns one byte of register data 260 */ 261 /**************************************************************************/ 262 uint8_t Adafruit_CCS811::read8(byte reg) { 263 uint8_t ret; 264 this->read(reg, &ret, 1); 265 266 return ret; 267 } 268 269 void Adafruit_CCS811::_i2c_init() { 270 Wire.begin(); 271 #ifdef ESP8266 272 Wire.setClockStretchLimit(500); 273 #endif 274 } 275 276 void Adafruit_CCS811::read(uint8_t reg, uint8_t *buf, uint8_t num) { 277 uint8_t pos = 0; 278 279 // on arduino we need to read in 32 byte chunks 280 while (pos < num) { 281 282 uint8_t read_now = min((uint8_t)32, (uint8_t)(num - pos)); 283 Wire.beginTransmission((uint8_t)_i2caddr); 284 Wire.write((uint8_t)reg + pos); 285 Wire.endTransmission(); 286 Wire.requestFrom((uint8_t)_i2caddr, read_now); 287 288 for (int i = 0; i < read_now; i++) { 289 buf[pos] = Wire.read(); 290 pos++; 291 } 292 } 293 } 294 295 void Adafruit_CCS811::write(uint8_t reg, uint8_t *buf, uint8_t num) { 296 Wire.beginTransmission((uint8_t)_i2caddr); 297 Wire.write((uint8_t)reg); 298 Wire.write((uint8_t *)buf, num); 299 Wire.endTransmission(); 300 }