Commit 715f636c authored by Eric Duminil's avatar Eric Duminil
Browse files

Remove SCD30 lib. Code is broken

parent 6af62412
......@@ -6,9 +6,6 @@
#include "sensor_console.h"
#include <Wire.h>
// The SCD30 from Sensirion is a high quality Nondispersive Infrared (NDIR) based CO₂ sensor capable of detecting 400 to 10000ppm with an accuracy of ±(30ppm+3%).
// https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
#include "src/lib/SparkFun_SCD30_Arduino_Library/src/SparkFun_SCD30_Arduino_Library.h" // From: http://librarymanager/All#SparkFun_SCD30
#include "src/lib/S8_UART/s8_uart.h"
namespace config {
......
SparkFun License Information
============================
SparkFun uses two different licenses for our files — one for hardware and one for code.
Hardware
---------
**SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).**
Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode).
You are free to:
Share — copy and redistribute the material in any medium or format
Adapt — remix, transform, and build upon the material
for any purpose, even commercially.
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
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.
ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
Notices:
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.
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.
Code
--------
**SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).**
The MIT License (MIT)
Copyright (c) 2020 SparkFun Electronics
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SparkFun SCD30 CO₂ Sensor Library
===========================================================
![SparkFun SCD30 CO₂ Sensor](https://cdn.sparkfun.com//assets/parts/1/2/9/8/4/SparkFun_Sensirion_SCD30.jpg)
[*SparkX CO₂ Humidity and Temperature Sensor - SCD30 (SPX-14751)*](https://www.sparkfun.com/products/14751)
The SCD30 from Sensirion is a high quality [NDIR](https://en.wikipedia.org/wiki/Nondispersive_infrared_sensor) based CO₂ sensor capable of detecting 400 to 10000ppm with an accuracy of ±(30ppm+3%). In order to improve accuracy the SCD30 has temperature and humidity sensing built-in, as well as commands to compensate for altitude.
We've written an Arduino library to make reading the CO₂, humidity, and temperature very easy. It can be downloaded through the Arduino Library manager: search for 'SparkFun SCD30'. We recommend using a [Qwiic Breadboard Cable](https://www.sparkfun.com/products/14425) to connect the SCD30 to a Qwiic compatible board. The Ye*LL*ow wire goes in the SC*L* pin. The SCD30 also supports a serial interface but we haven't worked with it.
The CO₂ sensor works very well and for additional accuracy the SCD30 accepts ambient pressure readings. We recommend using the SCD30 in conjunction with the [Qwiic Pressure Sensor - MS5637](https://www.sparkfun.com/products/14688) or the [Qwiic Environmental Sensor - BME680](https://www.sparkfun.com/products/14570) to obtain the current barometric pressure.
Note: The SCD30 has an automatic self-calibration routine. Sensirion recommends 7 days of continuous readings with at least 1 hour a day of 'fresh air' for self-calibration to complete.
Library written by Nathan Seidle ([SparkFun](http://www.sparkfun.com)).
Thanks to!
* [jobr97](https://github.com/jobr97) for adding the getTemperatureOffset() method
* [bobobo1618](https://github.com/bobobo1618) for writing a CRC check and improving the return values of the library
* [labeneator](https://github.com/labeneator) for adding method to disable calibrate at begin
* [AndreasExner](https://github.com/AndreasExner) for adding [reset and getAutoSelfCalibration methods](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/17)
* [awatterott](https://github.com/awatterott) for adding [getAltitudeCompensation()](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/18)
* [jogi-k](https://github.com/jogi-k) for adding [teensy i2clib](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/19) support
* [paulvha](https://github.com/paulvha) for the suggestions and corrections in [his version of the library](https://github.com/paulvha/scd30)
* [yamamaya](https://github.com/yamamaya) for the [3ms delay](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/24)
Repository Contents
-------------------
* **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE.
* **/src** - Source files for the library (.cpp, .h).
* **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE.
* **library.properties** - General library properties for the Arduino package manager.
Documentation
--------------
* **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library.
License Information
-------------------
This product is _**open source**_!
Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license.
Distributed as-is; no warranty is given.
- Your friends at SparkFun.
#######################################
# Syntax Coloring Map
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
SCD30 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
SCD30 KEYWORD2
begin KEYWORD2
isConnected KEYWORD2
enableDebugging KEYWORD2
beginMeasuring KEYWORD2
StopMeasurement KEYWORD2
setAmbientPressure KEYWORD2
getSettingValue KEYWORD2
getFirmwareVersion KEYWORD2
getCO2 KEYWORD2
getHumidity KEYWORD2
getTemperature KEYWORD2
getMeasurementInterval KEYWORD2
setMeasurementInterval KEYWORD2
getAltitudeCompensation KEYWORD2
setAltitudeCompensation KEYWORD2
getAutoSelfCalibration KEYWORD2
setAutoSelfCalibration KEYWORD2
getForcedRecalibration KEYWORD2
setForcedRecalibrationFactor KEYWORD2
getTemperatureOffset KEYWORD2
setTemperatureOffset KEYWORD2
dataAvailable KEYWORD2
readMeasurement KEYWORD2
reset KEYWORD2
sendCommand KEYWORD2
readRegister KEYWORD2
computeCRC8 KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
SCD30_ADDRESS LITERAL1
COMMAND_CONTINUOUS_MEASUREMENT LITERAL1
COMMAND_SET_MEASUREMENT_INTERVAL LITERAL1
COMMAND_GET_DATA_READY LITERAL1
COMMAND_READ_MEASUREMENT LITERAL1
COMMAND_AUTOMATIC_SELF_CALIBRATION LITERAL1
COMMAND_SET_FORCED_RECALIBRATION_FACTOR LITERAL1
COMMAND_SET_TEMPERATURE_OFFSET LITERAL1
COMMAND_SET_ALTITUDE_COMPENSATION LITERAL1
COMMAND_RESET LITERAL1
COMMAND_STOP_MEAS LITERAL1
COMMAND_READ_FW_VER LITERAL1
name=SparkFun SCD30 Arduino Library
version=1.0.17
author=SparkFun Electronics
maintainer=SparkFun Electronics <sparkfun.com>
sentence=Library for the Sensirion SCD30 CO2 Sensor
paragraph=An Arduinolibrary for the SCD30 CO2 sensor from Sensirion. The SCD30 is a high quality <a href="https://en.wikipedia.org/wiki/Nondispersive_infrared_sensor">NDIR</a> based CO₂ sensor capable of detecting 400 to 10000ppm with an accuracy of ±(30ppm+3%). In order to improve accuracy the SCD30 has temperature and humidity sensing built-in, as well as commands to set the current altitude.<br><br>Get the SCD30 <a href="https://www.sparkfun.com/products/14751">here</a>.
category=Sensors
url=https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
architectures=*
/*
This is a library written for the SCD30
SparkFun sells these at its website: www.sparkfun.com
Do you like this library? Help support SparkFun. Buy a board!
https://www.sparkfun.com/products/14751
Written by Nathan Seidle @ SparkFun Electronics, May 22nd, 2018
Updated February 1st 2021 to include some of the features of paulvha's version of the library
(while maintaining backward-compatibility):
https://github.com/paulvha/scd30
Thank you Paul!
The SCD30 measures CO2 with accuracy of +/- 30ppm.
This library handles the initialization of the SCD30 and outputs
CO2 levels, relative humidty, and temperature.
https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
Development environment specifics:
Arduino IDE 1.8.13
SparkFun code, firmware, and software is released under the MIT License.
Please see LICENSE.md for more details.
*/
#include "SparkFun_SCD30_Arduino_Library.h"
SCD30::SCD30(void)
{
// Constructor
}
// Initialize the Serial port
#ifdef USE_TEENSY3_I2C_LIB
bool SCD30::begin(i2c_t3 &wirePort, bool autoCalibrate, bool measBegin)
#else
bool SCD30::begin(TwoWire &wirePort, bool autoCalibrate, bool measBegin)
#endif
{
_i2cPort = &wirePort; // Grab which port the user wants us to use
/* Especially during obtaining the ACK BIT after a byte sent the SCD30 is using clock stretching (but NOT only there)!
* The need for clock stretching is described in the Sensirion_CO2_Sensors_SCD30_Interface_Description.pdf
*
* The default clock stretch (maximum wait time) on the ESP8266-library (2.4.2) is 230us which is set during _i2cPort->begin();
* In the current implementation of the ESP8266 I2C driver there is NO error message when this time expired, while
* the clock stretch is still happening, causing uncontrolled behaviour of the hardware combination.
*
* To set ClockStretchlimit() a check for ESP8266 boards has been added in the driver.
*
* With setting to 20000, we set a max timeout of 20mS (> 20x the maximum measured) basically disabling the time-out
* and now wait for clock stretch to be controlled by the client.
*/
#if defined(ARDUINO_ARCH_ESP8266)
_i2cPort->setClockStretchLimit(200000);
#endif
if (isConnected() == false)
return (false);
if (measBegin == false) // Exit now if measBegin is false
return (true);
// Check for device to respond correctly
if (beginMeasuring() == true) // Start continuous measurements
{
setMeasurementInterval(2); // 2 seconds between measurements
setAutoSelfCalibration(autoCalibrate); // Enable auto-self-calibration
return (true);
}
return (false); // Something went wrong
}
// Returns true if device responds to a firmware request
bool SCD30::isConnected()
{
uint16_t fwVer;
if (getFirmwareVersion(&fwVer) == false) // Read the firmware version. Return false if the CRC check fails.
return (false);
if (_printDebug == true)
{
_debugPort->print(F("Firmware version 0x"));
_debugPort->println(fwVer, HEX);
}
return (true);
}
// Calling this function with nothing sets the debug port to Serial
// You can also call it with other streams like Serial1, SerialUSB, etc.
void SCD30::enableDebugging(Stream &debugPort)
{
_debugPort = &debugPort;
_printDebug = true;
}
// Returns the latest available CO2 level
// If the current level has already been reported, trigger a new read
uint16_t SCD30::getCO2(void)
{
if (co2HasBeenReported == true) // Trigger a new read
{
if (readMeasurement() == false) // Pull in new co2, humidity, and temp into global vars
co2 = 0; // Failed to read sensor
}
co2HasBeenReported = true;
return (uint16_t)co2; // Cut off decimal as co2 is 0 to 10,000
}
// Returns the latest available humidity
// If the current level has already been reported, trigger a new read
float SCD30::getHumidity(void)
{
if (humidityHasBeenReported == true) // Trigger a new read
if (readMeasurement() == false) // Pull in new co2, humidity, and temp into global vars
humidity = 0; // Failed to read sensor
humidityHasBeenReported = true;
return humidity;
}
// Returns the latest available temperature
// If the current level has already been reported, trigger a new read
float SCD30::getTemperature(void)
{
if (temperatureHasBeenReported == true) // Trigger a new read
if (readMeasurement() == false) // Pull in new co2, humidity, and temp into global vars
temperature = 0; // Failed to read sensor
temperatureHasBeenReported = true;
return temperature;
}
// Enables or disables the ASC
bool SCD30::setAutoSelfCalibration(bool enable)
{
if (enable)
return sendCommand(COMMAND_AUTOMATIC_SELF_CALIBRATION, 1); // Activate continuous ASC
else
return sendCommand(COMMAND_AUTOMATIC_SELF_CALIBRATION, 0); // Deactivate continuous ASC
}
// Set the forced recalibration factor. See 1.3.7.
// The reference CO2 concentration has to be within the range 400 ppm ≤ cref(CO2) ≤ 2000 ppm.
bool SCD30::setForcedRecalibrationFactor(uint16_t concentration)
{
if (concentration < 400 || concentration > 2000)
{
return false; // Error check.
}
return sendCommand(COMMAND_SET_FORCED_RECALIBRATION_FACTOR, concentration);
}
// Get the temperature offset. See 1.3.8.
float SCD30::getTemperatureOffset(void)
{
uint16_t response = readRegister(COMMAND_SET_TEMPERATURE_OFFSET);
union
{
int16_t signed16;
uint16_t unsigned16;
} signedUnsigned; // Avoid any ambiguity casting int16_t to uint16_t
signedUnsigned.signed16 = response;
return (((float)signedUnsigned.signed16) / 100.0);
}
// Set the temperature offset to remove module heating from temp reading
bool SCD30::setTemperatureOffset(float tempOffset)
{
// Temp offset is only positive. See: https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/issues/27#issuecomment-971986826
//"The SCD30 offset temperature is obtained by subtracting the reference temperature from the SCD30 output temperature"
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/9.5_CO2/Sensirion_CO2_Sensors_SCD30_Low_Power_Mode.pdf
if (tempOffset < 0.0)
return (false);
uint16_t value = tempOffset * 100;
return sendCommand(COMMAND_SET_TEMPERATURE_OFFSET, value);
}
// Get the altitude compenstation. See 1.3.9.
uint16_t SCD30::getAltitudeCompensation(void)
{
return readRegister(COMMAND_SET_ALTITUDE_COMPENSATION);
}
// Set the altitude compenstation. See 1.3.9.
bool SCD30::setAltitudeCompensation(uint16_t altitude)
{
return sendCommand(COMMAND_SET_ALTITUDE_COMPENSATION, altitude);
}
// Set the pressure compenstation. This is passed during measurement startup.
// mbar can be 700 to 1200
bool SCD30::setAmbientPressure(uint16_t pressure_mbar)
{
if (pressure_mbar < 700 || pressure_mbar > 1200)
{
return false;
}
return sendCommand(COMMAND_CONTINUOUS_MEASUREMENT, pressure_mbar);
}
// SCD30 soft reset
void SCD30::reset()
{
sendCommand(COMMAND_RESET);
}
// Get the current ASC setting
bool SCD30::getAutoSelfCalibration()
{
uint16_t response = readRegister(COMMAND_AUTOMATIC_SELF_CALIBRATION);
if (response == 1)
{
return true;
}
else
{
return false;
}
}
// Begins continuous measurements
// Continuous measurement status is saved in non-volatile memory. When the sensor
// is powered down while continuous measurement mode is active SCD30 will measure
// continuously after repowering without sending the measurement command.
// Returns true if successful
bool SCD30::beginMeasuring(uint16_t pressureOffset)
{
return (sendCommand(COMMAND_CONTINUOUS_MEASUREMENT, pressureOffset));
}
// Overload - no pressureOffset
bool SCD30::beginMeasuring(void)
{
return (beginMeasuring(0));
}
// Stop continuous measurement
bool SCD30::StopMeasurement(void)
{
return (sendCommand(COMMAND_STOP_MEAS));
}
// Sets interval between measurements
// 2 seconds to 1800 seconds (30 minutes)
bool SCD30::setMeasurementInterval(uint16_t interval)
{
return sendCommand(COMMAND_SET_MEASUREMENT_INTERVAL, interval);
}
// Gets interval between measurements
// 2 seconds to 1800 seconds (30 minutes)
uint16_t SCD30::getMeasurementInterval(void)
{
uint16_t interval = 0;
getSettingValue(COMMAND_SET_MEASUREMENT_INTERVAL, &interval);
return (interval);
}
// Returns true when data is available
bool SCD30::dataAvailable()
{
uint16_t response = readRegister(COMMAND_GET_DATA_READY);
if (response == 1)
return (true);
return (false);
}
// Get 18 bytes from SCD30
// Updates global variables with floats
// Returns true if success
bool SCD30::readMeasurement()
{
// Verify we have data from the sensor
if (dataAvailable() == false)
return (false);
ByteToFl tempCO2;
tempCO2.value = 0;
ByteToFl tempHumidity;
tempHumidity.value = 0;
ByteToFl tempTemperature;
tempTemperature.value = 0;
_i2cPort->beginTransmission(SCD30_ADDRESS);
_i2cPort->write(COMMAND_READ_MEASUREMENT >> 8); // MSB
_i2cPort->write(COMMAND_READ_MEASUREMENT & 0xFF); // LSB
if (_i2cPort->endTransmission() != 0)
return (0); // Sensor did not ACK
delay(3);
const uint8_t receivedBytes = _i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)18);
bool error = false;
if (_i2cPort->available())
{
byte bytesToCrc[2];
for (byte x = 0; x < 18; x++)
{
byte incoming = _i2cPort->read();
switch (x)
{
case 0:
case 1:
case 3:
case 4:
tempCO2.array[x < 3 ? 3 - x : 4 - x] = incoming;
bytesToCrc[x % 3] = incoming;
break;
case 6:
case 7:
case 9:
case 10:
tempTemperature.array[x < 9 ? 9 - x : 10 - x] = incoming;
bytesToCrc[x % 3] = incoming;
break;
case 12:
case 13:
case 15:
case 16:
tempHumidity.array[x < 15 ? 15 - x : 16 - x] = incoming;
bytesToCrc[x % 3] = incoming;
break;
default:
// Validate CRC
uint8_t foundCrc = computeCRC8(bytesToCrc, 2);
if (foundCrc != incoming)
{
if (_printDebug == true)
{
_debugPort->print(F("readMeasurement: found CRC in byte "));
_debugPort->print(x);
_debugPort->print(F(", expected 0x"));
_debugPort->print(foundCrc, HEX);
_debugPort->print(F(", got 0x"));
_debugPort->println(incoming, HEX);
}
error = true;
}
break;
}
}
}
else
{
if (_printDebug == true)
{
_debugPort->print(F("readMeasurement: no SCD30 data found from I2C, i2c claims we should receive "));
_debugPort->print(receivedBytes);
_debugPort->println(F(" bytes"));
}
return false;
}
if (error)
{
if (_printDebug == true)
_debugPort->println(F("readMeasurement: encountered error reading SCD30 data."));
return false;
}
// Now copy the uint32s into their associated floats
co2 = tempCO2.value;
temperature = tempTemperature.value;
humidity = tempHumidity.value;
// Mark our global variables as fresh
co2HasBeenReported = false;
humidityHasBeenReported = false;
temperatureHasBeenReported = false;
return (true); // Success! New data available in globals.
}
// Gets a setting by reading the appropriate register.
// Returns true if the CRC is valid.
bool SCD30::getSettingValue(uint16_t registerAddress, uint16_t *val)
{
_i2cPort->beginTransmission(SCD30_ADDRESS);
_i2cPort->write(registerAddress >> 8); // MSB
_i2cPort->write(registerAddress & 0xFF); // LSB
if (_i2cPort->endTransmission() != 0)
return (false); // Sensor did not ACK
delay(3);
_i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)3); // Request data and CRC
if (_i2cPort->available())
{
uint8_t data[2];
data[0] = _i2cPort->read();
data[1] = _i2cPort->read();
uint8_t crc = _i2cPort->read();
*val = (uint16_t)data[0] << 8 | data[1];
uint8_t expectedCRC = computeCRC8(data, 2);
if (crc == expectedCRC) // Return true if CRC check is OK
return (true);
if (_printDebug == true)
{
_debugPort->print(F("getSettingValue: CRC fail: expected 0x"));
_debugPort->print(expectedCRC, HEX);
_debugPort->print(F(", got 0x"));
_debugPort->println(crc, HEX);
}
}
return (false);
}
// Gets two bytes from SCD30
uint16_t SCD30::readRegister(uint16_t registerAddress)
{
_i2cPort->beginTransmission(SCD30_ADDRESS);
_i2cPort->write(registerAddress >> 8); // MSB
_i2cPort->write(registerAddress & 0xFF); // LSB
if (_i2cPort->endTransmission() != 0)
return (0); // Sensor did not ACK
delay(3);
_i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)2);
if (_i2cPort->available())
{
uint8_t msb = _i2cPort->read();
uint8_t lsb = _i2cPort->read();
return ((uint16_t)msb << 8 | lsb);
}
return (0); // Sensor did not respond
}
// Sends a command along with arguments and CRC
bool SCD30::sendCommand(uint16_t command, uint16_t arguments)
{
uint8_t data[2];
data[0] = arguments >> 8;
data[1] = arguments & 0xFF;
uint8_t crc = computeCRC8(data, 2); // Calc CRC on the arguments only, not the command
_i2cPort->beginTransmission(SCD30_ADDRESS);
_i2cPort->write(command >> 8); // MSB
_i2cPort->write(command & 0xFF); // LSB
_i2cPort->write(arguments >> 8); // MSB
_i2cPort->write(arguments & 0xFF); // LSB
_i2cPort->write(crc);
if (_i2cPort->endTransmission() != 0)
return (false); // Sensor did not ACK
return (true);
}
// Sends just a command, no arguments, no CRC
bool SCD30::sendCommand(uint16_t command)
{
_i2cPort->beginTransmission(SCD30_ADDRESS);
_i2cPort->write(command >> 8); // MSB
_i2cPort->write(command & 0xFF); // LSB
if (_i2cPort->endTransmission() != 0)
return (false); // Sensor did not ACK
return (true);
}
// Given an array and a number of bytes, this calculate CRC8 for those bytes
// CRC is only calc'd on the data portion (two bytes) of the four bytes being sent
// From: http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html
// Tested with: http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
// x^8+x^5+x^4+1 = 0x31
uint8_t SCD30::computeCRC8(uint8_t data[], uint8_t len)
{
uint8_t crc = 0xFF; // Init with 0xFF
for (uint8_t x = 0; x < len; x++)
{
crc ^= data[x]; // XOR-in the next input byte
for (uint8_t i = 0; i < 8; i++)
{
if ((crc & 0x80) != 0)
crc = (uint8_t)((crc << 1) ^ 0x31);
else
crc <<= 1;
}
}
return crc; // No output reflection
}
/*
This is a library written for the SCD30
SparkFun sells these at its website: www.sparkfun.com
Do you like this library? Help support SparkFun. Buy a board!
https://www.sparkfun.com/products/14751
Written by Nathan Seidle @ SparkFun Electronics, May 22nd, 2018
Updated February 1st 2021 to include some of the features of paulvha's version of the library
(while maintaining backward-compatibility):
https://github.com/paulvha/scd30
Thank you Paul!
The SCD30 measures CO2 with accuracy of +/- 30ppm.
This library handles the initialization of the SCD30 and outputs
CO2 levels, relative humidty, and temperature.
https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
Development environment specifics:
Arduino IDE 1.8.13
SparkFun code, firmware, and software is released under the MIT License.
Please see LICENSE.md for more details.
*/
#ifndef __SparkFun_SCD30_ARDUINO_LIBARARY_H__
#define __SparkFun_SCD30_ARDUINO_LIBARARY_H__
// Uncomment the next #define if using an Teensy >= 3 or Teensy LC and want to use the dedicated I2C-Library for it
// Then you also have to include <i2c_t3.h> on your application instead of <Wire.h>
// #define USE_TEENSY3_I2C_LIB
#include "Arduino.h"
#ifdef USE_TEENSY3_I2C_LIB
#include <i2c_t3.h>
#else
#include <Wire.h>
#endif
// The default I2C address for the SCD30 is 0x61.
#define SCD30_ADDRESS 0x61
// Available commands
#define COMMAND_CONTINUOUS_MEASUREMENT 0x0010
#define COMMAND_SET_MEASUREMENT_INTERVAL 0x4600
#define COMMAND_GET_DATA_READY 0x0202
#define COMMAND_READ_MEASUREMENT 0x0300
#define COMMAND_AUTOMATIC_SELF_CALIBRATION 0x5306
#define COMMAND_SET_FORCED_RECALIBRATION_FACTOR 0x5204
#define COMMAND_SET_TEMPERATURE_OFFSET 0x5403
#define COMMAND_SET_ALTITUDE_COMPENSATION 0x5102
#define COMMAND_RESET 0xD304 // Soft reset
#define COMMAND_STOP_MEAS 0x0104
#define COMMAND_READ_FW_VER 0xD100
typedef union
{
byte array[4];
float value;
} ByteToFl; // paulvha
class SCD30
{
public:
SCD30(void);
bool begin(bool autoCalibrate) { return begin(Wire, autoCalibrate); }
#ifdef USE_TEENSY3_I2C_LIB
bool begin(i2c_t3 &wirePort = Wire, bool autoCalibrate = false, bool measBegin = true); // By default use Wire port
#else
bool begin(TwoWire &wirePort = Wire, bool autoCalibrate = false, bool measBegin = true); // By default use Wire port
#endif
bool isConnected();
void enableDebugging(Stream &debugPort = Serial); // Turn on debug printing. If user doesn't specify then Serial will be used.
bool beginMeasuring(uint16_t pressureOffset);
bool beginMeasuring(void);
bool StopMeasurement(void); // paulvha
bool setAmbientPressure(uint16_t pressure_mbar);
bool getSettingValue(uint16_t registerAddress, uint16_t *val);
bool getFirmwareVersion(uint16_t *val) { return (getSettingValue(COMMAND_READ_FW_VER, val)); }
uint16_t getCO2(void);
float getHumidity(void);
float getTemperature(void);
uint16_t getMeasurementInterval(void);
bool getMeasurementInterval(uint16_t *val) { return (getSettingValue(COMMAND_SET_MEASUREMENT_INTERVAL, val)); }
bool setMeasurementInterval(uint16_t interval);
uint16_t getAltitudeCompensation(void);
bool getAltitudeCompensation(uint16_t *val) { return (getSettingValue(COMMAND_SET_ALTITUDE_COMPENSATION, val)); }
bool setAltitudeCompensation(uint16_t altitude);
bool getAutoSelfCalibration(void);
bool setAutoSelfCalibration(bool enable);
bool getForcedRecalibration(uint16_t *val) { return (getSettingValue(COMMAND_SET_FORCED_RECALIBRATION_FACTOR, val)); }
bool setForcedRecalibrationFactor(uint16_t concentration);
float getTemperatureOffset(void);
bool getTemperatureOffset(uint16_t *val) { return (getSettingValue(COMMAND_SET_TEMPERATURE_OFFSET, val)); }
bool setTemperatureOffset(float tempOffset);
bool dataAvailable();
bool readMeasurement();
void reset();
bool sendCommand(uint16_t command, uint16_t arguments);
bool sendCommand(uint16_t command);
uint16_t readRegister(uint16_t registerAddress);
uint8_t computeCRC8(uint8_t data[], uint8_t len);
private:
// Variables
#ifdef USE_TEENSY3_I2C_LIB
i2c_t3 *_i2cPort; // The generic connection to user's chosen I2C hardware
#else
TwoWire *_i2cPort; // The generic connection to user's chosen I2C hardware
#endif
// Global main datums
float co2 = 0;
float temperature = 0;
float humidity = 0;
// These track the staleness of the current data
// This allows us to avoid calling readMeasurement() every time individual datums are requested
bool co2HasBeenReported = true;
bool humidityHasBeenReported = true;
bool temperatureHasBeenReported = true;
// Debug
Stream *_debugPort; // The stream to send debug messages to if enabled. Usually Serial.
boolean _printDebug = false; // Flag to print debugging variables
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment