pull/1/head V0.9
Mathis et Yohan 2021-07-17 15:01:44 +02:00
rodzic 0f019e9ed0
commit 5a8627b53c
10 zmienionych plików z 522268 dodań i 0 usunięć

BIN
.DS_Store vendored

Plik binarny nie jest wyświetlany.

BIN
RLS_V0.9/.DS_Store vendored 100644

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -0,0 +1,546 @@
/*!
* @file Adafruit_BMP280.cpp
*
* This is a library for the BMP280 orientation sensor
*
* Designed specifically to work with the Adafruit BMP280 Sensor.
*
* Pick one up today in the adafruit shop!
* ------> https://www.adafruit.com/product/2651
*
* These sensors use I2C to communicate, 2 pins are required to interface.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit andopen-source hardware by purchasing products
* from Adafruit!
*
* K.Townsend (Adafruit Industries)
*
* BSD license, all text above must be included in any redistribution
*/
#include "Adafruit_BMP280.h"
#include "Arduino.h"
#include <Wire.h>
/*!
* @brief BMP280 constructor using i2c
* @param *theWire
* optional wire
*/
Adafruit_BMP280::Adafruit_BMP280(TwoWire *theWire)
: _cs(-1), _mosi(-1), _miso(-1), _sck(-1) {
_wire = theWire;
temp_sensor = new Adafruit_BMP280_Temp(this);
pressure_sensor = new Adafruit_BMP280_Pressure(this);
}
Adafruit_BMP280::~Adafruit_BMP280(void) {
delete temp_sensor;
delete pressure_sensor;
}
/*!
* @brief BMP280 constructor using hardware SPI
* @param cspin
* cs pin number
* @param theSPI
* optional SPI object
*/
Adafruit_BMP280::Adafruit_BMP280(int8_t cspin, SPIClass *theSPI)
: _cs(cspin), _mosi(-1), _miso(-1), _sck(-1) {
_spi = theSPI;
}
/*!
* @brief BMP280 constructor using bitbang SPI
* @param cspin
* The pin to use for CS/SSEL.
* @param mosipin
* The pin to use for MOSI.
* @param misopin
* The pin to use for MISO.
* @param sckpin
* The pin to use for SCK.
*/
Adafruit_BMP280::Adafruit_BMP280(int8_t cspin, int8_t mosipin, int8_t misopin,
int8_t sckpin)
: _cs(cspin), _mosi(mosipin), _miso(misopin), _sck(sckpin) {}
/*!
* Initialises the sensor.
* @param addr
* The I2C address to use (default = 0x77)
* @param chipid
* The expected chip ID (used to validate connection).
* @return True if the init was successful, otherwise false.
*/
bool Adafruit_BMP280::begin(uint8_t addr, uint8_t chipid) {
_i2caddr = addr;
if (_cs == -1) {
// i2c
_wire->begin();
} else {
digitalWrite(_cs, HIGH);
pinMode(_cs, OUTPUT);
if (_sck == -1) {
// hardware SPI
_spi->begin();
} else {
// software SPI
pinMode(_sck, OUTPUT);
pinMode(_mosi, OUTPUT);
pinMode(_miso, INPUT);
}
}
if (read8(BMP280_REGISTER_CHIPID) != chipid)
return false;
readCoefficients();
// write8(BMP280_REGISTER_CONTROL, 0x3F); /* needed? */
setSampling();
delay(100);
return true;
}
/*!
* Sets the sampling config for the device.
* @param mode
* The operating mode of the sensor.
* @param tempSampling
* The sampling scheme for temp readings.
* @param pressSampling
* The sampling scheme for pressure readings.
* @param filter
* The filtering mode to apply (if any).
* @param duration
* The sampling duration.
*/
void Adafruit_BMP280::setSampling(sensor_mode mode,
sensor_sampling tempSampling,
sensor_sampling pressSampling,
sensor_filter filter,
standby_duration duration) {
_measReg.mode = mode;
_measReg.osrs_t = tempSampling;
_measReg.osrs_p = pressSampling;
_configReg.filter = filter;
_configReg.t_sb = duration;
write8(BMP280_REGISTER_CONFIG, _configReg.get());
write8(BMP280_REGISTER_CONTROL, _measReg.get());
}
uint8_t Adafruit_BMP280::spixfer(uint8_t x) {
if (_sck == -1)
return _spi->transfer(x);
// software spi
// Serial.println("Software SPI");
uint8_t reply = 0;
for (int i = 7; i >= 0; i--) {
reply <<= 1;
digitalWrite(_sck, LOW);
digitalWrite(_mosi, x & (1 << i));
digitalWrite(_sck, HIGH);
if (digitalRead(_miso))
reply |= 1;
}
return reply;
}
/**************************************************************************/
/*!
@brief Writes an 8 bit value over I2C/SPI
*/
/**************************************************************************/
void Adafruit_BMP280::write8(byte reg, byte value) {
if (_cs == -1) {
_wire->beginTransmission((uint8_t)_i2caddr);
_wire->write((uint8_t)reg);
_wire->write((uint8_t)value);
_wire->endTransmission();
} else {
if (_sck == -1)
_spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
digitalWrite(_cs, LOW);
spixfer(reg & ~0x80); // write, bit 7 low
spixfer(value);
digitalWrite(_cs, HIGH);
if (_sck == -1)
_spi->endTransaction(); // release the SPI bus
}
}
/*!
* @brief Reads an 8 bit value over I2C/SPI
* @param reg
* selected register
* @return value from selected register
*/
uint8_t Adafruit_BMP280::read8(byte reg) {
uint8_t value;
if (_cs == -1) {
_wire->beginTransmission((uint8_t)_i2caddr);
_wire->write((uint8_t)reg);
_wire->endTransmission();
_wire->requestFrom((uint8_t)_i2caddr, (byte)1);
value = _wire->read();
} else {
if (_sck == -1)
_spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
digitalWrite(_cs, LOW);
spixfer(reg | 0x80); // read, bit 7 high
value = spixfer(0);
digitalWrite(_cs, HIGH);
if (_sck == -1)
_spi->endTransaction(); // release the SPI bus
}
return value;
}
/*!
* @brief Reads a 16 bit value over I2C/SPI
*/
uint16_t Adafruit_BMP280::read16(byte reg) {
uint16_t value;
if (_cs == -1) {
_wire->beginTransmission((uint8_t)_i2caddr);
_wire->write((uint8_t)reg);
_wire->endTransmission();
_wire->requestFrom((uint8_t)_i2caddr, (byte)2);
value = (_wire->read() << 8) | _wire->read();
} else {
if (_sck == -1)
_spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
digitalWrite(_cs, LOW);
spixfer(reg | 0x80); // read, bit 7 high
value = (spixfer(0) << 8) | spixfer(0);
digitalWrite(_cs, HIGH);
if (_sck == -1)
_spi->endTransaction(); // release the SPI bus
}
return value;
}
uint16_t Adafruit_BMP280::read16_LE(byte reg) {
uint16_t temp = read16(reg);
return (temp >> 8) | (temp << 8);
}
/*!
* @brief Reads a signed 16 bit value over I2C/SPI
*/
int16_t Adafruit_BMP280::readS16(byte reg) { return (int16_t)read16(reg); }
int16_t Adafruit_BMP280::readS16_LE(byte reg) {
return (int16_t)read16_LE(reg);
}
/*!
* @brief Reads a 24 bit value over I2C/SPI
*/
uint32_t Adafruit_BMP280::read24(byte reg) {
uint32_t value;
if (_cs == -1) {
_wire->beginTransmission((uint8_t)_i2caddr);
_wire->write((uint8_t)reg);
_wire->endTransmission();
_wire->requestFrom((uint8_t)_i2caddr, (byte)3);
value = _wire->read();
value <<= 8;
value |= _wire->read();
value <<= 8;
value |= _wire->read();
} else {
if (_sck == -1)
_spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
digitalWrite(_cs, LOW);
spixfer(reg | 0x80); // read, bit 7 high
value = spixfer(0);
value <<= 8;
value |= spixfer(0);
value <<= 8;
value |= spixfer(0);
digitalWrite(_cs, HIGH);
if (_sck == -1)
_spi->endTransaction(); // release the SPI bus
}
return value;
}
/*!
* @brief Reads the factory-set coefficients
*/
void Adafruit_BMP280::readCoefficients() {
_bmp280_calib.dig_T1 = read16_LE(BMP280_REGISTER_DIG_T1);
_bmp280_calib.dig_T2 = readS16_LE(BMP280_REGISTER_DIG_T2);
_bmp280_calib.dig_T3 = readS16_LE(BMP280_REGISTER_DIG_T3);
_bmp280_calib.dig_P1 = read16_LE(BMP280_REGISTER_DIG_P1);
_bmp280_calib.dig_P2 = readS16_LE(BMP280_REGISTER_DIG_P2);
_bmp280_calib.dig_P3 = readS16_LE(BMP280_REGISTER_DIG_P3);
_bmp280_calib.dig_P4 = readS16_LE(BMP280_REGISTER_DIG_P4);
_bmp280_calib.dig_P5 = readS16_LE(BMP280_REGISTER_DIG_P5);
_bmp280_calib.dig_P6 = readS16_LE(BMP280_REGISTER_DIG_P6);
_bmp280_calib.dig_P7 = readS16_LE(BMP280_REGISTER_DIG_P7);
_bmp280_calib.dig_P8 = readS16_LE(BMP280_REGISTER_DIG_P8);
_bmp280_calib.dig_P9 = readS16_LE(BMP280_REGISTER_DIG_P9);
}
/*!
* Reads the temperature from the device.
* @return The temperature in degress celcius.
*/
float Adafruit_BMP280::readTemperature() {
int32_t var1, var2;
int32_t adc_T = read24(BMP280_REGISTER_TEMPDATA);
adc_T >>= 4;
var1 = ((((adc_T >> 3) - ((int32_t)_bmp280_calib.dig_T1 << 1))) *
((int32_t)_bmp280_calib.dig_T2)) >>
11;
var2 = (((((adc_T >> 4) - ((int32_t)_bmp280_calib.dig_T1)) *
((adc_T >> 4) - ((int32_t)_bmp280_calib.dig_T1))) >>
12) *
((int32_t)_bmp280_calib.dig_T3)) >>
14;
t_fine = var1 + var2;
float T = (t_fine * 5 + 128) >> 8;
return T / 100;
}
/*!
* Reads the barometric pressure from the device.
* @return Barometric pressure in Pa.
*/
float Adafruit_BMP280::readPressure() {
int64_t var1, var2, p;
// Must be done first to get the t_fine variable set up
readTemperature();
int32_t adc_P = read24(BMP280_REGISTER_PRESSUREDATA);
adc_P >>= 4;
var1 = ((int64_t)t_fine) - 128000;
var2 = var1 * var1 * (int64_t)_bmp280_calib.dig_P6;
var2 = var2 + ((var1 * (int64_t)_bmp280_calib.dig_P5) << 17);
var2 = var2 + (((int64_t)_bmp280_calib.dig_P4) << 35);
var1 = ((var1 * var1 * (int64_t)_bmp280_calib.dig_P3) >> 8) +
((var1 * (int64_t)_bmp280_calib.dig_P2) << 12);
var1 =
(((((int64_t)1) << 47) + var1)) * ((int64_t)_bmp280_calib.dig_P1) >> 33;
if (var1 == 0) {
return 0; // avoid exception caused by division by zero
}
p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((int64_t)_bmp280_calib.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((int64_t)_bmp280_calib.dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)_bmp280_calib.dig_P7) << 4);
return (float)p / 256;
}
/*!
* @brief Calculates the approximate altitude using barometric pressure and the
* supplied sea level hPa as a reference.
* @param seaLevelhPa
* The current hPa at sea level.
* @return The approximate altitude above sea level in meters.
*/
float Adafruit_BMP280::readAltitude(float seaLevelhPa) {
float altitude;
float pressure = readPressure(); // in Si units for Pascal
pressure /= 100;
altitude = 44330 * (1.0 - pow(pressure / seaLevelhPa, 0.1903));
return altitude;
}
/*!
* Calculates the pressure at sea level (QFH) from the specified altitude,
* and atmospheric pressure (QFE).
* @param altitude Altitude in m
* @param atmospheric Atmospheric pressure in hPa
* @return The approximate pressure in hPa
*/
float Adafruit_BMP280::seaLevelForAltitude(float altitude, float atmospheric) {
// Equation taken from BMP180 datasheet (page 17):
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
// Note that using the equation from wikipedia can give bad results
// at high altitude. See this thread for more information:
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255);
}
/*!
@brief calculates the boiling point of water by a given pressure
@param pressure pressure in hPa
@return temperature in °C
*/
float Adafruit_BMP280::waterBoilingPoint(float pressure) {
// Magnusformular for calculation of the boiling point of water at a given
// pressure
return (234.175 * log(pressure / 6.1078)) /
(17.08085 - log(pressure / 6.1078));
}
/*!
* @brief Take a new measurement (only possible in forced mode)
* !!!todo!!!
*/
/*
void Adafruit_BMP280::takeForcedMeasurement()
{
// If we are in forced mode, the BME sensor goes back to sleep after each
// measurement and we need to set it to forced mode once at this point, so
// it will take the next measurement and then return to sleep again.
// In normal mode simply does new measurements periodically.
if (_measReg.mode == MODE_FORCED) {
// set to forced mode, i.e. "take next measurement"
write8(BMP280_REGISTER_CONTROL, _measReg.get());
// wait until measurement has been completed, otherwise we would read
// the values from the last measurement
while (read8(BMP280_REGISTER_STATUS) & 0x08)
delay(1);
}
}
*/
/*!
* @brief Resets the chip via soft reset
*/
void Adafruit_BMP280::reset(void) {
write8(BMP280_REGISTER_SOFTRESET, MODE_SOFT_RESET_CODE);
}
/*!
@brief Gets the most recent sensor event from the hardware status register.
@return Sensor status as a byte.
*/
uint8_t Adafruit_BMP280::getStatus(void) {
return read8(BMP280_REGISTER_STATUS);
}
/*!
@brief Gets an Adafruit Unified Sensor object for the temp sensor component
@return Adafruit_Sensor pointer to temperature sensor
*/
Adafruit_Sensor *Adafruit_BMP280::getTemperatureSensor(void) {
return temp_sensor;
}
/*!
@brief Gets an Adafruit Unified Sensor object for the pressure sensor
component
@return Adafruit_Sensor pointer to pressure sensor
*/
Adafruit_Sensor *Adafruit_BMP280::getPressureSensor(void) {
return pressure_sensor;
}
/**************************************************************************/
/*!
@brief Gets the sensor_t data for the BMP280's temperature sensor
*/
/**************************************************************************/
void Adafruit_BMP280_Temp::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "BMP280", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
sensor->min_delay = 0;
sensor->min_value = -40.0; /* Temperature range -40 ~ +85 C */
sensor->max_value = +85.0;
sensor->resolution = 0.01; /* 0.01 C */
}
/**************************************************************************/
/*!
@brief Gets the temperature as a standard sensor event
@param event Sensor event object that will be populated
@returns True
*/
/**************************************************************************/
bool Adafruit_BMP280_Temp::getEvent(sensors_event_t *event) {
/* Clear the event */
memset(event, 0, sizeof(sensors_event_t));
event->version = sizeof(sensors_event_t);
event->sensor_id = _sensorID;
event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
event->timestamp = millis();
event->temperature = _theBMP280->readTemperature();
return true;
}
/**************************************************************************/
/*!
@brief Gets the sensor_t data for the BMP280's pressure sensor
*/
/**************************************************************************/
void Adafruit_BMP280_Pressure::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "BMP280", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_PRESSURE;
sensor->min_delay = 0;
sensor->min_value = 300.0; /* 300 ~ 1100 hPa */
sensor->max_value = 1100.0;
sensor->resolution = 0.012; /* 0.12 hPa relative */
}
/**************************************************************************/
/*!
@brief Gets the pressure as a standard sensor event
@param event Sensor event object that will be populated
@returns True
*/
/**************************************************************************/
bool Adafruit_BMP280_Pressure::getEvent(sensors_event_t *event) {
/* Clear the event */
memset(event, 0, sizeof(sensors_event_t));
event->version = sizeof(sensors_event_t);
event->sensor_id = _sensorID;
event->type = SENSOR_TYPE_PRESSURE;
event->timestamp = millis();
event->pressure = _theBMP280->readPressure() / 100; // convert Pa to hPa
return true;
}

