arduinoprojects

git clone https://git.tarina.org/arduinoprojects
Log | Files | Refs

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 }