st-anything/lib/Adafruit_AM2320_sensor_library/Adafruit_AM2320.cpp

322 lines
11 KiB
C++
Raw Normal View History

2023-03-11 14:11:03 +00:00
/*!
* @file Adafruit_AM2320.cpp
*
* @mainpage Adafruit AM2320 Temperature & Humidity Unified Sensor driver
*
* @section intro_sec Introduction
*
* This is the documentation for Adafruit's AM2320 driver for the
* Arduino platform. It is designed specifically to work with the
* Adafruit AM2320 breakout: https://www.adafruit.com/products/xxxx
*
* These sensors use I2C to communicate, 2 pins (SCL+SDA) are required
* to interface with the breakout.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* @section dependencies Dependencies
*
* This library depends on <a href="https://github.com/adafruit/Adafruit_Sensor">
* Adafruit_Sensor</a> being present on your system. Please make sure you have
* installed the latest version before using this library.
*
* @section author Author
*
* Written by Limor Fried for Adafruit Industries.
*
* @section license License
*
* 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.
*
*/
#include "Adafruit_AM2320.h"
/**************************************************************************/
/*!
@brief Instantiates a new AM2320 class
@param theI2C Optional pointer to a TwoWire object that should be used for I2C communication. Defaults to &Wire.
@param tempSensorId the id that should be used for the temperature sensor. Defaults to -1
@param humiditySensorId the id that should be used for the humidity sensor. Defaults to -1
*/
/**************************************************************************/
Adafruit_AM2320::Adafruit_AM2320(TwoWire *theI2C, int32_t tempSensorId, int32_t humiditySensorId):
_temp(this, tempSensorId),
_humidity(this, humiditySensorId),
_i2c(theI2C)
{}
/**************************************************************************/
/*!
@brief Setups the hardware
@return true
*/
/**************************************************************************/
bool Adafruit_AM2320::begin() {
_i2caddr = 0x5C; // fixed addr
_i2c->begin();
return true;
}
/**************************************************************************/
/*!
@brief read the temperature from the device
@return the temperature reading as a floating point value
*/
/**************************************************************************/
float Adafruit_AM2320::readTemperature() {
uint16_t t = readRegister16(AM2320_REG_TEMP_H);
float ft;
if (t == 0xFFFF) return NAN;
// check sign bit - the temperature MSB is signed , bit 0-15 are magnitude
if(t & 0x8000){
ft = -(int16_t)(t&0x7fff);
}
else {
ft = (int16_t)t;
}
return ft / 10.0;
}
/**************************************************************************/
/*!
@brief read the humidity from the device
@return the humidity reading as a floating point value
*/
/**************************************************************************/
float Adafruit_AM2320::readHumidity() {
uint16_t h = readRegister16(AM2320_REG_HUM_H);
if (h == 0xFFFF) return NAN;
float fh = h;
return fh / 10.0;
}
/**************************************************************************/
/*!
@brief read 2 bytes from a hardware register
@param reg the register to read
@return the read value as a 2 byte unsigned integer
*/
/**************************************************************************/
uint16_t Adafruit_AM2320::readRegister16(uint8_t reg) {
// wake up
Wire.beginTransmission(_i2caddr);
Wire.write(0x00);
Wire.endTransmission();
delay(10); // wait 10 ms
// send a command to read register
Wire.beginTransmission(_i2caddr);
Wire.write(AM2320_CMD_READREG);
Wire.write(reg);
Wire.write(2); // 2 bytes
Wire.endTransmission();
delay(2); // wait 2 ms
// 2 bytes preamble, 2 bytes data, 2 bytes CRC
Wire.requestFrom(_i2caddr, (uint8_t)6);
if (Wire.available() != 6)
return 0xFFFF;
uint8_t buffer[6];
for (int i=0; i<6; i++) {
buffer[i] = Wire.read();
//Serial.print("byte #"); Serial.print(i); Serial.print(" = 0x"); Serial.println(buffer[i], HEX);
}
if (buffer[0] != 0x03) return 0xFFFF; // must be 0x03 modbus reply
if (buffer[1] != 2) return 0xFFFF; // must be 2 bytes reply
uint16_t the_crc = buffer[5];
the_crc <<= 8;
the_crc |= buffer[4];
uint16_t calc_crc = crc16(buffer, 4); // preamble + data
//Serial.print("CRC: 0x"); Serial.println(calc_crc, HEX);
if (the_crc != calc_crc)
return 0xFFFF;
// All good!
uint16_t ret = buffer[2];
ret <<= 8;
ret |= buffer[3];
return ret;
}
/**************************************************************************/
/*!
@brief perfor a CRC check to verify data
@param buffer the pointer to the data to check
@param nbytes the number of bytes to calculate the CRC over
@return the calculated CRC
*/
/**************************************************************************/
uint16_t Adafruit_AM2320::crc16(uint8_t *buffer, uint8_t nbytes) {
uint16_t crc = 0xffff;
for (int i=0; i<nbytes; i++) {
uint8_t b = buffer[i];
crc ^= b;
for (int x=0; x<8; x++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
/**************************************************************************/
/*!
@brief set the name of the sensor
@param sensor a pointer to the sensor
*/
/**************************************************************************/
void Adafruit_AM2320::setName(sensor_t* sensor) {
strncpy(sensor->name, "AM2320", sizeof(sensor->name) - 1);
}
/**************************************************************************/
/*!
@brief set minimum delay to a fixed value of 2 seconds
@param sensor a pointer to the sensor
*/
/**************************************************************************/
void Adafruit_AM2320::setMinDelay(sensor_t* sensor) {
sensor->min_delay = 2000000L; // 2 seconds (in microseconds)
}
/**************************************************************************/
/*!
@brief create a temperature sensor instance
@param parent the pointer to the parent sensor
@param id the id value for the sensor
*/
/**************************************************************************/
Adafruit_AM2320::Temperature::Temperature(Adafruit_AM2320* parent, int32_t id):
_parent(parent),
_id(id)
{}
/**************************************************************************/
/*!
@brief read the temperature from the device and populate a sensor_event_t with the value
@param event a pointer to the event to populate
@return true
*/
/**************************************************************************/
bool Adafruit_AM2320::Temperature::getEvent(sensors_event_t* event) {
// Clear event definition.
memset(event, 0, sizeof(sensors_event_t));
// Populate sensor reading values.
event->version = sizeof(sensors_event_t);
event->sensor_id = _id;
event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
event->timestamp = millis();
event->temperature = _parent->readTemperature();
return true;
}
/**************************************************************************/
/*!
@brief populate a sensor_t with data for this sensor
@param sensor a pointer to the sensor_t to populate
*/
/**************************************************************************/
void Adafruit_AM2320::Temperature::getSensor(sensor_t* sensor) {
// Clear sensor definition.
memset(sensor, 0, sizeof(sensor_t));
// Set sensor name.
_parent->setName(sensor);
// Set version and ID
sensor->version = AM2320_SENSOR_VERSION;
sensor->sensor_id = _id;
// Set type and characteristics.
sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
_parent->setMinDelay(sensor);
// This isn't documented, of course
sensor->max_value = 80.0F;
sensor->min_value = -20.0F;
sensor->resolution = 2.0F;
}
/**************************************************************************/
/*!
@brief create a humidity sensor instance
@param parent the pointer to the parent sensor
@param id the id value for the sensor
*/
/**************************************************************************/
Adafruit_AM2320::Humidity::Humidity(Adafruit_AM2320* parent, int32_t id):
_parent(parent),
_id(id)
{}
/**************************************************************************/
/*!
@brief read the humidity from the device and populate a sensor_event_t with the value
@param event a pointer to the event to populate
@return true
*/
/**************************************************************************/
bool Adafruit_AM2320::Humidity::getEvent(sensors_event_t* event) {
// Clear event definition.
memset(event, 0, sizeof(sensors_event_t));
// Populate sensor reading values.
event->version = sizeof(sensors_event_t);
event->sensor_id = _id;
event->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
event->timestamp = millis();
event->relative_humidity = _parent->readHumidity();
return true;
}
/**************************************************************************/
/*!
@brief populate a sensor_t with data for this sensor
@param sensor a pointer to the sensor_t to populate
*/
/**************************************************************************/
void Adafruit_AM2320::Humidity::getSensor(sensor_t* sensor) {
// Clear sensor definition.
memset(sensor, 0, sizeof(sensor_t));
// Set sensor name.
_parent->setName(sensor);
// Set version and ID
sensor->version = AM2320_SENSOR_VERSION;
sensor->sensor_id = _id;
// Set type and characteristics.
sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
_parent->setMinDelay(sensor);
// This isn't documented, of course
sensor->max_value = 100.0F;
sensor->min_value = 0.0F;
sensor->resolution = 1.0F;
}