Wyświetl plik

@ -0,0 +1,263 @@
/*!
* @file Adafruit_BMP280.h
*
* This is a library for the Adafruit BMP280 Breakout.
*
* Designed specifically to work with the Adafruit BMP280 Breakout.
*
* Pick one up today in the adafruit shop!
* ------> https://www.adafruit.com/product/2651
*
* These sensors use I2C to communicate, 2 pins are required to interface.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit andopen-source hardware by purchasing products
* from Adafruit!
*
* K.Townsend (Adafruit Industries)
*
* BSD license, all text above must be included in any redistribution
*/
#ifndef __BMP280_H__
#define __BMP280_H__
#include "Adafruit_Sensor.h"
#include "Arduino.h"
#include <SPI.h>
#include <Wire.h>
/*!
* I2C ADDRESS/BITS/SETTINGS
*/
#define BMP280_ADDRESS (0x77) /**< The default I2C address for the sensor. */
#define BMP280_ADDRESS_ALT \
(0x76) /**< Alternative I2C address for the sensor. */
#define BMP280_CHIPID (0x58) /**< Default chip ID. */
// Forward declarations of Wire and SPI for board/variant combinations that
// don't have a default 'Wire' or 'SPI'
extern TwoWire Wire1; /**< Forward declaration of Wire object */
extern SPIClass SPI; /**< Forward declaration of SPI object */
/*!
* Registers available on the sensor.
*/
enum {
BMP280_REGISTER_DIG_T1 = 0x88,
BMP280_REGISTER_DIG_T2 = 0x8A,
BMP280_REGISTER_DIG_T3 = 0x8C,
BMP280_REGISTER_DIG_P1 = 0x8E,
BMP280_REGISTER_DIG_P2 = 0x90,
BMP280_REGISTER_DIG_P3 = 0x92,
BMP280_REGISTER_DIG_P4 = 0x94,
BMP280_REGISTER_DIG_P5 = 0x96,
BMP280_REGISTER_DIG_P6 = 0x98,
BMP280_REGISTER_DIG_P7 = 0x9A,
BMP280_REGISTER_DIG_P8 = 0x9C,
BMP280_REGISTER_DIG_P9 = 0x9E,
BMP280_REGISTER_CHIPID = 0xD0,
BMP280_REGISTER_VERSION = 0xD1,
BMP280_REGISTER_SOFTRESET = 0xE0,
BMP280_REGISTER_CAL26 = 0xE1, /**< R calibration = 0xE1-0xF0 */
BMP280_REGISTER_STATUS = 0xF3,
BMP280_REGISTER_CONTROL = 0xF4,
BMP280_REGISTER_CONFIG = 0xF5,
BMP280_REGISTER_PRESSUREDATA = 0xF7,
BMP280_REGISTER_TEMPDATA = 0xFA,
};
/*!
* Struct to hold calibration data.
*/
typedef struct {
uint16_t dig_T1; /**< dig_T1 cal register. */
int16_t dig_T2; /**< dig_T2 cal register. */
int16_t dig_T3; /**< dig_T3 cal register. */
uint16_t dig_P1; /**< dig_P1 cal register. */
int16_t dig_P2; /**< dig_P2 cal register. */
int16_t dig_P3; /**< dig_P3 cal register. */
int16_t dig_P4; /**< dig_P4 cal register. */
int16_t dig_P5; /**< dig_P5 cal register. */
int16_t dig_P6; /**< dig_P6 cal register. */
int16_t dig_P7; /**< dig_P7 cal register. */
int16_t dig_P8; /**< dig_P8 cal register. */
int16_t dig_P9; /**< dig_P9 cal register. */
} bmp280_calib_data;
class Adafruit_BMP280;
/** Adafruit Unified Sensor interface for temperature component of BMP280 */
class Adafruit_BMP280_Temp : public Adafruit_Sensor {
public:
/** @brief Create an Adafruit_Sensor compatible object for the temp sensor
@param parent A pointer to the BMP280 class */
Adafruit_BMP280_Temp(Adafruit_BMP280 *parent) { _theBMP280 = parent; }
bool getEvent(sensors_event_t *);
void getSensor(sensor_t *);
private:
int _sensorID = 280;
Adafruit_BMP280 *_theBMP280 = NULL;
};
/** Adafruit Unified Sensor interface for pressure component of BMP280 */
class Adafruit_BMP280_Pressure : public Adafruit_Sensor {
public:
/** @brief Create an Adafruit_Sensor compatible object for the pressure sensor
@param parent A pointer to the BMP280 class */
Adafruit_BMP280_Pressure(Adafruit_BMP280 *parent) { _theBMP280 = parent; }
bool getEvent(sensors_event_t *);
void getSensor(sensor_t *);
private:
int _sensorID = 0;
Adafruit_BMP280 *_theBMP280 = NULL;
};
/**
* Driver for the Adafruit BMP280 barometric pressure sensor.
*/
class Adafruit_BMP280 {
public:
/** Oversampling rate for the sensor. */
enum sensor_sampling {
/** No over-sampling. */
SAMPLING_NONE = 0x00,
/** 1x over-sampling. */
SAMPLING_X1 = 0x01,
/** 2x over-sampling. */
SAMPLING_X2 = 0x02,
/** 4x over-sampling. */
SAMPLING_X4 = 0x03,
/** 8x over-sampling. */
SAMPLING_X8 = 0x04,
/** 16x over-sampling. */
SAMPLING_X16 = 0x05
};
/** Operating mode for the sensor. */
enum sensor_mode {
/** Sleep mode. */
MODE_SLEEP = 0x00,
/** Forced mode. */
MODE_FORCED = 0x01,
/** Normal mode. */
MODE_NORMAL = 0x03,
/** Software reset. */
MODE_SOFT_RESET_CODE = 0xB6
};
/** Filtering level for sensor data. */
enum sensor_filter {
/** No filtering. */
FILTER_OFF = 0x00,
/** 2x filtering. */
FILTER_X2 = 0x01,
/** 4x filtering. */
FILTER_X4 = 0x02,
/** 8x filtering. */
FILTER_X8 = 0x03,
/** 16x filtering. */
FILTER_X16 = 0x04
};
/** Standby duration in ms */
enum standby_duration {
/** 1 ms standby. */
STANDBY_MS_1 = 0x00,
/** 62.5 ms standby. */
STANDBY_MS_63 = 0x01,
/** 125 ms standby. */
STANDBY_MS_125 = 0x02,
/** 250 ms standby. */
STANDBY_MS_250 = 0x03,
/** 500 ms standby. */
STANDBY_MS_500 = 0x04,
/** 1000 ms standby. */
STANDBY_MS_1000 = 0x05,
/** 2000 ms standby. */
STANDBY_MS_2000 = 0x06,
/** 4000 ms standby. */
STANDBY_MS_4000 = 0x07
};
Adafruit_BMP280(TwoWire *theWire = &Wire1);
Adafruit_BMP280(int8_t cspin, SPIClass *theSPI = &SPI);
Adafruit_BMP280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin);
~Adafruit_BMP280(void);
bool begin(uint8_t addr = BMP280_ADDRESS, uint8_t chipid = BMP280_CHIPID);
void reset(void);
uint8_t getStatus(void);
float readTemperature();
float readPressure(void);
float readAltitude(float seaLevelhPa = 1013.25);
float seaLevelForAltitude(float altitude, float atmospheric);
float waterBoilingPoint(float pressure);
Adafruit_Sensor *getTemperatureSensor(void);
Adafruit_Sensor *getPressureSensor(void);
// void takeForcedMeasurement();
void setSampling(sensor_mode mode = MODE_NORMAL,
sensor_sampling tempSampling = SAMPLING_X16,
sensor_sampling pressSampling = SAMPLING_X16,
sensor_filter filter = FILTER_OFF,
standby_duration duration = STANDBY_MS_1);
private:
TwoWire *_wire; /**< Wire object */
SPIClass *_spi; /**< SPI object */
Adafruit_BMP280_Temp *temp_sensor = NULL;
Adafruit_BMP280_Pressure *pressure_sensor = NULL;
/** Encapsulates the config register */
struct config {
/** Inactive duration (standby time) in normal mode */
unsigned int t_sb : 3;
/** Filter settings */
unsigned int filter : 3;
/** Unused - don't set */
unsigned int none : 1;
/** Enables 3-wire SPI */
unsigned int spi3w_en : 1;
/** Used to retrieve the assembled config register's byte value. */
unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; }
};
/** Encapsulates trhe ctrl_meas register */
struct ctrl_meas {
/** Temperature oversampling. */
unsigned int osrs_t : 3;
/** Pressure oversampling. */
unsigned int osrs_p : 3;
/** Device mode */
unsigned int mode : 2;
/** Used to retrieve the assembled ctrl_meas register's byte value. */
unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; }
};
void readCoefficients(void);
uint8_t spixfer(uint8_t x);
void write8(byte reg, byte value);
uint8_t read8(byte reg);
uint16_t read16(byte reg);
uint32_t read24(byte reg);
int16_t readS16(byte reg);
uint16_t read16_LE(byte reg);
int16_t readS16_LE(byte reg);
uint8_t _i2caddr;
int32_t _sensorID;
int32_t t_fine;
int8_t _cs, _mosi, _miso, _sck;
bmp280_calib_data _bmp280_calib;
config _configReg;
ctrl_meas _measReg;
};
#endif

