diff --git a/src/SparkFun_SCD30_Arduino_Library.cpp b/src/SparkFun_SCD30_Arduino_Library.cpp index 69f0396..c61eca6 100644 --- a/src/SparkFun_SCD30_Arduino_Library.cpp +++ b/src/SparkFun_SCD30_Arduino_Library.cpp @@ -7,9 +7,9 @@ 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! + (while maintaining backward-compatibility): + https://github.com/paulvha/scd30 + Thank you Paul! The SCD30 measures CO2 with accuracy of +/- 30ppm. @@ -32,14 +32,14 @@ SCD30::SCD30(void) // Constructor } -//Initialize the Serial port +// 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 + _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 @@ -71,83 +71,82 @@ bool SCD30::begin(TwoWire &wirePort, bool autoCalibrate, bool measBegin) if (measBegin == false) // Exit now if measBegin is false return (true); - //Check for device to respond correctly - if (beginMeasuring() == true) //Start continuous measurements + // Check for device to respond correctly + if (beginMeasuring() == true) // Start continuous measurements { - setMeasurementInterval(2); //2 seconds between measurements - setAutoSelfCalibration(autoCalibrate); //Enable auto-self-calibration + setMeasurementInterval(2); // 2 seconds between measurements + setAutoSelfCalibration(autoCalibrate); // Enable auto-self-calibration return (true); } - return (false); //Something went wrong + return (false); // Something went wrong } -//Calling this function with nothing sets the debug port to Serial -//You can also call it with other streams like Serial1, SerialUSB, etc. +// 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 +// 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 - readMeasurement(); //Pull in new co2, humidity, and temp into global vars - + if (co2HasBeenReported == true) // Trigger a new read + readMeasurement(); // Pull in new co2, humidity, and temp into global vars co2HasBeenReported = true; - return (uint16_t)co2; //Cut off decimal as co2 is 0 to 10,000 + 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 +// 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 - readMeasurement(); //Pull in new co2, humidity, and temp into global vars + if (humidityHasBeenReported == true) // Trigger a new read + readMeasurement(); // Pull in new co2, humidity, and temp into global vars humidityHasBeenReported = true; return humidity; } -//Returns the latest available temperature -//If the current level has already been reported, trigger a new read +// 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 - readMeasurement(); //Pull in new co2, humidity, and temp into global vars + if (temperatureHasBeenReported == true) // Trigger a new read + readMeasurement(); // Pull in new co2, humidity, and temp into global vars temperatureHasBeenReported = true; return temperature; } -//Enables or disables the ASC +// Enables or disables the ASC bool SCD30::setAutoSelfCalibration(bool enable) { if (enable) - return sendCommand(COMMAND_AUTOMATIC_SELF_CALIBRATION, 1); //Activate continuous ASC + return sendCommand(COMMAND_AUTOMATIC_SELF_CALIBRATION, 1); // Activate continuous ASC else - return sendCommand(COMMAND_AUTOMATIC_SELF_CALIBRATION, 0); //Deactivate continuous ASC + 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. +// 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 false; // Error check. } return sendCommand(COMMAND_SET_FORCED_RECALIBRATION_FACTOR, concentration); } -//Get the temperature offset. See 1.3.8. +// Get the temperature offset. See 1.3.8. float SCD30::getTemperatureOffset(void) { uint16_t response = readRegister(COMMAND_SET_TEMPERATURE_OFFSET); @@ -162,34 +161,35 @@ float SCD30::getTemperatureOffset(void) return (((float)signedUnsigned.signed16) / 100.0); } -//Set the temperature offset to remove module heating from temp reading +// 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 + // 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 + // 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); + 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. +// 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. +// 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 +// 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) @@ -219,17 +219,17 @@ bool SCD30::getAutoSelfCalibration() } } -//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 +// 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 +// Overload - no pressureOffset bool SCD30::beginMeasuring(void) { return (beginMeasuring(0)); @@ -241,15 +241,15 @@ bool SCD30::StopMeasurement(void) return (sendCommand(COMMAND_STOP_MEAS)); } -//Sets interval between measurements -//2 seconds to 1800 seconds (30 minutes) +// 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) +// Gets interval between measurements +// 2 seconds to 1800 seconds (30 minutes) uint16_t SCD30::getMeasurementInterval(void) { uint16_t interval = 0; @@ -257,7 +257,7 @@ uint16_t SCD30::getMeasurementInterval(void) return (interval); } -//Returns true when data is available +// Returns true when data is available bool SCD30::dataAvailable() { uint16_t response = readRegister(COMMAND_GET_DATA_READY); @@ -267,12 +267,12 @@ bool SCD30::dataAvailable() return (false); } -//Get 18 bytes from SCD30 -//Updates global variables with floats -//Returns true if success +// Get 18 bytes from SCD30 +// Updates global variables with floats +// Returns true if success bool SCD30::readMeasurement() { - //Verify we have data from the sensor + // Verify we have data from the sensor if (dataAvailable() == false) return (false); @@ -284,10 +284,10 @@ bool SCD30::readMeasurement() tempTemperature.value = 0; _i2cPort->beginTransmission(SCD30_ADDRESS); - _i2cPort->write(COMMAND_READ_MEASUREMENT >> 8); //MSB - _i2cPort->write(COMMAND_READ_MEASUREMENT & 0xFF); //LSB + _i2cPort->write(COMMAND_READ_MEASUREMENT >> 8); // MSB + _i2cPort->write(COMMAND_READ_MEASUREMENT & 0xFF); // LSB if (_i2cPort->endTransmission() != 0) - return (0); //Sensor did not ACK + return (0); // Sensor did not ACK delay(3); @@ -324,7 +324,7 @@ bool SCD30::readMeasurement() bytesToCrc[x % 3] = incoming; break; default: - //Validate CRC + // Validate CRC uint8_t foundCrc = computeCRC8(bytesToCrc, 2); if (foundCrc != incoming) { @@ -360,28 +360,28 @@ bool SCD30::readMeasurement() _debugPort->println(F("readMeasurement: encountered error reading SCD30 data.")); return false; } - //Now copy the uint32s into their associated floats + // Now copy the uint32s into their associated floats co2 = tempCO2.value; temperature = tempTemperature.value; humidity = tempHumidity.value; - //Mark our global variables as fresh + // Mark our global variables as fresh co2HasBeenReported = false; humidityHasBeenReported = false; temperatureHasBeenReported = false; - return (true); //Success! New data available in globals. + return (true); // Success! New data available in globals. } -//Gets a setting by reading the appropriate register. -//Returns true if the CRC is valid. +// 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 + _i2cPort->write(registerAddress >> 8); // MSB + _i2cPort->write(registerAddress & 0xFF); // LSB if (_i2cPort->endTransmission() != 0) - return (false); //Sensor did not ACK + return (false); // Sensor did not ACK delay(3); @@ -407,14 +407,14 @@ bool SCD30::getSettingValue(uint16_t registerAddress, uint16_t *val) return (false); } -//Gets two bytes from SCD30 +// 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 + _i2cPort->write(registerAddress >> 8); // MSB + _i2cPort->write(registerAddress & 0xFF); // LSB if (_i2cPort->endTransmission() != 0) - return (0); //Sensor did not ACK + return (0); // Sensor did not ACK delay(3); @@ -425,49 +425,49 @@ uint16_t SCD30::readRegister(uint16_t registerAddress) uint8_t lsb = _i2cPort->read(); return ((uint16_t)msb << 8 | lsb); } - return (0); //Sensor did not respond + return (0); // Sensor did not respond } -//Sends a command along with arguments and CRC +// 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 + 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(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 (false); // Sensor did not ACK return (true); } -//Sends just a command, no arguments, no CRC +// 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 + _i2cPort->write(command >> 8); // MSB + _i2cPort->write(command & 0xFF); // LSB if (_i2cPort->endTransmission() != 0) - return (false); //Sensor did not ACK + 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 +// 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 + uint8_t crc = 0xFF; // Init with 0xFF for (uint8_t x = 0; x < len; x++) { @@ -482,5 +482,5 @@ uint8_t SCD30::computeCRC8(uint8_t data[], uint8_t len) } } - return crc; //No output reflection + return crc; // No output reflection }