├── .gitignore ├── LICENSE.md ├── README.md ├── examples ├── Example1_BasicReadings │ └── Example1_BasicReadings.ino ├── Example2_BME280Compensation │ └── Example2_BME280Compensation.ino ├── Example3_ThermistorCompensation │ └── Example3_ThermistorCompensation.ino ├── Example4_SetBaseline │ └── Example4_SetBaseline.ino ├── Example5_WakeAndInterrupt │ └── Example5_WakeAndInterrupt.ino ├── Example6_TwentyMinuteTest │ └── Example6_TwentyMinuteTest.ino ├── Example7_SensitivityDemo │ └── Example7_SensitivityDemo.ino ├── Example8_Core │ └── Example8_Core.ino └── Example9_AdvancedBegin │ └── Example9_AdvancedBegin.ino ├── extras └── readme_picture.jpg ├── keywords.txt ├── library.properties └── src ├── SparkFunCCS811.cpp └── SparkFunCCS811.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | src/.SparkFunCCS811.cpp.un~ 3 | *.cpp~ 4 | *.properties~ 5 | *.un~ 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | SparkFun License Information 2 | ============================ 3 | 4 | SparkFun uses two different licenses for our files - one for hardware and one for code. 5 | 6 | Hardware 7 | --------- 8 | 9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).** 10 | 11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode). 12 | 13 | You are free to: 14 | 15 | Share — copy and redistribute the material in any medium or format 16 | Adapt — remix, transform, and build upon the material 17 | for any purpose, even commercially. 18 | The licensor cannot revoke these freedoms as long as you follow the license terms. 19 | Under the following terms: 20 | 21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. 24 | Notices: 25 | 26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. 27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. 28 | 29 | 30 | Code 31 | -------- 32 | 33 | **SparkFun code, firmware, and software is released under the [MIT License](http://opensource.org/licenses/MIT).** 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2015 SparkFun Electronics 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all 47 | copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. 56 | 57 | 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun CCS811 Arduino Library 2 | ======================================== 3 | 4 | ![SparkFun CCS811 Breakout](https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library/blob/master/extras/readme_picture.jpg) 5 | 6 | [*SparkFun CCS811 (SEN-14193)*](https://www.sparkfun.com/products/14193) 7 | 8 | This is an arduino IDE library to control the CCS811. 9 | 10 | This has been tested with Arduino Uno, ESP32, and Teensy 3.2 using Arduino 1.8.1. 11 | 12 | Repository Contents 13 | ------------------- 14 | 15 | * **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. 16 | * **/extras** - Contains class diagrams for the driver. Ignored by IDE. 17 | * **/src** - Source files for the library (.cpp, .h). 18 | * **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. 19 | * **library.properties** - General library properties for the Arduino package manager. 20 | 21 | Examples 22 | -------------- 23 | 24 | * BaselineOperator - Save and restore baselines to the EEPROM 25 | * BasicReadings - Get data from the CCS811 as fast as possible 26 | * BME280Compensated - Compensate the CCS811 with data from your BME280 sensor 27 | * Core - Shows how the underlying hardware object works 28 | * NTCCompensated - Compensate the CCS811 with data from a supplied NTC Thermistor 29 | * setEnvironmentalReadings - Compensate the CCS with random data 30 | * TwentyMinuteTest - Report data with timestamp. 31 | * WakeAndInterrupt - Shows how to use the nWake and nInt pins 32 | 33 | Documentation 34 | -------------- 35 | 36 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 37 | * **[Product Repository](https://github.com/sparkfun/CCS811_Air_Quality_Breakout)** - Main repository (including hardware files) for the CCS811 Breakout. 38 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/ccs811-air-quality-breakout-hookup-guide)** - Basic hookup guide for the CCS811 Breakout. 39 | 40 | Products that use this Library 41 | --------------------------------- 42 | 43 | * [SEN-14193](https://www.sparkfun.com/)- CCS811 Breakout board 44 | 45 | Version History 46 | --------------- 47 | 48 | * [V 1.0.0](https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library/tree/V_1.0.0) -- Initial commit of Arduino compatible library. 49 | 50 | License Information 51 | ------------------- 52 | 53 | This product is _**open source**_! 54 | 55 | Please review the LICENSE.md file for license information. 56 | 57 | If you have any questions or concerns on licensing, please contact techsupport@sparkfun.com. 58 | 59 | Distributed as-is; no warranty is given. 60 | 61 | - Your friends at SparkFun. 62 | 63 | -------------------------------------------------------------------------------- /examples/Example1_BasicReadings/Example1_BasicReadings.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Read basic CO2 and TVOCs 3 | 4 | Marshall Taylor @ SparkFun Electronics 5 | Nathan Seidle @ SparkFun Electronics 6 | 7 | April 4, 2017 8 | 9 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 10 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 11 | 12 | Read the TVOC and CO2 values from the SparkFun CSS811 breakout board 13 | 14 | A new sensor requires at 48-burn in. Once burned in a sensor requires 15 | 20 minutes of run in before readings are considered good. 16 | 17 | Hardware Connections (Breakoutboard to Arduino): 18 | 3.3V to 3.3V pin 19 | GND to GND pin 20 | SDA to A4 21 | SCL to A5 22 | 23 | ******************************************************************************/ 24 | #include 25 | 26 | #include "SparkFunCCS811.h" //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 27 | 28 | #define CCS811_ADDR 0x5B //Default I2C Address 29 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 30 | 31 | CCS811 mySensor(CCS811_ADDR); 32 | 33 | void setup() 34 | { 35 | Serial.begin(115200); 36 | Serial.println("CCS811 Basic Example"); 37 | 38 | Wire.begin(); //Inialize I2C Hardware 39 | 40 | if (mySensor.begin() == false) 41 | { 42 | Serial.print("CCS811 error. Please check wiring. Freezing..."); 43 | while (1) 44 | ; 45 | } 46 | } 47 | 48 | void loop() 49 | { 50 | //Check to see if data is ready with .dataAvailable() 51 | if (mySensor.dataAvailable()) 52 | { 53 | //If so, have the sensor read and calculate the results. 54 | //Get them later 55 | mySensor.readAlgorithmResults(); 56 | 57 | Serial.print("CO2["); 58 | //Returns calculated CO2 reading 59 | Serial.print(mySensor.getCO2()); 60 | Serial.print("] tVOC["); 61 | //Returns calculated TVOC reading 62 | Serial.print(mySensor.getTVOC()); 63 | Serial.print("] millis["); 64 | //Display the time since program start 65 | Serial.print(millis()); 66 | Serial.print("]"); 67 | Serial.println(); 68 | } 69 | 70 | delay(10); //Don't spam the I2C bus 71 | } -------------------------------------------------------------------------------- /examples/Example2_BME280Compensation/Example2_BME280Compensation.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Compensating the CCS811 with humidity readings from the BME280 3 | 4 | Marshall Taylor @ SparkFun Electronics 5 | 6 | April 4, 2017 7 | 8 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 9 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 10 | 11 | This example uses a BME280 to gather environmental data that is then used 12 | to compensate the CCS811. 13 | 14 | Hardware Connections (Breakoutboard to Arduino): 15 | 3.3V to 3.3V pin 16 | GND to GND pin 17 | SDA to A4 18 | SCL to A5 19 | 20 | Resources: 21 | Uses Wire.h for i2c operation 22 | 23 | Development environment specifics: 24 | Arduino IDE 1.8.1 25 | 26 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 27 | 28 | Please review the LICENSE.md file included with this example. If you have any questions 29 | or concerns with licensing, please contact techsupport@sparkfun.com. 30 | 31 | Distributed as-is; no warranty is given. 32 | ******************************************************************************/ 33 | #include 34 | #include //Click here to get the library: http://librarymanager/All#SparkFun_BME280 35 | #include //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 36 | 37 | #define CCS811_ADDR 0x5B //Default I2C Address 38 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 39 | 40 | #define PIN_NOT_WAKE 5 41 | 42 | //Global sensor objects 43 | CCS811 myCCS811(CCS811_ADDR); 44 | BME280 myBME280; 45 | 46 | void setup() 47 | { 48 | Serial.begin(115200); 49 | Serial.println(); 50 | Serial.println("Apply BME280 data to CCS811 for compensation."); 51 | 52 | Wire.begin(); 53 | 54 | //This begins the CCS811 sensor and prints error status of .beginWithStatus() 55 | CCS811Core::CCS811_Status_e returnCode = myCCS811.beginWithStatus(); 56 | Serial.print("CCS811 begin exited with: "); 57 | Serial.println(myCCS811.statusString(returnCode)); 58 | 59 | //For I2C, enable the following and disable the SPI section 60 | myBME280.settings.commInterface = I2C_MODE; 61 | myBME280.settings.I2CAddress = 0x77; 62 | 63 | //Initialize BME280 64 | //For I2C, enable the following and disable the SPI section 65 | myBME280.settings.commInterface = I2C_MODE; 66 | myBME280.settings.I2CAddress = 0x77; 67 | myBME280.settings.runMode = 3; //Normal mode 68 | myBME280.settings.tStandby = 0; 69 | myBME280.settings.filter = 4; 70 | myBME280.settings.tempOverSample = 5; 71 | myBME280.settings.pressOverSample = 5; 72 | myBME280.settings.humidOverSample = 5; 73 | 74 | //Calling .begin() causes the settings to be loaded 75 | delay(10); //Make sure sensor had enough time to turn on. BME280 requires 2ms to start up. 76 | myBME280.begin(); 77 | } 78 | //--------------------------------------------------------------- 79 | void loop() 80 | { 81 | //Check to see if data is available 82 | if (myCCS811.dataAvailable()) 83 | { 84 | //Calling this function updates the global tVOC and eCO2 variables 85 | myCCS811.readAlgorithmResults(); 86 | //printInfoSerial fetches the values of tVOC and eCO2 87 | printInfoSerial(); 88 | 89 | float BMEtempC = myBME280.readTempC(); 90 | float BMEhumid = myBME280.readFloatHumidity(); 91 | 92 | Serial.print("Applying new values (deg C, %): "); 93 | Serial.print(BMEtempC); 94 | Serial.print(","); 95 | Serial.println(BMEhumid); 96 | Serial.println(); 97 | 98 | //This sends the temperature data to the CCS811 99 | myCCS811.setEnvironmentalData(BMEhumid, BMEtempC); 100 | } 101 | else if (myCCS811.checkForStatusError()) 102 | { 103 | //If the CCS811 found an internal error, print it. 104 | printSensorError(); 105 | } 106 | 107 | delay(2000); //Wait for next reading 108 | } 109 | 110 | //--------------------------------------------------------------- 111 | void printInfoSerial() 112 | { 113 | //getCO2() gets the previously read data from the library 114 | Serial.println("CCS811 data:"); 115 | Serial.print(" CO2 concentration : "); 116 | Serial.print(myCCS811.getCO2()); 117 | Serial.println(" ppm"); 118 | 119 | //getTVOC() gets the previously read data from the library 120 | Serial.print(" TVOC concentration : "); 121 | Serial.print(myCCS811.getTVOC()); 122 | Serial.println(" ppb"); 123 | 124 | Serial.println("BME280 data:"); 125 | Serial.print(" Temperature: "); 126 | Serial.print(myBME280.readTempC(), 2); 127 | Serial.println(" degrees C"); 128 | 129 | Serial.print(" Temperature: "); 130 | Serial.print(myBME280.readTempF(), 2); 131 | Serial.println(" degrees F"); 132 | 133 | Serial.print(" Pressure: "); 134 | Serial.print(myBME280.readFloatPressure(), 2); 135 | Serial.println(" Pa"); 136 | 137 | Serial.print(" Pressure: "); 138 | Serial.print((myBME280.readFloatPressure() * 0.0002953), 2); 139 | Serial.println(" InHg"); 140 | 141 | Serial.print(" Altitude: "); 142 | Serial.print(myBME280.readFloatAltitudeMeters(), 2); 143 | Serial.println("m"); 144 | 145 | Serial.print(" Altitude: "); 146 | Serial.print(myBME280.readFloatAltitudeFeet(), 2); 147 | Serial.println("ft"); 148 | 149 | Serial.print(" %RH: "); 150 | Serial.print(myBME280.readFloatHumidity(), 2); 151 | Serial.println(" %"); 152 | 153 | Serial.println(); 154 | } 155 | 156 | //printSensorError gets, clears, then prints the errors 157 | //saved within the error register. 158 | void printSensorError() 159 | { 160 | uint8_t error = myCCS811.getErrorRegister(); 161 | 162 | if (error == 0xFF) //comm error 163 | { 164 | Serial.println("Failed to get ERROR_ID register."); 165 | } 166 | else 167 | { 168 | Serial.print("Error: "); 169 | if (error & 1 << 5) 170 | Serial.print("HeaterSupply"); 171 | if (error & 1 << 4) 172 | Serial.print("HeaterFault"); 173 | if (error & 1 << 3) 174 | Serial.print("MaxResistance"); 175 | if (error & 1 << 2) 176 | Serial.print("MeasModeInvalid"); 177 | if (error & 1 << 1) 178 | Serial.print("ReadRegInvalid"); 179 | if (error & 1 << 0) 180 | Serial.print("MsgInvalid"); 181 | Serial.println(); 182 | } 183 | } -------------------------------------------------------------------------------- /examples/Example3_ThermistorCompensation/Example3_ThermistorCompensation.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Compensating with low-cost NTC thermistor 3 | 4 | Marshall Taylor @ SparkFun Electronics 5 | 6 | April 4, 2017 7 | 8 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 9 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 10 | 11 | NOTE: Temperature from an attached NTC Thermistor is no longer supported on the CCS811. 12 | This example is for reference only and will only work on SparkFun Air Quality Breakouts purchased in 2017. 13 | For temp/humidity compensation on the CCS811, refer to Example 2 - BME280 Compensation. 14 | 15 | This example uses an NTC thermistor to gather temperature data that is then used 16 | to compensate the CCS811. (humidity defaulted at 50%) 17 | 18 | Hardware Connections (Breakoutboard to Arduino): 19 | 3.3V to 3.3V pin 20 | GND to GND pin 21 | SDA to A4 22 | SCL to A5 23 | SEN-00250 (NTCLE100E3103JB0) between NTC terminals 24 | 25 | Resources: 26 | Uses Wire.h for i2c operation 27 | 28 | Development environment specifics: 29 | Arduino IDE 1.8.1 30 | 31 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 32 | 33 | Please review the LICENSE.md file included with this example. If you have any questions 34 | or concerns with licensing, please contact techsupport@sparkfun.com. 35 | 36 | Distributed as-is; no warranty is given. 37 | ******************************************************************************/ 38 | #include 39 | #include "SparkFunCCS811.h" //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 40 | 41 | #define CCS811_ADDR 0x5B //Default I2C Address 42 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 43 | 44 | CCS811 myCCS811(CCS811_ADDR); 45 | 46 | void setup() 47 | { 48 | Serial.begin(115200); 49 | Serial.println(); 50 | Serial.println("Apply NTC data to CCS811 for compensation."); 51 | 52 | Wire.begin(); 53 | 54 | //This begins the CCS811 sensor and prints error status of .beginWithStatus() 55 | CCS811Core::CCS811_Status_e returnCode = myCCS811.beginWithStatus(); 56 | Serial.print("CCS811 begin exited with: "); 57 | //Pass the error code to a function to print the results 58 | Serial.print(myCCS811.statusString(returnCode)); 59 | Serial.println(); 60 | 61 | myCCS811.setRefResistance(9950); 62 | } 63 | 64 | void loop() 65 | { 66 | if (myCCS811.dataAvailable()) 67 | { 68 | myCCS811.readAlgorithmResults(); //Calling this function updates the global tVOC and CO2 variables 69 | 70 | Serial.println("CCS811 data:"); 71 | Serial.print(" CO2 concentration : "); 72 | Serial.print(myCCS811.getCO2()); 73 | Serial.println(" ppm"); 74 | 75 | Serial.print(" TVOC concentration : "); 76 | Serial.print(myCCS811.getTVOC()); 77 | Serial.println(" ppb"); 78 | 79 | //.readNTC() causes the CCS811 library to gather ADC data and save value 80 | myCCS811.readNTC(); 81 | Serial.print(" Measured resistance : "); 82 | //After .readNTC() is called, .getResistance() can be called to actually 83 | //get the resistor value. This is not needed to get the temperature, 84 | //but can be useful information for debugging. 85 | // 86 | //Use the resistance value for custom thermistors, and calculate the 87 | //temperature yourself. 88 | Serial.print(myCCS811.getResistance()); 89 | Serial.println(" ohms"); 90 | 91 | //After .readNTC() is called, .getTemperature() can be called to get 92 | //a temperature value providing that part SEN-00250 is used in the 93 | //NTC terminals. (NTCLE100E3103JB0) 94 | Serial.print(" Converted temperature : "); 95 | float readTemperature = myCCS811.getTemperature(); 96 | Serial.print(readTemperature, 2); 97 | Serial.println(" deg C"); 98 | 99 | //Pass the temperature back into the CCS811 to compensate 100 | myCCS811.setEnvironmentalData(50, readTemperature); 101 | 102 | Serial.println(); 103 | } 104 | else if (myCCS811.checkForStatusError()) 105 | { 106 | printSensorError(); 107 | } 108 | 109 | delay(10); //Don't spam the I2C bus 110 | } 111 | 112 | //printSensorError gets, clears, then prints the errors 113 | //saved within the error register. 114 | void printSensorError() 115 | { 116 | uint8_t error = myCCS811.getErrorRegister(); 117 | 118 | if (error == 0xFF) //comm error 119 | { 120 | Serial.println("Failed to get ERROR_ID register."); 121 | } 122 | else 123 | { 124 | Serial.print("Error: "); 125 | if (error & 1 << 5) 126 | Serial.print("HeaterSupply"); 127 | if (error & 1 << 4) 128 | Serial.print("HeaterFault"); 129 | if (error & 1 << 3) 130 | Serial.print("MaxResistance"); 131 | if (error & 1 << 2) 132 | Serial.print("MeasModeInvalid"); 133 | if (error & 1 << 1) 134 | Serial.print("ReadRegInvalid"); 135 | if (error & 1 << 0) 136 | Serial.print("MsgInvalid"); 137 | Serial.println(); 138 | } 139 | } -------------------------------------------------------------------------------- /examples/Example4_SetBaseline/Example4_SetBaseline.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Adjust baseline 3 | 4 | Marshall Taylor @ SparkFun Electronics 5 | 6 | April 4, 2017 7 | 8 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 9 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 10 | 11 | This example demonstrates usage of the baseline register. 12 | 13 | To use, wait until the sensor is burned in, warmed up, and in clean air. Then, 14 | use the terminal to save the baseline to EEPROM. Aftewards, the sensor can be 15 | powered up in dirty air and the baseline can be restored to the CCS811 to help 16 | the sensor stablize faster. 17 | 18 | EEPROM memory usage: 19 | 20 | addr: data 21 | ---------- 22 | 0x00: 0xA5 23 | 0x01: 0xB2 24 | 0x02: 0xnn 25 | 0x03: 0xmm 26 | 27 | 0xA5B2 is written as an indicator that 0x02 and 0x03 contain a valid number. 28 | 0xnnmm is the saved data. 29 | 30 | The first time used, there will be no saved data 31 | 32 | Hardware Connections (Breakoutboard to Arduino): 33 | 3.3V to 3.3V pin 34 | GND to GND pin 35 | SDA to A4 36 | SCL to A5 37 | 38 | Resources: 39 | Uses Wire.h for i2c operation 40 | Uses EEPROM.h for internal EEPROM driving 41 | 42 | Development environment specifics: 43 | Arduino IDE 1.8.1 44 | 45 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 46 | 47 | Please review the LICENSE.md file included with this example. If you have any questions 48 | or concerns with licensing, please contact techsupport@sparkfun.com. 49 | 50 | Distributed as-is; no warranty is given. 51 | ******************************************************************************/ 52 | #include 53 | #include //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 54 | #include 55 | 56 | #define CCS811_ADDR 0x5B //Default I2C Address 57 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 58 | 59 | CCS811 mySensor(CCS811_ADDR); 60 | 61 | void setup() 62 | { 63 | Serial.begin(115200); 64 | Serial.println(); 65 | Serial.println("CCS811 Baseline Example"); 66 | 67 | Wire.begin(); 68 | 69 | //This begins the CCS811 sensor and prints error status of .beginWithStatus() 70 | CCS811Core::CCS811_Status_e returnCode = mySensor.beginWithStatus(); 71 | Serial.print("CCS811 begin exited with: "); 72 | //Pass the error code to a function to print the results 73 | Serial.print(mySensor.statusString(returnCode)); 74 | Serial.println(); 75 | 76 | //This looks for previously saved data in the eeprom at program start 77 | if ((EEPROM.read(0) == 0xA5) && (EEPROM.read(1) == 0xB2)) 78 | { 79 | Serial.println("EEPROM contains saved data."); 80 | } 81 | else 82 | { 83 | Serial.println("Saved data not found!"); 84 | } 85 | Serial.println(); 86 | 87 | Serial.println("Program running. Send the following characters to operate:"); 88 | Serial.println(" 's' - save baseline into EEPROM"); 89 | Serial.println(" 'l' - load and apply baseline from EEPROM"); 90 | Serial.println(" 'c' - clear baseline from EEPROM"); 91 | Serial.println(" 'r' - read and print sensor data"); 92 | } 93 | 94 | void loop() 95 | { 96 | char c; 97 | unsigned int result; 98 | unsigned int baselineToApply; 99 | CCS811Core::CCS811_Status_e errorStatus; 100 | if (Serial.available()) 101 | { 102 | c = Serial.read(); 103 | switch (c) 104 | { 105 | case 's': 106 | //This gets the latest baseline from the sensor 107 | result = mySensor.getBaseline(); 108 | Serial.print("baseline for this sensor: 0x"); 109 | if (result < 0x100) 110 | Serial.print("0"); 111 | if (result < 0x10) 112 | Serial.print("0"); 113 | Serial.println(result, HEX); 114 | //The baseline is saved (with valid data indicator bytes) 115 | EEPROM.write(0, 0xA5); 116 | EEPROM.write(1, 0xB2); 117 | EEPROM.write(2, (result >> 8) & 0x00FF); 118 | EEPROM.write(3, result & 0x00FF); 119 | break; 120 | case 'l': 121 | if ((EEPROM.read(0) == 0xA5) && (EEPROM.read(1) == 0xB2)) 122 | { 123 | Serial.println("EEPROM contains saved data."); 124 | //The recovered baseline is packed into a 16 bit word 125 | baselineToApply = ((unsigned int)EEPROM.read(2) << 8) | EEPROM.read(3); 126 | Serial.print("Saved baseline: 0x"); 127 | if (baselineToApply < 0x100) 128 | Serial.print("0"); 129 | if (baselineToApply < 0x10) 130 | Serial.print("0"); 131 | Serial.println(baselineToApply, HEX); 132 | //This programs the baseline into the sensor and monitors error states 133 | errorStatus = mySensor.setBaseline(baselineToApply); 134 | if (errorStatus == CCS811Core::CCS811_Stat_SUCCESS) 135 | { 136 | Serial.println("Baseline written to CCS811."); 137 | } 138 | else 139 | { 140 | Serial.print("Error writing baseline: "); 141 | Serial.println(mySensor.statusString(errorStatus)); 142 | } 143 | } 144 | else 145 | { 146 | Serial.println("Saved data not found!"); 147 | } 148 | break; 149 | case 'c': 150 | //Clear data indicator and data from the eeprom 151 | Serial.println("Clearing EEPROM space."); 152 | EEPROM.write(0, 0x00); 153 | EEPROM.write(1, 0x00); 154 | EEPROM.write(2, 0x00); 155 | EEPROM.write(3, 0x00); 156 | break; 157 | case 'r': 158 | if (mySensor.dataAvailable()) 159 | { 160 | //Simply print the last sensor data 161 | mySensor.readAlgorithmResults(); 162 | 163 | Serial.print("CO2["); 164 | Serial.print(mySensor.getCO2()); 165 | Serial.print("] tVOC["); 166 | Serial.print(mySensor.getTVOC()); 167 | Serial.print("]"); 168 | Serial.println(); 169 | } 170 | else 171 | { 172 | Serial.println("Sensor data not available."); 173 | } 174 | break; 175 | default: 176 | break; 177 | } 178 | } 179 | delay(10); 180 | } 181 | -------------------------------------------------------------------------------- /examples/Example5_WakeAndInterrupt/Example5_WakeAndInterrupt.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Wake from sleep and read interrupts 3 | 4 | Marshall Taylor @ SparkFun Electronics 5 | 6 | April 4, 2017 7 | 8 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 9 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 10 | 11 | This example configures the nWAKE and nINT pins. 12 | The interrupt pin is configured to pull low when the data is 13 | ready to be collected. 14 | The wake pin is configured to enable the sensor during I2C communications 15 | 16 | Hardware Connections (Breakoutboard to Arduino): 17 | 3.3V to 3.3V pin 18 | GND to GND pin 19 | SDA to A4 20 | SCL to A5 21 | NOT_INT to D6 22 | NOT_WAKE to D5 (For 5V arduinos, use resistor divider) 23 | D5--- 24 | | 25 | R1 = 4.7K 26 | | 27 | --------NOT_WAKE 28 | | 29 | R2 = 4.7K 30 | | 31 | GND 32 | 33 | Resources: 34 | Uses Wire.h for i2c operation 35 | 36 | Development environment specifics: 37 | Arduino IDE 1.8.1 38 | 39 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 40 | 41 | Please review the LICENSE.md file included with this example. If you have any questions 42 | or concerns with licensing, please contact techsupport@sparkfun.com. 43 | 44 | Distributed as-is; no warranty is given. 45 | ******************************************************************************/ 46 | #include 47 | 48 | #include //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 49 | 50 | #define CCS811_ADDR 0x5B //Default I2C Address 51 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 52 | 53 | #define PIN_NOT_WAKE 5 54 | #define PIN_NOT_INT 6 55 | 56 | CCS811 myCCS811(CCS811_ADDR); 57 | 58 | //Global sensor object 59 | //--------------------------------------------------------------- 60 | void setup() 61 | { 62 | //Start the serial 63 | Serial.begin(115200); 64 | Serial.println(); 65 | Serial.println("..."); 66 | 67 | Wire.begin(); 68 | 69 | //This begins the CCS811 sensor and prints error status of .beginWithStatus() 70 | CCS811Core::CCS811_Status_e returnCode = myCCS811.beginWithStatus(); 71 | Serial.print("CCS811 begin exited with: "); 72 | //Pass the error code to a function to print the results 73 | Serial.println(myCCS811.statusString(returnCode)); 74 | 75 | //This sets the mode to 60 second reads, and prints returned error status. 76 | returnCode = myCCS811.setDriveMode(2); 77 | Serial.print("Mode request exited with: "); 78 | Serial.println(myCCS811.statusString(returnCode)); 79 | 80 | //Configure and enable the interrupt line, 81 | //then print error status 82 | pinMode(PIN_NOT_INT, INPUT_PULLUP); 83 | returnCode = myCCS811.enableInterrupts(); 84 | Serial.print("Interrupt configuation exited with: "); 85 | Serial.println(myCCS811.statusString(returnCode)); 86 | 87 | //Configure the wake line 88 | pinMode(PIN_NOT_WAKE, OUTPUT); 89 | digitalWrite(PIN_NOT_WAKE, 1); //Start asleep 90 | } 91 | //--------------------------------------------------------------- 92 | void loop() 93 | { 94 | //Look for interrupt request from CCS811 95 | if (digitalRead(PIN_NOT_INT) == 0) 96 | { 97 | //Wake up the CCS811 logic engine 98 | digitalWrite(PIN_NOT_WAKE, 0); 99 | //Need to wait at least 50 us 100 | delay(1); 101 | //Interrupt signal caught, so cause the CCS811 to run its algorithm 102 | myCCS811.readAlgorithmResults(); //Calling this function updates the global tVOC and CO2 variables 103 | 104 | Serial.print("CO2["); 105 | Serial.print(myCCS811.getCO2()); 106 | Serial.print("] tVOC["); 107 | Serial.print(myCCS811.getTVOC()); 108 | Serial.print("] millis["); 109 | Serial.print(millis()); 110 | Serial.print("]"); 111 | Serial.println(); 112 | 113 | //Now put the CCS811's logic engine to sleep 114 | digitalWrite(PIN_NOT_WAKE, 1); 115 | //Need to be asleep for at least 20 us 116 | delay(1); 117 | } 118 | delay(1); //cycle kinda fast 119 | } 120 | 121 | //printSensorError gets, clears, then prints the errors 122 | //saved within the error register. 123 | void printSensorError() 124 | { 125 | uint8_t error = myCCS811.getErrorRegister(); 126 | 127 | if (error == 0xFF) //comm error 128 | { 129 | Serial.println("Failed to get ERROR_ID register."); 130 | } 131 | else 132 | { 133 | Serial.print("Error: "); 134 | if (error & 1 << 5) 135 | Serial.print("HeaterSupply"); 136 | if (error & 1 << 4) 137 | Serial.print("HeaterFault"); 138 | if (error & 1 << 3) 139 | Serial.print("MaxResistance"); 140 | if (error & 1 << 2) 141 | Serial.print("MeasModeInvalid"); 142 | if (error & 1 << 1) 143 | Serial.print("ReadRegInvalid"); 144 | if (error & 1 << 0) 145 | Serial.print("MsgInvalid"); 146 | Serial.println(); 147 | } 148 | } -------------------------------------------------------------------------------- /examples/Example6_TwentyMinuteTest/Example6_TwentyMinuteTest.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Run for 20 minutes 3 | 4 | Nathan Seidle @ SparkFun Electronics 5 | Marshall Taylor @ SparkFun Electronics 6 | 7 | April 4, 2017 8 | 9 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 10 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 11 | 12 | Hardware Connections (Breakoutboard to Arduino): 13 | 3.3V to 3.3V pin 14 | GND to GND pin 15 | SDA to A4 16 | SCL to A5 17 | 18 | Calculates the current run time and indicates when 20 minutes has passed 19 | 20 | Read the TVOC and CO2 values from the SparkFun CSS811 breakout board 21 | 22 | A new sensor requires at 48-burn in. Once burned in a sensor requires 23 | 20 minutes of run in before readings are considered good. 24 | 25 | Resources: 26 | Uses Wire.h for i2c operation 27 | 28 | Development environment specifics: 29 | Arduino IDE 1.8.1 30 | 31 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 32 | 33 | Please review the LICENSE.md file included with this example. If you have any questions 34 | or concerns with licensing, please contact techsupport@sparkfun.com. 35 | 36 | Distributed as-is; no warranty is given. 37 | ******************************************************************************/ 38 | #include 39 | 40 | #include "SparkFunCCS811.h" //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 41 | 42 | #define CCS811_ADDR 0x5B //Default I2C Address 43 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 44 | 45 | CCS811 myCCS811(CCS811_ADDR); 46 | 47 | void setup() 48 | { 49 | Serial.begin(115200); 50 | Serial.println("20 minute test"); 51 | 52 | Wire.begin(); 53 | 54 | //This begins the CCS811 sensor and prints error status of .beginWithStatus() 55 | CCS811Core::CCS811_Status_e returnCode = myCCS811.beginWithStatus(); 56 | Serial.print("CCS811 begin exited with: "); 57 | Serial.println(myCCS811.statusString(returnCode)); 58 | } 59 | 60 | void loop() 61 | { 62 | if (myCCS811.dataAvailable()) 63 | { 64 | myCCS811.readAlgorithmResults(); 65 | 66 | Serial.print("CO2["); 67 | Serial.print(myCCS811.getCO2()); 68 | Serial.print("] tVOC["); 69 | Serial.print(myCCS811.getTVOC()); 70 | Serial.print("] millis["); 71 | Serial.print(millis()); 72 | Serial.print("] "); 73 | printRunTime(); 74 | Serial.println(); 75 | } 76 | else if (myCCS811.checkForStatusError()) 77 | { 78 | printSensorError(); 79 | } 80 | 81 | delay(1000); //Wait for next reading 82 | } 83 | 84 | //Prints the amount of time the board has been running 85 | //Does the hour, minute, and second calcs 86 | void printRunTime() 87 | { 88 | char buffer[50]; 89 | 90 | unsigned long runTime = millis(); 91 | 92 | int hours = runTime / (60 * 60 * 1000L); 93 | runTime %= (60 * 60 * 1000L); 94 | int minutes = runTime / (60 * 1000L); 95 | runTime %= (60 * 1000L); 96 | int seconds = runTime / 1000L; 97 | 98 | sprintf(buffer, "RunTime[%02d:%02d:%02d]", hours, minutes, seconds); 99 | Serial.print(buffer); 100 | 101 | if (hours == 0 && minutes < 20) 102 | Serial.print(" Not yet valid"); 103 | } 104 | 105 | //printSensorError gets, clears, then prints the errors 106 | //saved within the error register. 107 | void printSensorError() 108 | { 109 | uint8_t error = myCCS811.getErrorRegister(); 110 | 111 | if (error == 0xFF) //comm error 112 | { 113 | Serial.println("Failed to get ERROR_ID register."); 114 | } 115 | else 116 | { 117 | Serial.print("Error: "); 118 | if (error & 1 << 5) 119 | Serial.print("HeaterSupply"); 120 | if (error & 1 << 4) 121 | Serial.print("HeaterFault"); 122 | if (error & 1 << 3) 123 | Serial.print("MaxResistance"); 124 | if (error & 1 << 2) 125 | Serial.print("MeasModeInvalid"); 126 | if (error & 1 << 1) 127 | Serial.print("ReadRegInvalid"); 128 | if (error & 1 << 0) 129 | Serial.print("MsgInvalid"); 130 | Serial.println(); 131 | } 132 | } -------------------------------------------------------------------------------- /examples/Example7_SensitivityDemo/Example7_SensitivityDemo.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Sensitivity Demo 3 | 4 | Marshall Taylor @ SparkFun Electronics 5 | 6 | April 4, 2017 7 | 8 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 9 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 10 | 11 | Hardware Connections (Breakoutboard to Arduino): 12 | 3.3V to 3.3V pin 13 | GND to GND pin 14 | SDA to A4 15 | SCL to A5 16 | 17 | Generates random temperature and humidity data, and uses it to compensate the CCS811. 18 | This just demonstrates how the algorithm responds to various compensation points. 19 | Use NTCCompensated or BME280Compensated for real-world examples. 20 | 21 | Resources: 22 | Uses Wire.h for i2c operation 23 | 24 | Development environment specifics: 25 | Arduino IDE 1.8.1 26 | 27 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 28 | 29 | Please review the LICENSE.md file included with this example. If you have any questions 30 | or concerns with licensing, please contact techsupport@sparkfun.com. 31 | 32 | Distributed as-is; no warranty is given. 33 | ******************************************************************************/ 34 | float temperatureVariable = 25.0; //in degrees C 35 | float humidityVariable = 65.0; //in % relative 36 | 37 | #include 38 | #include "SparkFunCCS811.h" //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 39 | 40 | #define CCS811_ADDR 0x5B //Default I2C Address 41 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 42 | 43 | CCS811 myCCS811(CCS811_ADDR); 44 | 45 | void setup() 46 | { 47 | Serial.begin(115200); 48 | Serial.println("CCS811 EnvironmentalReadings Example"); 49 | 50 | Wire.begin(); 51 | 52 | //This begins the CCS811 sensor and prints error status of .beginWithStatus() 53 | CCS811Core::CCS811_Status_e returnCode = myCCS811.beginWithStatus(); 54 | Serial.print("CCS811 begin exited with: "); 55 | Serial.println(myCCS811.statusString(returnCode)); 56 | } 57 | 58 | void loop() 59 | { 60 | Serial.println(); 61 | //Randomize the Temperature and Humidity 62 | humidityVariable = (float)random(0, 10000) / 100; //0 to 100% 63 | temperatureVariable = (float)random(500, 7000) / 100; // 5C to 70C 64 | Serial.println("New humidity and temperature:"); 65 | Serial.print(" Humidity: "); 66 | Serial.print(humidityVariable, 2); 67 | Serial.println("% relative"); 68 | Serial.print(" Temperature: "); 69 | Serial.print(temperatureVariable, 2); 70 | Serial.println(" degrees C"); 71 | myCCS811.setEnvironmentalData(humidityVariable, temperatureVariable); 72 | 73 | Serial.println("Environmental data applied!"); 74 | myCCS811.readAlgorithmResults(); //Dump a reading and wait 75 | delay(1000); 76 | //Print data points 77 | for (int i = 0; i < 10; i++) 78 | { 79 | if (myCCS811.dataAvailable()) 80 | { 81 | //Calling readAlgorithmResults() function updates the global tVOC and CO2 variables 82 | myCCS811.readAlgorithmResults(); 83 | 84 | Serial.print("CO2["); 85 | Serial.print(myCCS811.getCO2()); 86 | Serial.print("] tVOC["); 87 | Serial.print(myCCS811.getTVOC()); 88 | Serial.print("] millis["); 89 | Serial.print(millis()); 90 | Serial.print("]"); 91 | Serial.println(); 92 | } 93 | else if (myCCS811.checkForStatusError()) 94 | { 95 | //If the CCS811 found an internal error, print it. 96 | printSensorError(); 97 | } 98 | delay(1000); //Wait for next reading 99 | } 100 | } 101 | 102 | //printSensorError gets, clears, then prints the errors 103 | //saved within the error register. 104 | void printSensorError() 105 | { 106 | uint8_t error = myCCS811.getErrorRegister(); 107 | 108 | if (error == 0xFF) //comm error 109 | { 110 | Serial.println("Failed to get ERROR_ID register."); 111 | } 112 | else 113 | { 114 | Serial.print("Error: "); 115 | if (error & 1 << 5) 116 | Serial.print("HeaterSupply"); 117 | if (error & 1 << 4) 118 | Serial.print("HeaterFault"); 119 | if (error & 1 << 3) 120 | Serial.print("MaxResistance"); 121 | if (error & 1 << 2) 122 | Serial.print("MeasModeInvalid"); 123 | if (error & 1 << 1) 124 | Serial.print("ReadRegInvalid"); 125 | if (error & 1 << 0) 126 | Serial.print("MsgInvalid"); 127 | Serial.println(); 128 | } 129 | } -------------------------------------------------------------------------------- /examples/Example8_Core/Example8_Core.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Core 3 | 4 | Marshall Taylor @ SparkFun Electronics 5 | 6 | April 4, 2017 7 | 8 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 9 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 10 | 11 | This example shows how the normally hidden core class operates the wire interface. 12 | 13 | The class 'CCS811Core' abstracts the wire library and contains special hardware 14 | functions, and is normally not needed. 15 | 16 | Use this sketch to test the core of the library, or inherit it with your own 17 | functions for performing CCS811 operations. 18 | 19 | Hardware Connections (Breakoutboard to Arduino): 20 | 3.3V to 3.3V pin 21 | GND to GND pin 22 | SDA to A4 23 | SCL to A5 24 | 25 | 26 | Resources: 27 | Uses Wire.h for i2c operation 28 | 29 | Development environment specifics: 30 | Arduino IDE 1.8.1 31 | 32 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 33 | 34 | Please review the LICENSE.md file included with this example. If you have any questions 35 | or concerns with licensing, please contact techsupport@sparkfun.com. 36 | 37 | Distributed as-is; no warranty is given. 38 | ******************************************************************************/ 39 | #include 40 | 41 | #include "SparkFunCCS811.h" //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 42 | 43 | #define CCS811_ADDR 0x5B //Default I2C Address 44 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 45 | 46 | CCS811Core mySensor(CCS811_ADDR); 47 | 48 | void setup() 49 | { 50 | Serial.begin(115200); 51 | Serial.println(); 52 | Serial.println("CCS811 Core Example"); 53 | 54 | Wire.begin(); 55 | 56 | //This setup routine is similar to what is used in the subclass' .begin() function 57 | CCS811Core::CCS811_Status_e returnCode = mySensor.beginCore(Wire); //Pass in the Wire port you want to use 58 | Serial.print("beginCore exited with: "); 59 | switch (returnCode) 60 | { 61 | case CCS811Core::CCS811_Stat_SUCCESS: 62 | Serial.print("SUCCESS"); 63 | break; 64 | case CCS811Core::CCS811_Stat_ID_ERROR: 65 | Serial.print("ID_ERROR"); 66 | break; 67 | case CCS811Core::CCS811_Stat_I2C_ERROR: 68 | Serial.print("I2C_ERROR"); 69 | break; 70 | case CCS811Core::CCS811_Stat_INTERNAL_ERROR: 71 | Serial.print("INTERNAL_ERROR"); 72 | break; 73 | case CCS811Core::CCS811_Stat_GENERIC_ERROR: 74 | Serial.print("GENERIC_ERROR"); 75 | break; 76 | default: 77 | Serial.print("Unspecified error."); 78 | } 79 | 80 | //Write to this register to start app 81 | Wire.beginTransmission(CCS811_ADDR); 82 | Wire.write(CSS811_APP_START); 83 | Wire.endTransmission(); 84 | } 85 | 86 | void loop() 87 | { 88 | uint8_t arraySize = 10; 89 | uint8_t tempData[arraySize]; 90 | 91 | tempData[0] = 0x18; 92 | tempData[1] = 0x27; 93 | tempData[2] = 0x36; 94 | tempData[3] = 0x45; 95 | 96 | mySensor.multiWriteRegister(0x11, tempData, 2); 97 | 98 | tempData[0] = 0x00; 99 | tempData[1] = 0x00; 100 | tempData[2] = 0x00; 101 | tempData[3] = 0x00; 102 | 103 | mySensor.multiReadRegister(0x11, tempData, 3); 104 | 105 | for (int i = 0; i < arraySize; i++) 106 | { 107 | if (i % 8 == 0) 108 | { 109 | Serial.println(); 110 | Serial.print("0x"); 111 | Serial.print(i, HEX); 112 | Serial.print(":"); 113 | } 114 | 115 | Serial.print(tempData[i], HEX); 116 | Serial.print(" "); 117 | } 118 | 119 | Serial.println("\n"); 120 | delay(1000); //Wait for next reading 121 | } -------------------------------------------------------------------------------- /examples/Example9_AdvancedBegin/Example9_AdvancedBegin.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Read basic CO2 and TVOCs on alternate Wire ports 3 | 4 | Marshall Taylor @ SparkFun Electronics 5 | Nathan Seidle @ SparkFun Electronics 6 | 7 | April 4, 2017 8 | 9 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 10 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 11 | 12 | Read the TVOC and CO2 values from the SparkFun CSS811 breakout board 13 | 14 | This shows how to begin communication with the sensor on a different Wire port. 15 | Helpful if you have platform that is a slave to a larger system and need 16 | a dedicated Wire port or if you need to talk to many sensors at the same time. 17 | 18 | A new sensor requires at 48-burn in. Once burned in a sensor requires 19 | 20 minutes of run in before readings are considered good. 20 | 21 | Hardware Connections (Breakoutboard to Arduino): 22 | 3.3V to 3.3V pin 23 | GND to GND pin 24 | SDA to A4 25 | SCL to A5 26 | 27 | Resources: 28 | Uses Wire.h for i2c operation 29 | 30 | Development environment specifics: 31 | Arduino IDE 1.8.1 32 | 33 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 34 | 35 | Please review the LICENSE.md file included with this example. If you have any questions 36 | or concerns with licensing, please contact techsupport@sparkfun.com. 37 | 38 | Distributed as-is; no warranty is given. 39 | ******************************************************************************/ 40 | #include 41 | 42 | #include "SparkFunCCS811.h" 43 | 44 | #define CCS811_ADDR 0x5B //Default I2C Address 45 | //#define CCS811_ADDR 0x5A //Alternate I2C Address 46 | 47 | CCS811 mySensor(CCS811_ADDR); 48 | 49 | void setup() 50 | { 51 | Serial.begin(115200); 52 | Serial.println("CCS811 Basic Example"); 53 | 54 | Wire1.begin(); //Compilation will fail here if your hardware doesn't support additional Wire ports 55 | 56 | //This begins the CCS811 sensor and prints error status of .beginWithStatus() 57 | CCS811Core::CCS811_Status_e returnCode = mySensor.beginWithStatus(Wire1); //Pass Wire1 into the library 58 | Serial.print("CCS811 begin exited with: "); 59 | Serial.println(mySensor.statusString(returnCode)); 60 | } 61 | 62 | void loop() 63 | { 64 | //Check to see if data is ready with .dataAvailable() 65 | if (mySensor.dataAvailable()) 66 | { 67 | //If so, have the sensor read and calculate the results. 68 | //Get them later 69 | mySensor.readAlgorithmResults(); 70 | 71 | Serial.print("CO2["); 72 | //Returns calculated CO2 reading 73 | Serial.print(mySensor.getCO2()); 74 | Serial.print("] tVOC["); 75 | //Returns calculated TVOC reading 76 | Serial.print(mySensor.getTVOC()); 77 | Serial.print("] millis["); 78 | //Simply the time since program start 79 | Serial.print(millis()); 80 | Serial.print("]"); 81 | Serial.println(); 82 | } 83 | 84 | delay(10); //Don't spam the I2C bus 85 | } -------------------------------------------------------------------------------- /extras/readme_picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/SparkFun_CCS811_Arduino_Library/287aa5c6120ea3227f7fa6fdef4f2253888ea2f2/extras/readme_picture.jpg -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ######################################################## 2 | # Syntax Coloring Map for SparkFun CCS811 Library # 3 | ######################################################## 4 | # Class 5 | ################################################################### 6 | 7 | CCS811Core KEYWORD1 8 | CCS811 KEYWORD1 9 | 10 | ################################################################### 11 | # Methods and Functions 12 | ################################################################### 13 | 14 | beginCore KEYWORD2 15 | readRegister KEYWORD2 16 | multiReadRegister KEYWORD2 17 | writeRegister KEYWORD2 18 | multiWriteRegister KEYWORD2 19 | begin KEYWORD2 20 | readAlgorithmResults KEYWORD2 21 | checkForStatusError KEYWORD2 22 | dataAvailable KEYWORD2 23 | appValid KEYWORD2 24 | getErrorRegister KEYWORD2 25 | getBaseline KEYWORD2 26 | setBaseline KEYWORD2 27 | enableInterrupts KEYWORD2 28 | disableInterrupts KEYWORD2 29 | setDriveMode KEYWORD2 30 | setEnvironmentalData KEYWORD2 31 | setRefResistance KEYWORD2 32 | readNTC KEYWORD2 33 | getTVOC KEYWORD2 34 | getCO2 KEYWORD2 35 | getResistance KEYWORD2 36 | getTemperature KEYWORD2 37 | status KEYWORD2 38 | 39 | ################################################################### 40 | # Constants 41 | ################################################################### 42 | 43 | CSS811_STATUS LITERAL1 44 | CSS811_MEAS_MODE LITERAL1 45 | CSS811_ALG_RESULT_DATA LITERAL1 46 | CSS811_RAW_DATA LITERAL1 47 | CSS811_ENV_DATA LITERAL1 48 | CSS811_NTC LITERAL1 49 | CSS811_THRESHOLDS LITERAL1 50 | CSS811_BASELINE LITERAL1 51 | CSS811_HW_ID LITERAL1 52 | CSS811_HW_VERSION LITERAL1 53 | CSS811_FW_BOOT_VERSION LITERAL1 54 | CSS811_FW_APP_VERSION LITERAL1 55 | CSS811_ERROR_ID LITERAL1 56 | CSS811_APP_START LITERAL1 57 | CSS811_SW_RESET LITERAL1 58 | SENSOR_SUCCESS LITERAL1 59 | SENSOR_ID_ERROR LITERAL1 60 | SENSOR_I2C_ERROR LITERAL1 61 | SENSOR_INTERNAL_ERROR LITERAL1 62 | SENSOR_GENERIC_ERROR LITERAL1 63 | 64 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun CCS811 Arduino Library 2 | version=2.0.3 3 | author=SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=An Arduino library to drive the AMS CCS811 by I2C. 6 | paragraph=The CCS811 Air Quality Breakout is a digital gas sensor solution that senses a wide range of Total Volatile Organic Compounds (TVOCs), including equivalent carbon dioxide (eCO2) and metal oxide (MOX) levels. It is intended for indoor air quality monitoring in personal devices such as watches and phones, but we’ve put it on a breakout board so you can use it as a regular I2C device. 7 | category=Sensors 8 | url=https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/SparkFunCCS811.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SparkFunCCS811.cpp 3 | CCS811 Arduino library 4 | 5 | Marshall Taylor @ SparkFun Electronics 6 | Nathan Seidle @ SparkFun Electronics 7 | 8 | April 4, 2017 9 | 10 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 11 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 12 | 13 | Resources: 14 | Uses Wire.h for i2c operation 15 | 16 | Development environment specifics: 17 | Arduino IDE 1.8.1 18 | 19 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 20 | 21 | Please review the LICENSE.md file included with this example. If you have any questions 22 | or concerns with licensing, please contact techsupport@sparkfun.com. 23 | 24 | Distributed as-is; no warranty is given. 25 | ******************************************************************************/ 26 | 27 | //See SparkFunCCS811.h for additional topology notes. 28 | 29 | #include "SparkFunCCS811.h" 30 | #include "stdint.h" 31 | 32 | #include 33 | #include "Wire.h" 34 | #include 35 | 36 | //****************************************************************************// 37 | // 38 | // CCS811Core functions 39 | // 40 | // Default
is 0x5B. 41 | // 42 | //****************************************************************************// 43 | CCS811Core::CCS811Core(uint8_t inputArg) : I2CAddress(inputArg) 44 | { 45 | } 46 | 47 | CCS811Core::CCS811_Status_e CCS811Core::beginCore(TwoWire &wirePort) 48 | { 49 | CCS811Core::CCS811_Status_e returnError = CCS811_Stat_SUCCESS; 50 | 51 | _i2cPort = &wirePort; //Pull in user's choice of I2C hardware 52 | 53 | //Wire.begin(); //See issue 13 https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library/issues/13 54 | 55 | #ifdef __AVR__ 56 | #endif 57 | 58 | #ifdef __MK20DX256__ 59 | #endif 60 | 61 | #if defined(ARDUINO_ARCH_ESP8266) 62 | _i2cPort->setClockStretchLimit(200000); // was default 230 uS, now 200ms 63 | #endif 64 | 65 | //Spin for a few ms 66 | volatile uint8_t temp = 0; 67 | for (uint16_t i = 0; i < 10000; i++) 68 | { 69 | temp++; 70 | } 71 | 72 | //Check the ID register to determine if the operation was a success. 73 | uint8_t readCheck; 74 | readCheck = 0; 75 | returnError = readRegister(CSS811_HW_ID, &readCheck); 76 | 77 | if (returnError != CCS811_Stat_SUCCESS) 78 | return returnError; 79 | 80 | if (readCheck != 0x81) 81 | { 82 | returnError = CCS811_Stat_ID_ERROR; 83 | } 84 | 85 | return returnError; 86 | } 87 | 88 | //****************************************************************************// 89 | // 90 | // ReadRegister 91 | // 92 | // Parameters: 93 | // offset -- register to read 94 | // *outputPointer -- Pass &variable (address of) to save read data to 95 | // 96 | //****************************************************************************// 97 | CCS811Core::CCS811_Status_e CCS811Core::readRegister(uint8_t offset, uint8_t *outputPointer) 98 | { 99 | //Return value 100 | uint8_t numBytes = 1; 101 | CCS811Core::CCS811_Status_e returnError = CCS811_Stat_SUCCESS; 102 | 103 | _i2cPort->beginTransmission(I2CAddress); 104 | _i2cPort->write(offset); 105 | if (_i2cPort->endTransmission() != 0) 106 | { 107 | returnError = CCS811_Stat_I2C_ERROR; 108 | } 109 | 110 | _i2cPort->requestFrom(I2CAddress, numBytes); 111 | *outputPointer = _i2cPort->read(); // receive a byte as a proper uint8_t 112 | 113 | return returnError; 114 | } 115 | 116 | //****************************************************************************// 117 | // 118 | // multiReadRegister 119 | // 120 | // Parameters: 121 | // offset -- register to read 122 | // *outputPointer -- Pass &variable (base address of) to save read data to 123 | // length -- number of bytes to read 124 | // 125 | // Note: Does not know if the target memory space is an array or not, or 126 | // if there is the array is big enough. if the variable passed is only 127 | // two bytes long and 3 bytes are requested, this will over-write some 128 | // other memory! 129 | // 130 | //****************************************************************************// 131 | CCS811Core::CCS811_Status_e CCS811Core::multiReadRegister(uint8_t offset, uint8_t *outputPointer, uint8_t length) 132 | { 133 | CCS811Core::CCS811_Status_e returnError = CCS811_Stat_SUCCESS; 134 | 135 | //define pointer that will point to the external space 136 | uint8_t i = 0; 137 | uint8_t c = 0; 138 | //Set the address 139 | _i2cPort->beginTransmission(I2CAddress); 140 | _i2cPort->write(offset); 141 | if (_i2cPort->endTransmission() != 0) 142 | { 143 | returnError = CCS811_Stat_I2C_ERROR; 144 | } 145 | else //OK, all worked, keep going 146 | { 147 | // request 6 bytes from slave device 148 | _i2cPort->requestFrom(I2CAddress, length); 149 | while ((_i2cPort->available()) && (i < length)) // slave may send less than requested 150 | { 151 | c = _i2cPort->read(); // receive a byte as character 152 | *outputPointer = c; 153 | outputPointer++; 154 | i++; 155 | } 156 | } 157 | 158 | return returnError; 159 | } 160 | 161 | //****************************************************************************// 162 | // 163 | // writeRegister 164 | // 165 | // Parameters: 166 | // offset -- register to write 167 | // dataToWrite -- 8 bit data to write to register 168 | // 169 | //****************************************************************************// 170 | CCS811Core::CCS811_Status_e CCS811Core::writeRegister(uint8_t offset, uint8_t dataToWrite) 171 | { 172 | CCS811Core::CCS811_Status_e returnError = CCS811_Stat_SUCCESS; 173 | 174 | _i2cPort->beginTransmission(I2CAddress); 175 | _i2cPort->write(offset); 176 | _i2cPort->write(dataToWrite); 177 | if (_i2cPort->endTransmission() != 0) 178 | { 179 | returnError = CCS811_Stat_I2C_ERROR; 180 | } 181 | return returnError; 182 | } 183 | 184 | //****************************************************************************// 185 | // 186 | // multiReadRegister 187 | // 188 | // Parameters: 189 | // offset -- register to read 190 | // *inputPointer -- Pass &variable (base address of) to save read data to 191 | // length -- number of bytes to read 192 | // 193 | // Note: Does not know if the target memory space is an array or not, or 194 | // if there is the array is big enough. if the variable passed is only 195 | // two bytes long and 3 bytes are requested, this will over-write some 196 | // other memory! 197 | // 198 | //****************************************************************************// 199 | CCS811Core::CCS811_Status_e CCS811Core::multiWriteRegister(uint8_t offset, uint8_t *inputPointer, uint8_t length) 200 | { 201 | CCS811Core::CCS811_Status_e returnError = CCS811_Stat_SUCCESS; 202 | //define pointer that will point to the external space 203 | uint8_t i = 0; 204 | //Set the address 205 | _i2cPort->beginTransmission(I2CAddress); 206 | _i2cPort->write(offset); 207 | while (i < length) // send data bytes 208 | { 209 | _i2cPort->write(*inputPointer); // receive a byte as character 210 | inputPointer++; 211 | i++; 212 | } 213 | if (_i2cPort->endTransmission() != 0) 214 | { 215 | returnError = CCS811_Stat_I2C_ERROR; 216 | } 217 | return returnError; 218 | } 219 | 220 | //****************************************************************************// 221 | // 222 | // Main user class -- wrapper for the core class + maths 223 | // 224 | // Construct with same rules as the core ( uint8_t busType, uint8_t inputArg ) 225 | // 226 | //****************************************************************************// 227 | CCS811::CCS811(uint8_t inputArg) : CCS811Core(inputArg) 228 | { 229 | refResistance = 10000; //Unsupported feature. 230 | resistance = 0; //Unsupported feature. 231 | temperature = 0; 232 | tVOC = 0; 233 | CO2 = 0; 234 | } 235 | 236 | CCS811::CCS811() : CCS811(0){} 237 | //****************************************************************************// 238 | // 239 | // Begin 240 | // 241 | // This starts the lower level begin, then applies settings 242 | // 243 | //****************************************************************************// 244 | bool CCS811::begin(TwoWire &wirePort) 245 | { 246 | if (beginWithStatus(wirePort) == CCS811_Stat_SUCCESS) 247 | return true; 248 | return false; 249 | } 250 | 251 | //****************************************************************************// 252 | // 253 | // Begin 254 | // 255 | // This starts the lower level begin, then applies settings 256 | // 257 | //****************************************************************************// 258 | CCS811Core::CCS811_Status_e CCS811::beginWithStatus(TwoWire &wirePort) 259 | { 260 | uint8_t data[4] = {0x11, 0xE5, 0x72, 0x8A}; //Reset key 261 | CCS811Core::CCS811_Status_e returnError = CCS811_Stat_SUCCESS; //Default error state 262 | 263 | //restart the core 264 | returnError = beginCore(wirePort); 265 | 266 | if (returnError != CCS811_Stat_SUCCESS) 267 | return returnError; 268 | 269 | //Reset the device 270 | multiWriteRegister(CSS811_SW_RESET, data, 4); 271 | 272 | //Tclk = 1/16MHz = 0x0000000625 273 | //0.001 s / tclk = 16000 counts 274 | volatile uint8_t temp = 0; 275 | 276 | #ifdef ARDUINO_ARCH_ESP32 277 | for (uint32_t i = 0; i < 80000; i++) //This waits > 1ms @ 80MHz clock 278 | { 279 | temp++; 280 | } 281 | #elif __AVR__ 282 | for (uint16_t i = 0; i < 16000; i++) //This waits > 1ms @ 16MHz clock 283 | { 284 | temp++; 285 | } 286 | #else 287 | for (uint32_t i = 0; i < 200000; i++) //Spin for a good while 288 | { 289 | temp++; 290 | } 291 | #endif 292 | 293 | if (checkForStatusError() == true) 294 | return CCS811_Stat_INTERNAL_ERROR; 295 | 296 | if (appValid() == false) 297 | return CCS811_Stat_INTERNAL_ERROR; 298 | 299 | //Write 0 bytes to this register to start app 300 | _i2cPort->beginTransmission(I2CAddress); 301 | _i2cPort->write(CSS811_APP_START); 302 | if (_i2cPort->endTransmission() != 0) 303 | { 304 | return CCS811_Stat_I2C_ERROR; 305 | } 306 | 307 | //Added from issue 6 308 | // Without a delay here, the CCS811 and I2C can be put in a bad state. 309 | // Seems to work with 50us delay, but make a bit longer to be sure. 310 | #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) 311 | delayMicroseconds(100); 312 | #endif 313 | 314 | returnError = setDriveMode(1); //Read every second 315 | 316 | return returnError; 317 | } 318 | 319 | //****************************************************************************// 320 | // 321 | // Sensor functions 322 | // 323 | //****************************************************************************// 324 | //Updates the total voltatile organic compounds (TVOC) in parts per billion (PPB) 325 | //and the CO2 value 326 | //Returns nothing 327 | CCS811Core::CCS811_Status_e CCS811::readAlgorithmResults(void) 328 | { 329 | uint8_t data[4]; 330 | CCS811Core::CCS811_Status_e returnError = multiReadRegister(CSS811_ALG_RESULT_DATA, data, 4); 331 | if (returnError != CCS811_Stat_SUCCESS) 332 | return returnError; 333 | // Data ordered: 334 | // co2MSB, co2LSB, tvocMSB, tvocLSB 335 | 336 | CO2 = ((uint16_t)data[0] << 8) | data[1]; 337 | tVOC = ((uint16_t)data[2] << 8) | data[3]; 338 | return CCS811_Stat_SUCCESS; 339 | } 340 | 341 | //Checks to see if error bit is set 342 | bool CCS811::checkForStatusError(void) 343 | { 344 | uint8_t value; 345 | //return the status bit 346 | readRegister(CSS811_STATUS, &value); 347 | return (value & 1 << 0); 348 | } 349 | 350 | //Checks to see if DATA_READ flag is set in the status register 351 | bool CCS811::dataAvailable(void) 352 | { 353 | uint8_t value; 354 | CCS811Core::CCS811_Status_e returnError = readRegister(CSS811_STATUS, &value); 355 | if (returnError != CCS811_Stat_SUCCESS) 356 | { 357 | return 0; 358 | } 359 | else 360 | { 361 | return (value & 1 << 3); 362 | } 363 | } 364 | 365 | //Checks to see if APP_VALID flag is set in the status register 366 | bool CCS811::appValid(void) 367 | { 368 | uint8_t value; 369 | CCS811Core::CCS811_Status_e returnError = readRegister(CSS811_STATUS, &value); 370 | if (returnError != CCS811_Stat_SUCCESS) 371 | { 372 | return 0; 373 | } 374 | else 375 | { 376 | return (value & 1 << 4); 377 | } 378 | } 379 | 380 | uint8_t CCS811::getErrorRegister(void) 381 | { 382 | uint8_t value; 383 | 384 | CCS811Core::CCS811_Status_e returnError = readRegister(CSS811_ERROR_ID, &value); 385 | if (returnError != CCS811_Stat_SUCCESS) 386 | { 387 | return 0xFF; 388 | } 389 | else 390 | { 391 | return value; //Send all errors in the event of communication error 392 | } 393 | } 394 | 395 | //Returns the baseline value 396 | //Used for telling sensor what 'clean' air is 397 | //You must put the sensor in clean air and record this value 398 | uint16_t CCS811::getBaseline(void) 399 | { 400 | uint8_t data[2]; 401 | CCS811Core::CCS811_Status_e returnError = multiReadRegister(CSS811_BASELINE, data, 2); 402 | 403 | unsigned int baseline = ((uint16_t)data[0] << 8) | data[1]; 404 | if (returnError != CCS811_Stat_SUCCESS) 405 | { 406 | return 0; 407 | } 408 | else 409 | { 410 | return (baseline); 411 | } 412 | } 413 | 414 | CCS811Core::CCS811_Status_e CCS811::setBaseline(uint16_t input) 415 | { 416 | uint8_t data[2]; 417 | data[0] = (input >> 8) & 0x00FF; 418 | data[1] = input & 0x00FF; 419 | 420 | CCS811Core::CCS811_Status_e returnError = multiWriteRegister(CSS811_BASELINE, data, 2); 421 | 422 | return returnError; 423 | } 424 | 425 | //Enable the nINT signal 426 | CCS811Core::CCS811_Status_e CCS811::enableInterrupts(void) 427 | { 428 | uint8_t value; 429 | CCS811Core::CCS811_Status_e returnError = readRegister(CSS811_MEAS_MODE, &value); //Read what's currently there 430 | if (returnError != CCS811_Stat_SUCCESS) 431 | return returnError; 432 | value |= (1 << 3); //Set INTERRUPT bit 433 | writeRegister(CSS811_MEAS_MODE, value); 434 | return returnError; 435 | } 436 | 437 | //Disable the nINT signal 438 | CCS811Core::CCS811_Status_e CCS811::disableInterrupts(void) 439 | { 440 | uint8_t value; 441 | CCS811Core::CCS811_Status_e returnError = readRegister(CSS811_MEAS_MODE, &value); //Read what's currently there 442 | if (returnError != CCS811_Stat_SUCCESS) 443 | return returnError; 444 | value &= ~(1 << 3); //Clear INTERRUPT bit 445 | returnError = writeRegister(CSS811_MEAS_MODE, value); 446 | return returnError; 447 | } 448 | 449 | //Mode 0 = Idle 450 | //Mode 1 = read every 1s 451 | //Mode 2 = every 10s 452 | //Mode 3 = every 60s 453 | //Mode 4 = RAW mode 454 | CCS811Core::CCS811_Status_e CCS811::setDriveMode(uint8_t mode) 455 | { 456 | if (mode > 4) 457 | mode = 4; //sanitize input 458 | 459 | uint8_t value; 460 | CCS811Core::CCS811_Status_e returnError = readRegister(CSS811_MEAS_MODE, &value); //Read what's currently there 461 | if (returnError != CCS811_Stat_SUCCESS) 462 | return returnError; 463 | value &= ~(0b00000111 << 4); //Clear DRIVE_MODE bits 464 | value |= (mode << 4); //Mask in mode 465 | returnError = writeRegister(CSS811_MEAS_MODE, value); 466 | return returnError; 467 | } 468 | 469 | //Given a temp and humidity, write this data to the CSS811 for better compensation 470 | //This function expects the humidity and temp to come in as floats 471 | CCS811Core::CCS811_Status_e CCS811::setEnvironmentalData(float relativeHumidity, float temperature) 472 | { 473 | //Check for invalid temperatures 474 | if ((temperature < -25) || (temperature > 50)) 475 | return CCS811_Stat_GENERIC_ERROR; 476 | 477 | //Check for invalid humidity 478 | if ((relativeHumidity < 0) || (relativeHumidity > 100)) 479 | return CCS811_Stat_GENERIC_ERROR; 480 | 481 | uint32_t rH = relativeHumidity * 1000; //42.348 becomes 42348 482 | uint32_t temp = temperature * 1000; //23.2 becomes 23200 483 | 484 | byte envData[4]; 485 | 486 | //Split value into 7-bit integer and 9-bit fractional 487 | 488 | //Incorrect way from datasheet. 489 | //envData[0] = ((rH % 1000) / 100) > 7 ? (rH / 1000 + 1) << 1 : (rH / 1000) << 1; 490 | //envData[1] = 0; //CCS811 only supports increments of 0.5 so bits 7-0 will always be zero 491 | //if (((rH % 1000) / 100) > 2 && (((rH % 1000) / 100) < 8)) 492 | //{ 493 | // envData[0] |= 1; //Set 9th bit of fractional to indicate 0.5% 494 | //} 495 | 496 | //Correct rounding. See issue 8: https://github.com/sparkfun/Qwiic_BME280_CCS811_Combo/issues/8 497 | envData[0] = (rH + 250) / 500; 498 | envData[1] = 0; //CCS811 only supports increments of 0.5 so bits 7-0 will always be zero 499 | 500 | temp += 25000; //Add the 25C offset 501 | //Split value into 7-bit integer and 9-bit fractional 502 | //envData[2] = ((temp % 1000) / 100) > 7 ? (temp / 1000 + 1) << 1 : (temp / 1000) << 1; 503 | //envData[3] = 0; 504 | //if (((temp % 1000) / 100) > 2 && (((temp % 1000) / 100) < 8)) 505 | //{ 506 | // envData[2] |= 1; //Set 9th bit of fractional to indicate 0.5C 507 | //} 508 | 509 | //Correct rounding 510 | envData[2] = (temp + 250) / 500; 511 | envData[3] = 0; 512 | 513 | CCS811Core::CCS811_Status_e returnError = multiWriteRegister(CSS811_ENV_DATA, envData, 4); 514 | return returnError; 515 | } 516 | 517 | uint16_t CCS811::getTVOC(void) 518 | { 519 | return tVOC; 520 | } 521 | 522 | uint16_t CCS811::getCO2(void) 523 | { 524 | return CO2; 525 | } 526 | 527 | //****************************************************************************// 528 | // 529 | // The CCS811 no longer supports temperature compensation from an NTC thermistor. 530 | // NTC thermistor compensation will only work on boards purchased in 2017. 531 | // List of unsupported functions: 532 | // setRefResistance(); 533 | // readNTC(); 534 | // getResistance(); 535 | // getTemperature(); 536 | // 537 | //****************************************************************************// 538 | 539 | void CCS811::setRefResistance(float input) 540 | { 541 | refResistance = input; 542 | } 543 | 544 | CCS811Core::CCS811_Status_e CCS811::readNTC(void) 545 | { 546 | uint8_t data[4]; 547 | CCS811Core::CCS811_Status_e returnError = multiReadRegister(CSS811_NTC, data, 4); 548 | 549 | vrefCounts = ((uint16_t)data[0] << 8) | data[1]; 550 | //Serial.print("vrefCounts: "); 551 | //Serial.println(vrefCounts); 552 | ntcCounts = ((uint16_t)data[2] << 8) | data[3]; 553 | //Serial.print("ntcCounts: "); 554 | //Serial.println(ntcCounts); 555 | //Serial.print("sum: "); 556 | //Serial.println(ntcCounts + vrefCounts); 557 | resistance = ((float)ntcCounts * refResistance / (float)vrefCounts); 558 | 559 | //Code from Milan Malesevic and Zoran Stupic, 2011, 560 | //Modified by Max Mayfield, 561 | temperature = log((long)resistance); 562 | temperature = 1 / (0.001129148 + (0.000234125 * temperature) + (0.0000000876741 * temperature * temperature * temperature)); 563 | temperature = temperature - 273.15; // Convert Kelvin to Celsius 564 | 565 | return returnError; 566 | } 567 | 568 | float CCS811::getResistance(void) 569 | { 570 | return resistance; 571 | } 572 | 573 | float CCS811::getTemperature(void) 574 | { 575 | return temperature; 576 | } 577 | 578 | const char *CCS811::statusString(CCS811_Status_e stat) 579 | { 580 | CCS811_Status_e val; 581 | if (stat == CCS811_Stat_NUM) 582 | { 583 | val = stat; 584 | } 585 | else 586 | { 587 | val = stat; 588 | } 589 | 590 | switch (val) 591 | { 592 | case CCS811_Stat_SUCCESS: 593 | return "All is well."; 594 | break; 595 | case CCS811_Stat_ID_ERROR: 596 | return "ID Error"; 597 | break; 598 | case CCS811_Stat_I2C_ERROR: 599 | return "I2C Error"; 600 | break; 601 | case CCS811_Stat_INTERNAL_ERROR: 602 | return "Internal Error"; 603 | break; 604 | case CCS811_Stat_GENERIC_ERROR: 605 | return "Generic Error"; 606 | break; 607 | default: 608 | return "Unknown Status"; 609 | break; 610 | } 611 | return "None"; 612 | } 613 | -------------------------------------------------------------------------------- /src/SparkFunCCS811.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SparkFunCCS811.h 3 | CCS811 Arduino library 4 | 5 | Marshall Taylor @ SparkFun Electronics 6 | Nathan Seidle @ SparkFun Electronics 7 | 8 | April 4, 2017 9 | 10 | https://github.com/sparkfun/CCS811_Air_Quality_Breakout 11 | https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library 12 | 13 | Resources: 14 | Uses Wire.h for i2c operation 15 | 16 | Development environment specifics: 17 | Arduino IDE 1.8.1 18 | 19 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 20 | 21 | Please review the LICENSE.md file included with this example. If you have any questions 22 | or concerns with licensing, please contact techsupport@sparkfun.com. 23 | 24 | Distributed as-is; no warranty is given. 25 | ******************************************************************************/ 26 | 27 | #ifndef __CCS811_H__ 28 | #define __CCS811_H__ 29 | 30 | #include "stdint.h" 31 | #include 32 | 33 | //Register addresses 34 | #define CSS811_STATUS 0x00 35 | #define CSS811_MEAS_MODE 0x01 36 | #define CSS811_ALG_RESULT_DATA 0x02 37 | #define CSS811_RAW_DATA 0x03 38 | #define CSS811_ENV_DATA 0x05 39 | #define CSS811_NTC 0x06 //NTC compensation no longer supported 40 | #define CSS811_THRESHOLDS 0x10 41 | #define CSS811_BASELINE 0x11 42 | #define CSS811_HW_ID 0x20 43 | #define CSS811_HW_VERSION 0x21 44 | #define CSS811_FW_BOOT_VERSION 0x23 45 | #define CSS811_FW_APP_VERSION 0x24 46 | #define CSS811_ERROR_ID 0xE0 47 | #define CSS811_APP_START 0xF4 48 | #define CSS811_SW_RESET 0xFF 49 | 50 | //This is the core operational class of the driver. 51 | // CCS811Core contains only read and write operations towards the sensor. 52 | // To use the higher level functions, use the class CCS811 which inherits 53 | // this class. 54 | 55 | class CCS811Core 56 | { 57 | public: 58 | // Return values 59 | typedef enum 60 | { 61 | CCS811_Stat_SUCCESS, 62 | CCS811_Stat_ID_ERROR, 63 | CCS811_Stat_I2C_ERROR, 64 | CCS811_Stat_INTERNAL_ERROR, 65 | CCS811_Stat_NUM, 66 | CCS811_Stat_GENERIC_ERROR 67 | //... 68 | } CCS811_Status_e; 69 | 70 | CCS811Core(uint8_t); 71 | ~CCS811Core() = default; 72 | 73 | void setI2CAddress(uint8_t address){ 74 | I2CAddress = address; 75 | } 76 | CCS811_Status_e beginCore(TwoWire &wirePort); 77 | 78 | //***Reading functions***// 79 | 80 | //readRegister reads one 8-bit register 81 | CCS811_Status_e readRegister(uint8_t offset, uint8_t *outputPointer); 82 | //multiReadRegister takes a uint8 array address as input and performs 83 | // a number of consecutive reads 84 | CCS811_Status_e multiReadRegister(uint8_t offset, uint8_t *outputPointer, uint8_t length); 85 | 86 | //***Writing functions***// 87 | 88 | //Writes an 8-bit byte; 89 | CCS811_Status_e writeRegister(uint8_t offset, uint8_t dataToWrite); 90 | //multiWriteRegister takes a uint8 array address as input and performs 91 | // a number of consecutive writes 92 | CCS811_Status_e multiWriteRegister(uint8_t offset, uint8_t *inputPointer, uint8_t length); 93 | 94 | protected: 95 | //Variables 96 | TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware 97 | uint8_t I2CAddress; 98 | }; 99 | 100 | //This is the highest level class of the driver. 101 | // 102 | // class CCS811 inherits the CCS811Core and makes use of the beginCore() 103 | //method through its own begin() method. It also contains user settings/values. 104 | 105 | class CCS811 : public CCS811Core 106 | { 107 | public: 108 | CCS811(uint8_t); 109 | CCS811(); 110 | 111 | //Call to check for errors, start app, and set default mode 1 112 | bool begin(TwoWire &wirePort = Wire); //Use the Wire hardware by default 113 | CCS811_Status_e beginWithStatus(TwoWire &wirePort = Wire); //Use the Wire hardware by default 114 | const char *statusString(CCS811_Status_e stat = CCS811_Stat_NUM); // Returns a human-readable status message. Defaults to status member, but prints string for supplied status if supplied 115 | 116 | CCS811_Status_e readAlgorithmResults(void); 117 | bool checkForStatusError(void); 118 | bool dataAvailable(void); 119 | bool appValid(void); 120 | uint8_t getErrorRegister(void); 121 | uint16_t getBaseline(void); 122 | CCS811_Status_e setBaseline(uint16_t); 123 | CCS811_Status_e enableInterrupts(void); 124 | CCS811_Status_e disableInterrupts(void); 125 | CCS811_Status_e setDriveMode(uint8_t mode); 126 | CCS811_Status_e setEnvironmentalData(float relativeHumidity, float temperature); 127 | void setRefResistance(float); //Unsupported feature. Refer to CPP file for more information. 128 | CCS811_Status_e readNTC(void); //Unsupported feature. Refer to CPP file for more information. 129 | uint16_t getTVOC(void); 130 | uint16_t getCO2(void); 131 | float getResistance(void); //Unsupported feature. Refer to CPP file for more information. 132 | float getTemperature(void); //Unsupported feature. Refer to CPP file for more information. 133 | 134 | private: 135 | //These are the air quality values obtained from the sensor 136 | float refResistance; //Unsupported feature. Refer to CPP file for more information. 137 | float resistance; //Unsupported feature. Refer to CPP file for more information. 138 | uint16_t tVOC; 139 | uint16_t CO2; 140 | uint16_t vrefCounts = 0; 141 | uint16_t ntcCounts = 0; 142 | float temperature; 143 | }; 144 | 145 | #endif // End of definition check 146 | --------------------------------------------------------------------------------