Wyświetl plik

@ -0,0 +1,385 @@
/*
===============================================================================================================
QMC5883LCompass.h
Library for using QMC5583L series chip boards as a compass.
Learn more at [https://github.com/mprograms/QMC5883LCompass]
Supports:
- Getting values of XYZ axis.
- Calculating Azimuth.
- Getting 16 point Azimuth bearing direction (0 - 15).
- Getting 16 point Azimuth bearing Names (N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW)
- Smoothing of XYZ readings via rolling averaging and min / max removal.
- Optional chipset modes (see below)
===============================================================================================================
v1.0 - June 13, 2019
Written by MRPrograms
Github: [https://github.com/mprograms/]
Release under the GNU General Public License v3
[https://www.gnu.org/licenses/gpl-3.0.en.html]
===============================================================================================================
FROM QST QMC5883L Datasheet [https://nettigo.pl/attachments/440]
-----------------------------------------------
MODE CONTROL (MODE)
Standby 0x00
Continuous 0x01
OUTPUT DATA RATE (ODR)
10Hz 0x00
50Hz 0x04
100Hz 0x08
200Hz 0x0C
FULL SCALE (RNG)
2G 0x00
8G 0x10
OVER SAMPLE RATIO (OSR)
512 0x00
256 0x40
128 0x80
64 0xC0
*/
#include "Arduino.h"
#include "QMC5883LCompass.h"
#include <Wire.h>
QMC5883LCompass::QMC5883LCompass() {
}
/**
INIT
Initialize Chip - This needs to be called in the sketch setup() function.
@since v0.1;
**/
void QMC5883LCompass::init(){
Wire1.begin();
_writeReg(0x0B,0x01);
setMode(0x01,0x0C,0x10,0X00);
}
/**
SET ADDRESS
Set the I2C Address of the chip. This needs to be called in the sketch setup() function.
@since v0.1;
**/
// Set I2C Address if different then default.
void QMC5883LCompass::setADDR(byte b){
_ADDR = b;
}
/**
REGISTER
Write the register to the chip.
@since v0.1;
**/
// Write register values to chip
void QMC5883LCompass::_writeReg(byte r, byte v){
Wire1.beginTransmission(_ADDR);
Wire1.write(r);
Wire1.write(v);
Wire1.endTransmission();
}
/**
CHIP MODE
Set the chip mode.
@since v0.1;
**/
// Set chip mode
void QMC5883LCompass::setMode(byte mode, byte odr, byte rng, byte osr){
_writeReg(0x09,mode|odr|rng|osr);
}
/**
RESET
Reset the chip.
@since v0.1;
**/
// Reset the chip
void QMC5883LCompass::setReset(){
_writeReg(0x0A,0x80);
}
// 1 = Basic 2 = Advanced
void QMC5883LCompass::setSmoothing(byte steps, bool adv){
_smoothUse = true;
_smoothSteps = ( steps > 10) ? 10 : steps;
_smoothAdvanced = (adv == true) ? true : false;
}
/**
SET CALIBRATION
Set calibration values for more accurate readings
@author Claus Näveke - TheNitek [https://github.com/TheNitek]
@since v1.1.0
**/
void QMC5883LCompass::setCalibration(int x_min, int x_max, int y_min, int y_max, int z_min, int z_max){
_calibrationUse = true;
_vCalibration[0][0] = x_min;
_vCalibration[0][1] = x_max;
_vCalibration[1][0] = y_min;
_vCalibration[1][1] = y_max;
_vCalibration[2][0] = z_min;
_vCalibration[2][1] = z_max;
}
/**
READ
Read the XYZ axis and save the values in an array.
@since v0.1;
**/
void QMC5883LCompass::read(){
Wire1.beginTransmission(_ADDR);
Wire1.write(0x00);
int err = Wire1.endTransmission();
if (!err) {
Wire1.requestFrom(_ADDR, (byte)6);
_vRaw[0] = (int)(int16_t)(Wire1.read() | Wire1.read() << 8);
_vRaw[1] = (int)(int16_t)(Wire1.read() | Wire1.read() << 8);
_vRaw[2] = (int)(int16_t)(Wire1.read() | Wire1.read() << 8);
if ( _calibrationUse ) {
_applyCalibration();
}
if ( _smoothUse ) {
_smoothing();
}
//byte overflow = Wire.read() & 0x02;
//return overflow << 2;
}
}
/**
APPLY CALIBRATION
This function uses the calibration data provided via @see setCalibration() to calculate more
accurate readings
@author Claus Näveke - TheNitek [https://github.com/TheNitek]
Based on this awesome article:
https://appelsiini.net/2018/calibrate-magnetometer/
@since v1.1.0
**/
void QMC5883LCompass::_applyCalibration(){
int x_offset = (_vCalibration[0][0] + _vCalibration[0][1])/2;
int y_offset = (_vCalibration[1][0] + _vCalibration[1][1])/2;
int z_offset = (_vCalibration[2][0] + _vCalibration[2][1])/2;
int x_avg_delta = (_vCalibration[0][1] - _vCalibration[0][0])/2;
int y_avg_delta = (_vCalibration[1][1] - _vCalibration[1][0])/2;
int z_avg_delta = (_vCalibration[2][1] - _vCalibration[2][0])/2;
int avg_delta = (x_avg_delta + y_avg_delta + z_avg_delta) / 3;
float x_scale = (float)avg_delta / x_avg_delta;
float y_scale = (float)avg_delta / y_avg_delta;
float z_scale = (float)avg_delta / z_avg_delta;
_vCalibrated[0] = (_vRaw[0] - x_offset) * x_scale;
_vCalibrated[1] = (_vRaw[1] - y_offset) * y_scale;
_vCalibrated[2] = (_vRaw[2] - z_offset) * z_scale;
}
/**
SMOOTH OUTPUT
This function smooths the output for the XYZ axis. Depending on the options set in
@see setSmoothing(), we can run multiple methods of smoothing the sensor readings.
First we store (n) samples of sensor readings for each axis and store them in a rolling array.
As each new sensor reading comes in we replace it with a new reading. Then we average the total
of all (n) readings.
Advanced Smoothing
If you turn advanced smoothing on, we will select the min and max values from our array
of (n) samples. We then subtract both the min and max from the total and average the total of all
(n - 2) readings.
NOTE: This function does several calculations and can cause your sketch to run slower.
@since v0.3;
**/
void QMC5883LCompass::_smoothing(){
byte max = 0;
byte min = 0;
if ( _vScan > _smoothSteps - 1 ) { _vScan = 0; }
for ( int i = 0; i < 3; i++ ) {
if ( _vTotals[i] != 0 ) {
_vTotals[i] = _vTotals[i] - _vHistory[_vScan][i];
}
_vHistory[_vScan][i] = ( _calibrationUse ) ? _vCalibrated[i] : _vRaw[i];
_vTotals[i] = _vTotals[i] + _vHistory[_vScan][i];
if ( _smoothAdvanced ) {
max = 0;
for (int j = 0; j < _smoothSteps - 1; j++) {
max = ( _vHistory[j][i] > _vHistory[max][i] ) ? j : max;
}
min = 0;
for (int k = 0; k < _smoothSteps - 1; k++) {
min = ( _vHistory[k][i] < _vHistory[min][i] ) ? k : min;
}
_vSmooth[i] = ( _vTotals[i] - (_vHistory[max][i] + _vHistory[min][i]) ) / (_smoothSteps - 2);
} else {
_vSmooth[i] = _vTotals[i] / _smoothSteps;
}
}
_vScan++;
}
/**
GET X AXIS
Read the X axis
@since v0.1;
@return int x axis
**/
int QMC5883LCompass::getX(){
return _get(0);
}
/**
GET Y AXIS
Read the Y axis
@since v0.1;
@return int y axis
**/
int QMC5883LCompass::getY(){
return _get(1);
}
/**
GET Z AXIS
Read the Z axis
@since v0.1;
@return int z axis
**/
int QMC5883LCompass::getZ(){
return _get(2);
}
/**
GET SENSOR AXIS READING
Get the smoothed, calibration, or raw data from a given sensor axis
@since v1.1.0
@return int sensor axis value
**/
int QMC5883LCompass::_get(int i){
if ( _smoothUse )
return _vSmooth[i];
if ( _calibrationUse )
return _vCalibrated[i];
return _vRaw[i];
}
/**
GET AZIMUTH
Calculate the azimuth (in degrees);
@since v0.1;
@return int azimuth
**/
int QMC5883LCompass::getAzimuth(){
int a = atan2( getY(), getX() ) * 180.0 / PI;
return a < 0 ? 360 + a : a;
}
/**
GET BEARING
Divide the 360 degree circle into 16 equal parts and then return the a value of 0-15
based on where the azimuth is currently pointing.
@since v1.0.1 - function now requires azimuth parameter.
@since v0.2.0 - initial creation
@return byte direction of bearing
*/
byte QMC5883LCompass::getBearing(int azimuth){
unsigned long a = azimuth / 22.5;
unsigned long r = a - (int)a;
byte sexdec = 0;
sexdec = ( r >= .5 ) ? ceil(a) : floor(a);
return sexdec;
}
/**
This will take the location of the azimuth as calculated in getBearing() and then
produce an array of chars as a text representation of the direction.
NOTE: This function does not return anything since it is not possible to return an array.
Values must be passed by reference back to your sketch.
Example:
( if direction is in 1 / NNE)
char myArray[3];
compass.getDirection(myArray, azimuth);
Serial.print(myArray[0]); // N
Serial.print(myArray[1]); // N
Serial.print(myArray[2]); // E
@see getBearing();
@since v1.0.1 - function now requires azimuth parameter.
@since v0.2.0 - initial creation
*/
void QMC5883LCompass::getDirection(char* myArray, int azimuth){
int d = getBearing(azimuth);
myArray[0] = _bearings[d][0];
myArray[1] = _bearings[d][1];
myArray[2] = _bearings[d][2];
}

Wyświetl plik

@ -0,0 +1,66 @@
#ifndef QMC5883L_Compass
#define QMC5883L_Compass
#include "Arduino.h"
#include "Wire.h"
class QMC5883LCompass{
public:
QMC5883LCompass();
void init();
void setADDR(byte b);
void setMode(byte mode, byte odr, byte rng, byte osr);
void setSmoothing(byte steps, bool adv);
void setCalibration(int x_min, int x_max, int y_min, int y_max, int z_min, int z_max);
void setReset();
void read();
int getX();
int getY();
int getZ();
int getAzimuth();
byte getBearing(int azimuth);
void getDirection(char* myArray, int azimuth);
private:
void _writeReg(byte reg,byte val);
int _get(int index);
bool _smoothUse = false;
byte _smoothSteps = 5;
bool _smoothAdvanced = false;
byte _ADDR = 0x0D;
int _vRaw[3] = {0,0,0};
int _vHistory[10][3];
int _vScan = 0;
long _vTotals[3] = {0,0,0};
int _vSmooth[3] = {0,0,0};
void _smoothing();
bool _calibrationUse = false;
int _vCalibration[3][2];
int _vCalibrated[3];
void _applyCalibration();
const char _bearings[16][3] = {
{' ', ' ', 'N'},
{'N', 'N', 'E'},
{' ', 'N', 'E'},
{'E', 'N', 'E'},
{' ', ' ', 'E'},
{'E', 'S', 'E'},
{' ', 'S', 'E'},
{'S', 'S', 'E'},
{' ', ' ', 'S'},
{'S', 'S', 'W'},
{' ', 'S', 'W'},
{'W', 'S', 'W'},
{' ', ' ', 'W'},
{'W', 'N', 'W'},
{' ', 'N', 'W'},
{'N', 'N', 'W'},
};
};
#endif