Initial commit of Julian's code
This commit is contained in:
commit
f2be3769ef
16 changed files with 4322 additions and 0 deletions
357
Adafruit_10DOF.cpp
Normal file
357
Adafruit_10DOF.cpp
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
/***************************************************************************
|
||||
This is a library for the Adafruit 10DOF Breakout
|
||||
|
||||
Designed specifically to work with the Adafruit 10DOF Breakout
|
||||
|
||||
These displays 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!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
#include <limits.h>
|
||||
#include <Math.h>
|
||||
|
||||
#include "Adafruit_10DOF.h"
|
||||
|
||||
#define PI (3.14159265F);
|
||||
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new Adafruit_10DOF class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_10DOF::Adafruit_10DOF(void)
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_10DOF::begin()
|
||||
{
|
||||
// Enable I2C
|
||||
Wire.begin();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Populates the .pitch/.roll fields in the sensors_vec_t struct
|
||||
with the right angular data (in degree)
|
||||
|
||||
@param event The sensors_event_t variable containing the
|
||||
data from the accelerometer
|
||||
@param orientation The sensors_vec_t object that will have it's
|
||||
.pitch and .roll fields populated
|
||||
@return Returns true if the operation was successful, false if there
|
||||
was an error
|
||||
|
||||
@code
|
||||
|
||||
bool error;
|
||||
sensors_event_t event;
|
||||
sensors_vec_t orientation;
|
||||
...
|
||||
lsm303accelGetSensorEvent(&event);
|
||||
error = accelGetOrientation(&event, &orientation);
|
||||
|
||||
@endcode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_10DOF::accelGetOrientation(sensors_event_t *event, sensors_vec_t *orientation)
|
||||
{
|
||||
/* Make sure the input is valid, not null, etc. */
|
||||
if (event == NULL) return false;
|
||||
if (orientation == NULL) return false;
|
||||
|
||||
float t_pitch;
|
||||
float t_roll;
|
||||
float t_heading;
|
||||
float signOfZ = event->acceleration.z >= 0 ? 1.0F : -1.0F;
|
||||
|
||||
/* roll: Rotation around the longitudinal axis (the plane body, 'X axis'). -90<=roll<=90 */
|
||||
/* roll is positive and increasing when moving downward */
|
||||
/* */
|
||||
/* y */
|
||||
/* roll = atan(-----------------) */
|
||||
/* sqrt(x^2 + z^2) */
|
||||
/* where: x, y, z are returned value from accelerometer sensor */
|
||||
|
||||
t_roll = event->acceleration.x * event->acceleration.x + event->acceleration.z * event->acceleration.z;
|
||||
orientation->roll = (float)atan2(event->acceleration.y, sqrt(t_roll)) * 180 / PI;
|
||||
|
||||
/* pitch: Rotation around the lateral axis (the wing span, 'Y axis'). -180<=pitch<=180) */
|
||||
/* pitch is positive and increasing when moving upwards */
|
||||
/* */
|
||||
/* x */
|
||||
/* pitch = atan(-----------------) */
|
||||
/* sqrt(y^2 + z^2) */
|
||||
/* where: x, y, z are returned value from accelerometer sensor */
|
||||
|
||||
t_pitch = event->acceleration.y * event->acceleration.y + event->acceleration.z * event->acceleration.z;
|
||||
orientation->pitch = (float)atan2(event->acceleration.x, signOfZ * sqrt(t_pitch)) * 180 / PI;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Utilize the sensor data from an accelerometer to compensate
|
||||
the magnetic sensor measurements when the sensor is tilted
|
||||
(the pitch and roll angles are not equal 0<EFBFBD>)
|
||||
|
||||
@param axis The given axis (SENSOR_AXIS_X/Y/Z) that is
|
||||
parallel to the gravity of the Earth
|
||||
|
||||
@param mag_event The raw magnetometer data to adjust for tilt
|
||||
|
||||
@param accel_event The accelerometer event data to use to determine
|
||||
the tilt when compensating the mag_event values
|
||||
|
||||
@code
|
||||
|
||||
// Perform tilt compensation with matching accelerometer data
|
||||
sensors_event_t accel_event;
|
||||
error = lsm303accelGetSensorEvent(&accel_event);
|
||||
if (!error)
|
||||
{
|
||||
magTiltCompensation(SENSOR_AXIS_Z, &mag_event, &accel_event);
|
||||
}
|
||||
|
||||
@endcode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_10DOF::magTiltCompensation(sensors_axis_t axis, sensors_event_t *mag_event, sensors_event_t *accel_event)
|
||||
{
|
||||
/* Make sure the input is valid, not null, etc. */
|
||||
if (mag_event == NULL) return false;
|
||||
if (accel_event == NULL) return false;
|
||||
|
||||
float accel_X, accel_Y, accel_Z;
|
||||
float *mag_X, *mag_Y, *mag_Z;
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case SENSOR_AXIS_X:
|
||||
/* The X-axis is parallel to the gravity */
|
||||
accel_X = accel_event->acceleration.y;
|
||||
accel_Y = accel_event->acceleration.z;
|
||||
accel_Z = accel_event->acceleration.x;
|
||||
mag_X = &(mag_event->magnetic.y);
|
||||
mag_Y = &(mag_event->magnetic.z);
|
||||
mag_Z = &(mag_event->magnetic.x);
|
||||
break;
|
||||
|
||||
case SENSOR_AXIS_Y:
|
||||
/* The Y-axis is parallel to the gravity */
|
||||
accel_X = accel_event->acceleration.z;
|
||||
accel_Y = accel_event->acceleration.x;
|
||||
accel_Z = accel_event->acceleration.y;
|
||||
mag_X = &(mag_event->magnetic.z);
|
||||
mag_Y = &(mag_event->magnetic.x);
|
||||
mag_Z = &(mag_event->magnetic.y);
|
||||
break;
|
||||
|
||||
case SENSOR_AXIS_Z:
|
||||
/* The Z-axis is parallel to the gravity */
|
||||
accel_X = accel_event->acceleration.x;
|
||||
accel_Y = accel_event->acceleration.y;
|
||||
accel_Z = accel_event->acceleration.z;
|
||||
mag_X = &(mag_event->magnetic.x);
|
||||
mag_Y = &(mag_event->magnetic.y);
|
||||
mag_Z = &(mag_event->magnetic.z);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
float t_roll = accel_X * accel_X + accel_Z * accel_Z;
|
||||
float rollRadians = (float)atan2(accel_Y, sqrt(t_roll));
|
||||
|
||||
float t_pitch = accel_Y * accel_Y + accel_Z * accel_Z;
|
||||
float pitchRadians = (float)atan2(accel_X, sqrt(t_pitch));
|
||||
|
||||
float cosRoll = (float)cos(rollRadians);
|
||||
float sinRoll = (float)sin(rollRadians);
|
||||
float cosPitch = (float)cos(-1*pitchRadians);
|
||||
float sinPitch = (float)sin(-1*pitchRadians);
|
||||
|
||||
/* The tilt compensation algorithm */
|
||||
/* Xh = X.cosPitch + Z.sinPitch */
|
||||
/* Yh = X.sinRoll.sinPitch + Y.cosRoll - Z.sinRoll.cosPitch */
|
||||
*mag_X = (*mag_X) * cosPitch + (*mag_Z) * sinPitch;
|
||||
*mag_Y = (*mag_X) * sinRoll * sinPitch + (*mag_Y) * cosRoll - (*mag_Z) * sinRoll * cosPitch;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Populates the .heading fields in the sensors_vec_t
|
||||
struct with the right angular data (0-359<EFBFBD>)
|
||||
|
||||
Heading increases when measuring clockwise
|
||||
|
||||
@param axis The given axis (SENSOR_AXIS_X/Y/Z)
|
||||
|
||||
@param event The raw magnetometer sensor data to use when
|
||||
calculating out heading
|
||||
|
||||
@param orientation The sensors_vec_t object where we will
|
||||
assign an 'orientation.heading' value
|
||||
|
||||
@code
|
||||
|
||||
magGetOrientation(SENSOR_AXIS_Z, &mag_event, &orientation);
|
||||
|
||||
@endcode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_10DOF::magGetOrientation(sensors_axis_t axis, sensors_event_t *event, sensors_vec_t *orientation)
|
||||
{
|
||||
/* Make sure the input is valid, not null, etc. */
|
||||
if (event == NULL) return false;
|
||||
if (orientation == NULL) return false;
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case SENSOR_AXIS_X:
|
||||
/* Sensor rotates around X-axis */
|
||||
/* "heading" is the angle between the 'Y axis' and magnetic north on the horizontal plane (Oyz) */
|
||||
/* heading = atan(Mz / My) */
|
||||
orientation->heading = (float)atan2(event->magnetic.z, event->magnetic.y) * 180 / PI;
|
||||
break;
|
||||
|
||||
case SENSOR_AXIS_Y:
|
||||
/* Sensor rotates around Y-axis */
|
||||
/* "heading" is the angle between the 'Z axis' and magnetic north on the horizontal plane (Ozx) */
|
||||
/* heading = atan(Mx / Mz) */
|
||||
orientation->heading = (float)atan2(event->magnetic.x, event->magnetic.z) * 180 / PI;
|
||||
break;
|
||||
|
||||
case SENSOR_AXIS_Z:
|
||||
/* Sensor rotates around Z-axis */
|
||||
/* "heading" is the angle between the 'X axis' and magnetic north on the horizontal plane (Oxy) */
|
||||
/* heading = atan(My / Mx) */
|
||||
orientation->heading = (float)atan2(event->magnetic.y, event->magnetic.x) * 180 / PI;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Normalize to 0-359<35> */
|
||||
if (orientation->heading < 0)
|
||||
{
|
||||
orientation->heading = 360 + orientation->heading;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Populates the .roll/.pitch/.heading fields in the sensors_vec_t
|
||||
struct with the right angular data (in degree).
|
||||
|
||||
The starting position is set by placing the object flat and
|
||||
pointing northwards (Z-axis pointing upward and X-axis pointing
|
||||
northwards).
|
||||
|
||||
The orientation of the object can be modeled as resulting from
|
||||
3 consecutive rotations in turn: heading (Z-axis), pitch (Y-axis),
|
||||
and roll (X-axis) applied to the starting position.
|
||||
|
||||
|
||||
@param accel_event The sensors_event_t variable containing the
|
||||
data from the accelerometer
|
||||
|
||||
@param mag_event The sensors_event_t variable containing the
|
||||
data from the magnetometer
|
||||
|
||||
@param orientation The sensors_vec_t object that will have it's
|
||||
.roll, .pitch and .heading fields populated
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_10DOF::fusionGetOrientation(sensors_event_t *accel_event, sensors_event_t *mag_event, sensors_vec_t *orientation)
|
||||
{
|
||||
/* Make sure the input is valid, not null, etc. */
|
||||
if ( accel_event == NULL) return false;
|
||||
if ( mag_event == NULL) return false;
|
||||
if ( orientation == NULL) return false;
|
||||
|
||||
float const PI_F = 3.14159265F;
|
||||
|
||||
/* roll: Rotation around the X-axis. -180 <= roll <= 180 */
|
||||
/* a positive roll angle is defined to be a clockwise rotation about the positive X-axis */
|
||||
/* */
|
||||
/* y */
|
||||
/* roll = atan2(---) */
|
||||
/* z */
|
||||
/* */
|
||||
/* where: y, z are returned value from accelerometer sensor */
|
||||
orientation->roll = (float)atan2(accel_event->acceleration.y, accel_event->acceleration.z);
|
||||
|
||||
/* pitch: Rotation around the Y-axis. -180 <= roll <= 180 */
|
||||
/* a positive pitch angle is defined to be a clockwise rotation about the positive Y-axis */
|
||||
/* */
|
||||
/* -x */
|
||||
/* pitch = atan(-------------------------------) */
|
||||
/* y * sin(roll) + z * cos(roll) */
|
||||
/* */
|
||||
/* where: x, y, z are returned value from accelerometer sensor */
|
||||
if (accel_event->acceleration.y * sin(orientation->roll) + accel_event->acceleration.z * cos(orientation->roll) == 0)
|
||||
orientation->pitch = accel_event->acceleration.x > 0 ? (PI_F / 2) : (-PI_F / 2);
|
||||
else
|
||||
orientation->pitch = (float)atan(-accel_event->acceleration.x / (accel_event->acceleration.y * sin(orientation->roll) + \
|
||||
accel_event->acceleration.z * cos(orientation->roll)));
|
||||
|
||||
/* heading: Rotation around the Z-axis. -180 <= roll <= 180 */
|
||||
/* a positive heading angle is defined to be a clockwise rotation about the positive Z-axis */
|
||||
/* */
|
||||
/* z * sin(roll) - y * cos(roll) */
|
||||
/* heading = atan2(--------------------------------------------------------------------------) */
|
||||
/* x * cos(pitch) + y * sin(pitch) * sin(roll) + z * sin(pitch) * cos(roll)) */
|
||||
/* */
|
||||
/* where: x, y, z are returned value from magnetometer sensor */
|
||||
orientation->heading = (float)atan2(mag_event->magnetic.z * sin(orientation->roll) - mag_event->magnetic.y * cos(orientation->roll), \
|
||||
mag_event->magnetic.x * cos(orientation->pitch) + \
|
||||
mag_event->magnetic.y * sin(orientation->pitch) * sin(orientation->roll) + \
|
||||
mag_event->magnetic.z * sin(orientation->pitch) * cos(orientation->roll));
|
||||
|
||||
|
||||
/* Convert angular data to degree */
|
||||
orientation->roll = orientation->roll * 180 / PI_F;
|
||||
orientation->pitch = orientation->pitch * 180 / PI_F;
|
||||
orientation->heading = orientation->heading * 180 / PI_F;
|
||||
|
||||
return true;
|
||||
}
|
||||
53
Adafruit_10DOF.h
Normal file
53
Adafruit_10DOF.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/***************************************************************************
|
||||
This is a library for the Adafruit 10DOF Breakout
|
||||
|
||||
Designed specifically to work with the Adafruit 10DOF Breakout
|
||||
|
||||
These displays 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!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#ifndef __ADAFRUIT_10DOF_H__
|
||||
#define __ADAFRUIT_10DOF_H__
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "Adafruit_Sensor.h"
|
||||
#include "Adafruit_LSM303_U.h"
|
||||
#include "Adafruit_BMP085_U.h"
|
||||
#include "Adafruit_L3GD20_U.h"
|
||||
#include <Wire.h>
|
||||
|
||||
/** Sensor axis */
|
||||
typedef enum
|
||||
{
|
||||
SENSOR_AXIS_X = (1),
|
||||
SENSOR_AXIS_Y = (2),
|
||||
SENSOR_AXIS_Z = (3)
|
||||
} sensors_axis_t;
|
||||
|
||||
/* Driver for the the 10DOF breakout sensors */
|
||||
class Adafruit_10DOF
|
||||
{
|
||||
public:
|
||||
Adafruit_10DOF(void);
|
||||
bool begin(void);
|
||||
|
||||
bool accelGetOrientation ( sensors_event_t *event, sensors_vec_t *orientation );
|
||||
bool magTiltCompensation ( sensors_axis_t axis, sensors_event_t *mag_event, sensors_event_t *accel_event );
|
||||
bool magGetOrientation ( sensors_axis_t axis, sensors_event_t *event, sensors_vec_t *mag_orientation );
|
||||
bool fusionGetOrientation ( sensors_event_t *accel_event, sensors_event_t *mag_event, sensors_vec_t *orientation );
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
481
Adafruit_BMP085_U.cpp
Normal file
481
Adafruit_BMP085_U.cpp
Normal file
|
|
@ -0,0 +1,481 @@
|
|||
/***************************************************************************
|
||||
This is a library for the BMP085 pressure sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
----> http://www.adafruit.com/products/391
|
||||
----> http://www.adafruit.com/products/1603
|
||||
|
||||
These displays 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!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "Adafruit_BMP085_U.h"
|
||||
|
||||
static bmp085_calib_data _bmp085_coeffs; // Last read accelerometer data will be available here
|
||||
static uint8_t _bmp085Mode;
|
||||
|
||||
#define BMP085_USE_DATASHEET_VALS (0) /* Set to 1 for sanity check */
|
||||
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void writeCommand(byte reg, byte value)
|
||||
{
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)value);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void read8(byte reg, uint8_t *value)
|
||||
{
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)1);
|
||||
#if ARDUINO >= 100
|
||||
*value = Wire.read();
|
||||
#else
|
||||
*value = Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a 16 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void read16(byte reg, uint16_t *value)
|
||||
{
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)2);
|
||||
#if ARDUINO >= 100
|
||||
*value = (Wire.read() << 8) | Wire.read();
|
||||
#else
|
||||
*value = (Wire.receive() << 8) | Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a signed 16 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readS16(byte reg, int16_t *value)
|
||||
{
|
||||
uint16_t i;
|
||||
read16(reg, &i);
|
||||
*value = (int16_t)i;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the factory-set coefficients
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readCoefficients(void)
|
||||
{
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
_bmp085_coeffs.ac1 = 408;
|
||||
_bmp085_coeffs.ac2 = -72;
|
||||
_bmp085_coeffs.ac3 = -14383;
|
||||
_bmp085_coeffs.ac4 = 32741;
|
||||
_bmp085_coeffs.ac5 = 32757;
|
||||
_bmp085_coeffs.ac6 = 23153;
|
||||
_bmp085_coeffs.b1 = 6190;
|
||||
_bmp085_coeffs.b2 = 4;
|
||||
_bmp085_coeffs.mb = -32768;
|
||||
_bmp085_coeffs.mc = -8711;
|
||||
_bmp085_coeffs.md = 2868;
|
||||
_bmp085Mode = 0;
|
||||
#else
|
||||
readS16(BMP085_REGISTER_CAL_AC1, &_bmp085_coeffs.ac1);
|
||||
readS16(BMP085_REGISTER_CAL_AC2, &_bmp085_coeffs.ac2);
|
||||
readS16(BMP085_REGISTER_CAL_AC3, &_bmp085_coeffs.ac3);
|
||||
read16(BMP085_REGISTER_CAL_AC4, &_bmp085_coeffs.ac4);
|
||||
read16(BMP085_REGISTER_CAL_AC5, &_bmp085_coeffs.ac5);
|
||||
read16(BMP085_REGISTER_CAL_AC6, &_bmp085_coeffs.ac6);
|
||||
readS16(BMP085_REGISTER_CAL_B1, &_bmp085_coeffs.b1);
|
||||
readS16(BMP085_REGISTER_CAL_B2, &_bmp085_coeffs.b2);
|
||||
readS16(BMP085_REGISTER_CAL_MB, &_bmp085_coeffs.mb);
|
||||
readS16(BMP085_REGISTER_CAL_MC, &_bmp085_coeffs.mc);
|
||||
readS16(BMP085_REGISTER_CAL_MD, &_bmp085_coeffs.md);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readRawTemperature(int32_t *temperature)
|
||||
{
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
*temperature = 27898;
|
||||
#else
|
||||
uint16_t t;
|
||||
writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READTEMPCMD);
|
||||
delay(5);
|
||||
read16(BMP085_REGISTER_TEMPDATA, &t);
|
||||
*temperature = t;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readRawPressure(int32_t *pressure)
|
||||
{
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
*pressure = 23843;
|
||||
#else
|
||||
uint8_t p8;
|
||||
uint16_t p16;
|
||||
int32_t p32;
|
||||
|
||||
writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READPRESSURECMD + (_bmp085Mode << 6));
|
||||
switch(_bmp085Mode)
|
||||
{
|
||||
case BMP085_MODE_ULTRALOWPOWER:
|
||||
delay(5);
|
||||
break;
|
||||
case BMP085_MODE_STANDARD:
|
||||
delay(8);
|
||||
break;
|
||||
case BMP085_MODE_HIGHRES:
|
||||
delay(14);
|
||||
break;
|
||||
case BMP085_MODE_ULTRAHIGHRES:
|
||||
default:
|
||||
delay(26);
|
||||
break;
|
||||
}
|
||||
|
||||
read16(BMP085_REGISTER_PRESSUREDATA, &p16);
|
||||
p32 = (uint32_t)p16 << 8;
|
||||
read8(BMP085_REGISTER_PRESSUREDATA+2, &p8);
|
||||
p32 += p8;
|
||||
p32 >>= (8 - _bmp085Mode);
|
||||
|
||||
*pressure = p32;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Compute B5 coefficient used in temperature & pressure calcs.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int32_t Adafruit_BMP085_Unified::computeB5(int32_t ut) {
|
||||
int32_t X1 = (ut - (int32_t)_bmp085_coeffs.ac6) * ((int32_t)_bmp085_coeffs.ac5) >> 15;
|
||||
int32_t X2 = ((int32_t)_bmp085_coeffs.mc << 11) / (X1+(int32_t)_bmp085_coeffs.md);
|
||||
return X1 + X2;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new Adafruit_BMP085_Unified class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_BMP085_Unified::Adafruit_BMP085_Unified(int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BMP085_Unified::begin(bmp085_mode_t mode)
|
||||
{
|
||||
// Enable I2C
|
||||
Wire.begin();
|
||||
|
||||
/* Mode boundary check */
|
||||
if ((mode > BMP085_MODE_ULTRAHIGHRES) || (mode < 0))
|
||||
{
|
||||
mode = BMP085_MODE_ULTRAHIGHRES;
|
||||
}
|
||||
|
||||
/* Make sure we have the right device */
|
||||
uint8_t id;
|
||||
read8(BMP085_REGISTER_CHIPID, &id);
|
||||
if(id != 0x55)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the mode indicator */
|
||||
_bmp085Mode = mode;
|
||||
|
||||
/* Coefficients need to be read once */
|
||||
readCoefficients();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the compensated pressure level in kPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getPressure(float *pressure)
|
||||
{
|
||||
int32_t ut = 0, up = 0, compp = 0;
|
||||
int32_t x1, x2, b5, b6, x3, b3, p;
|
||||
uint32_t b4, b7;
|
||||
|
||||
/* Get the raw pressure and temperature values */
|
||||
readRawTemperature(&ut);
|
||||
readRawPressure(&up);
|
||||
|
||||
/* Temperature compensation */
|
||||
b5 = computeB5(ut);
|
||||
|
||||
/* Pressure compensation */
|
||||
b6 = b5 - 4000;
|
||||
x1 = (_bmp085_coeffs.b2 * ((b6 * b6) >> 12)) >> 11;
|
||||
x2 = (_bmp085_coeffs.ac2 * b6) >> 11;
|
||||
x3 = x1 + x2;
|
||||
b3 = (((((int32_t) _bmp085_coeffs.ac1) * 4 + x3) << _bmp085Mode) + 2) >> 2;
|
||||
x1 = (_bmp085_coeffs.ac3 * b6) >> 13;
|
||||
x2 = (_bmp085_coeffs.b1 * ((b6 * b6) >> 12)) >> 16;
|
||||
x3 = ((x1 + x2) + 2) >> 2;
|
||||
b4 = (_bmp085_coeffs.ac4 * (uint32_t) (x3 + 32768)) >> 15;
|
||||
b7 = ((uint32_t) (up - b3) * (50000 >> _bmp085Mode));
|
||||
|
||||
if (b7 < 0x80000000)
|
||||
{
|
||||
p = (b7 << 1) / b4;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = (b7 / b4) << 1;
|
||||
}
|
||||
|
||||
x1 = (p >> 8) * (p >> 8);
|
||||
x1 = (x1 * 3038) >> 16;
|
||||
x2 = (-7357 * p) >> 16;
|
||||
compp = p + ((x1 + x2 + 3791) >> 4);
|
||||
|
||||
/* Assign compensated pressure value */
|
||||
*pressure = compp;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the temperatures in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getTemperature(float *temp)
|
||||
{
|
||||
int32_t UT, X1, X2, B5; // following ds convention
|
||||
float t;
|
||||
|
||||
readRawTemperature(&UT);
|
||||
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
// use datasheet numbers!
|
||||
UT = 27898;
|
||||
_bmp085_coeffs.ac6 = 23153;
|
||||
_bmp085_coeffs.ac5 = 32757;
|
||||
_bmp085_coeffs.mc = -8711;
|
||||
_bmp085_coeffs.md = 2868;
|
||||
#endif
|
||||
|
||||
B5 = computeB5(UT);
|
||||
t = (B5+8) >> 4;
|
||||
t /= 10;
|
||||
|
||||
*temp = t;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the altitude (in meters) from the specified atmospheric
|
||||
pressure (in hPa), and sea-level pressure (in hPa).
|
||||
|
||||
@param seaLevel Sea-level pressure in hPa
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel, float atmospheric)
|
||||
{
|
||||
// Equation taken from BMP180 datasheet (page 16):
|
||||
// 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 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the altitude (in meters) from the specified atmospheric
|
||||
pressure (in hPa), and sea-level pressure (in hPa). Note that this
|
||||
function just calls the overload of pressureToAltitude which takes
|
||||
seaLevel and atmospheric pressure--temperature is ignored. The original
|
||||
implementation of this function was based on calculations from Wikipedia
|
||||
which are not accurate at higher altitudes. To keep compatibility with
|
||||
old code this function remains with the same interface, but it calls the
|
||||
more accurate calculation.
|
||||
|
||||
@param seaLevel Sea-level pressure in hPa
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
@param temp Temperature in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel, float atmospheric, float temp)
|
||||
{
|
||||
return pressureToAltitude(seaLevel, atmospheric);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the pressure at sea level (in hPa) from the specified altitude
|
||||
(in meters), and atmospheric pressure (in hPa).
|
||||
|
||||
@param altitude Altitude in meters
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::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);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the pressure at sea level (in hPa) from the specified altitude
|
||||
(in meters), and atmospheric pressure (in hPa). Note that this
|
||||
function just calls the overload of seaLevelForAltitude which takes
|
||||
altitude and atmospheric pressure--temperature is ignored. The original
|
||||
implementation of this function was based on calculations from Wikipedia
|
||||
which are not accurate at higher altitudes. To keep compatibility with
|
||||
old code this function remains with the same interface, but it calls the
|
||||
more accurate calculation.
|
||||
|
||||
@param altitude Altitude in meters
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
@param temp Temperature in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude, float atmospheric, float temp)
|
||||
{
|
||||
return seaLevelForAltitude(altitude, atmospheric);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Provides the sensor_t data for this sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::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, "BMP085", 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->max_value = 300.0F; // 300..1100 hPa
|
||||
sensor->min_value = 1100.0F;
|
||||
sensor->resolution = 0.01F; // Datasheet states 0.01 hPa resolution
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the sensor and returns the data as a sensors_event_t
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BMP085_Unified::getEvent(sensors_event_t *event)
|
||||
{
|
||||
float pressure_kPa;
|
||||
|
||||
/* 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 = 0;
|
||||
getPressure(&pressure_kPa);
|
||||
event->pressure = pressure_kPa / 100.0F;
|
||||
|
||||
return true;
|
||||
}
|
||||
122
Adafruit_BMP085_U.h
Normal file
122
Adafruit_BMP085_U.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/***************************************************************************
|
||||
This is a library for the BMP085 pressure sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
----> http://www.adafruit.com/products/391
|
||||
----> http://www.adafruit.com/products/1603
|
||||
|
||||
These displays 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!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#ifndef __BMP085_H__
|
||||
#define __BMP085_H__
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "Adafruit_Sensor.h"
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
/*=========================================================================
|
||||
I2C ADDRESS/BITS
|
||||
-----------------------------------------------------------------------*/
|
||||
#define BMP085_ADDRESS (0x77)
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
REGISTERS
|
||||
-----------------------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
BMP085_REGISTER_CAL_AC1 = 0xAA, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC2 = 0xAC, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC3 = 0xAE, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC4 = 0xB0, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC5 = 0xB2, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC6 = 0xB4, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_B1 = 0xB6, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_B2 = 0xB8, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MB = 0xBA, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MC = 0xBC, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MD = 0xBE, // R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CHIPID = 0xD0,
|
||||
BMP085_REGISTER_VERSION = 0xD1,
|
||||
BMP085_REGISTER_SOFTRESET = 0xE0,
|
||||
BMP085_REGISTER_CONTROL = 0xF4,
|
||||
BMP085_REGISTER_TEMPDATA = 0xF6,
|
||||
BMP085_REGISTER_PRESSUREDATA = 0xF6,
|
||||
BMP085_REGISTER_READTEMPCMD = 0x2E,
|
||||
BMP085_REGISTER_READPRESSURECMD = 0x34
|
||||
};
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
MODE SETTINGS
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
BMP085_MODE_ULTRALOWPOWER = 0,
|
||||
BMP085_MODE_STANDARD = 1,
|
||||
BMP085_MODE_HIGHRES = 2,
|
||||
BMP085_MODE_ULTRAHIGHRES = 3
|
||||
} bmp085_mode_t;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
CALIBRATION DATA
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef struct
|
||||
{
|
||||
int16_t ac1;
|
||||
int16_t ac2;
|
||||
int16_t ac3;
|
||||
uint16_t ac4;
|
||||
uint16_t ac5;
|
||||
uint16_t ac6;
|
||||
int16_t b1;
|
||||
int16_t b2;
|
||||
int16_t mb;
|
||||
int16_t mc;
|
||||
int16_t md;
|
||||
} bmp085_calib_data;
|
||||
/*=========================================================================*/
|
||||
|
||||
class Adafruit_BMP085_Unified : public Adafruit_Sensor
|
||||
{
|
||||
public:
|
||||
Adafruit_BMP085_Unified(int32_t sensorID = -1);
|
||||
|
||||
bool begin(bmp085_mode_t mode = BMP085_MODE_ULTRAHIGHRES);
|
||||
void getTemperature(float *temp);
|
||||
void getPressure(float *pressure);
|
||||
float pressureToAltitude(float seaLvel, float atmospheric);
|
||||
float seaLevelForAltitude(float altitude, float atmospheric);
|
||||
// Note that the next two functions are just for compatibility with old
|
||||
// code that passed the temperature as a third parameter. A newer
|
||||
// calculation is used which does not need temperature.
|
||||
float pressureToAltitude(float seaLevel, float atmospheric, float temp);
|
||||
float seaLevelForAltitude(float altitude, float atmospheric, float temp);
|
||||
bool getEvent(sensors_event_t*);
|
||||
void getSensor(sensor_t*);
|
||||
|
||||
private:
|
||||
int32_t computeB5(int32_t ut);
|
||||
int32_t _sensorID;
|
||||
};
|
||||
|
||||
#endif
|
||||
500
Adafruit_GPS.cpp
Normal file
500
Adafruit_GPS.cpp
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
/***********************************
|
||||
This is our GPS library
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, check license.txt for more information
|
||||
All text above must be included in any redistribution
|
||||
****************************************/
|
||||
#ifdef __AVR__
|
||||
// Only include software serial on AVR platforms (i.e. not on Due).
|
||||
#include <SoftwareSerial.h>
|
||||
#endif
|
||||
#include "Adafruit_GPS.h"
|
||||
|
||||
// how long are max NMEA lines to parse?
|
||||
#define MAXLINELENGTH 120
|
||||
|
||||
// we double buffer: read one line in and leave one for the main program
|
||||
volatile char line1[MAXLINELENGTH];
|
||||
volatile char line2[MAXLINELENGTH];
|
||||
// our index into filling the current line
|
||||
volatile uint8_t lineidx=0;
|
||||
// pointers to the double buffers
|
||||
volatile char *currentline;
|
||||
volatile char *lastline;
|
||||
volatile boolean recvdflag;
|
||||
volatile boolean inStandbyMode;
|
||||
|
||||
|
||||
boolean Adafruit_GPS::parse(char *nmea) {
|
||||
// do checksum check
|
||||
|
||||
// first look if we even have one
|
||||
if (nmea[strlen(nmea)-4] == '*') {
|
||||
uint16_t sum = parseHex(nmea[strlen(nmea)-3]) * 16;
|
||||
sum += parseHex(nmea[strlen(nmea)-2]);
|
||||
|
||||
// check checksum
|
||||
for (uint8_t i=1; i < (strlen(nmea)-4); i++) {
|
||||
sum ^= nmea[i];
|
||||
}
|
||||
if (sum != 0) {
|
||||
// bad checksum :(
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
int32_t degree;
|
||||
long minutes;
|
||||
char degreebuff[10];
|
||||
// look for a few common sentences
|
||||
if (strstr(nmea, "$GPGGA")) {
|
||||
// found GGA
|
||||
char *p = nmea;
|
||||
// get time
|
||||
p = strchr(p, ',')+1;
|
||||
float timef = atof(p);
|
||||
uint32_t time = timef;
|
||||
hour = time / 10000;
|
||||
minute = (time % 10000) / 100;
|
||||
seconds = (time % 100);
|
||||
|
||||
milliseconds = fmod(timef, 1.0) * 1000;
|
||||
|
||||
// parse out latitude
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
strncpy(degreebuff, p, 2);
|
||||
p += 2;
|
||||
degreebuff[2] = '\0';
|
||||
degree = atol(degreebuff) * 10000000;
|
||||
strncpy(degreebuff, p, 2); // minutes
|
||||
p += 3; // skip decimal point
|
||||
strncpy(degreebuff + 2, p, 4);
|
||||
degreebuff[6] = '\0';
|
||||
minutes = 50 * atol(degreebuff) / 3;
|
||||
latitude_fixed = degree + minutes;
|
||||
latitude = degree / 100000 + minutes * 0.000006F;
|
||||
latitudeDegrees = (latitude-100*int(latitude/100))/60.0;
|
||||
latitudeDegrees += int(latitude/100);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
if (p[0] == 'S') latitudeDegrees *= -1.0;
|
||||
if (p[0] == 'N') lat = 'N';
|
||||
else if (p[0] == 'S') lat = 'S';
|
||||
else if (p[0] == ',') lat = 0;
|
||||
else return false;
|
||||
}
|
||||
|
||||
// parse out longitude
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
strncpy(degreebuff, p, 3);
|
||||
p += 3;
|
||||
degreebuff[3] = '\0';
|
||||
degree = atol(degreebuff) * 10000000;
|
||||
strncpy(degreebuff, p, 2); // minutes
|
||||
p += 3; // skip decimal point
|
||||
strncpy(degreebuff + 2, p, 4);
|
||||
degreebuff[6] = '\0';
|
||||
minutes = 50 * atol(degreebuff) / 3;
|
||||
longitude_fixed = degree + minutes;
|
||||
longitude = degree / 100000 + minutes * 0.000006F;
|
||||
longitudeDegrees = (longitude-100*int(longitude/100))/60.0;
|
||||
longitudeDegrees += int(longitude/100);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
if (p[0] == 'W') longitudeDegrees *= -1.0;
|
||||
if (p[0] == 'W') lon = 'W';
|
||||
else if (p[0] == 'E') lon = 'E';
|
||||
else if (p[0] == ',') lon = 0;
|
||||
else return false;
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
fixquality = atoi(p);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
satellites = atoi(p);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
HDOP = atof(p);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
altitude = atof(p);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
geoidheight = atof(p);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (strstr(nmea, "$GPRMC")) {
|
||||
// found RMC
|
||||
char *p = nmea;
|
||||
|
||||
// get time
|
||||
p = strchr(p, ',')+1;
|
||||
float timef = atof(p);
|
||||
uint32_t time = timef;
|
||||
hour = time / 10000;
|
||||
minute = (time % 10000) / 100;
|
||||
seconds = (time % 100);
|
||||
|
||||
milliseconds = fmod(timef, 1.0) * 1000;
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
// Serial.println(p);
|
||||
if (p[0] == 'A')
|
||||
fix = true;
|
||||
else if (p[0] == 'V')
|
||||
fix = false;
|
||||
else
|
||||
return false;
|
||||
|
||||
// parse out latitude
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
strncpy(degreebuff, p, 2);
|
||||
p += 2;
|
||||
degreebuff[2] = '\0';
|
||||
long degree = atol(degreebuff) * 10000000;
|
||||
strncpy(degreebuff, p, 2); // minutes
|
||||
p += 3; // skip decimal point
|
||||
strncpy(degreebuff + 2, p, 4);
|
||||
degreebuff[6] = '\0';
|
||||
long minutes = 50 * atol(degreebuff) / 3;
|
||||
latitude_fixed = degree + minutes;
|
||||
latitude = degree / 100000 + minutes * 0.000006F;
|
||||
latitudeDegrees = (latitude-100*int(latitude/100))/60.0;
|
||||
latitudeDegrees += int(latitude/100);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
if (p[0] == 'S') latitudeDegrees *= -1.0;
|
||||
if (p[0] == 'N') lat = 'N';
|
||||
else if (p[0] == 'S') lat = 'S';
|
||||
else if (p[0] == ',') lat = 0;
|
||||
else return false;
|
||||
}
|
||||
|
||||
// parse out longitude
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
strncpy(degreebuff, p, 3);
|
||||
p += 3;
|
||||
degreebuff[3] = '\0';
|
||||
degree = atol(degreebuff) * 10000000;
|
||||
strncpy(degreebuff, p, 2); // minutes
|
||||
p += 3; // skip decimal point
|
||||
strncpy(degreebuff + 2, p, 4);
|
||||
degreebuff[6] = '\0';
|
||||
minutes = 50 * atol(degreebuff) / 3;
|
||||
longitude_fixed = degree + minutes;
|
||||
longitude = degree / 100000 + minutes * 0.000006F;
|
||||
longitudeDegrees = (longitude-100*int(longitude/100))/60.0;
|
||||
longitudeDegrees += int(longitude/100);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
if (p[0] == 'W') longitudeDegrees *= -1.0;
|
||||
if (p[0] == 'W') lon = 'W';
|
||||
else if (p[0] == 'E') lon = 'E';
|
||||
else if (p[0] == ',') lon = 0;
|
||||
else return false;
|
||||
}
|
||||
// speed
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
speed = atof(p);
|
||||
}
|
||||
|
||||
// angle
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
angle = atof(p);
|
||||
}
|
||||
|
||||
p = strchr(p, ',')+1;
|
||||
if (',' != *p)
|
||||
{
|
||||
uint32_t fulldate = atof(p);
|
||||
day = fulldate / 10000;
|
||||
month = (fulldate % 10000) / 100;
|
||||
year = (fulldate % 100);
|
||||
}
|
||||
// we dont parse the remaining, yet!
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char Adafruit_GPS::read(void) {
|
||||
char c = 0;
|
||||
|
||||
if (paused) return c;
|
||||
|
||||
#ifdef __AVR__
|
||||
if(gpsSwSerial) {
|
||||
if(!gpsSwSerial->available()) return c;
|
||||
c = gpsSwSerial->read();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if(!gpsHwSerial->available()) return c;
|
||||
c = gpsHwSerial->read();
|
||||
}
|
||||
|
||||
//Serial.print(c);
|
||||
|
||||
// if (c == '$') { //please don't eat the dollar sign - rdl 9/15/14
|
||||
// currentline[lineidx] = 0;
|
||||
// lineidx = 0;
|
||||
// }
|
||||
if (c == '\n') {
|
||||
currentline[lineidx] = 0;
|
||||
|
||||
if (currentline == line1) {
|
||||
currentline = line2;
|
||||
lastline = line1;
|
||||
} else {
|
||||
currentline = line1;
|
||||
lastline = line2;
|
||||
}
|
||||
|
||||
//Serial.println("----");
|
||||
//Serial.println((char *)lastline);
|
||||
//Serial.println("----");
|
||||
lineidx = 0;
|
||||
recvdflag = true;
|
||||
}
|
||||
|
||||
currentline[lineidx++] = c;
|
||||
if (lineidx >= MAXLINELENGTH)
|
||||
lineidx = MAXLINELENGTH-1;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifdef __AVR__
|
||||
// Constructor when using SoftwareSerial or NewSoftSerial
|
||||
#if ARDUINO >= 100
|
||||
Adafruit_GPS::Adafruit_GPS(SoftwareSerial *ser)
|
||||
#else
|
||||
Adafruit_GPS::Adafruit_GPS(NewSoftSerial *ser)
|
||||
#endif
|
||||
{
|
||||
common_init(); // Set everything to common state, then...
|
||||
gpsSwSerial = ser; // ...override gpsSwSerial with value passed.
|
||||
}
|
||||
#endif
|
||||
|
||||
// Constructor when using HardwareSerial
|
||||
Adafruit_GPS::Adafruit_GPS(HardwareSerial *ser) {
|
||||
common_init(); // Set everything to common state, then...
|
||||
gpsHwSerial = ser; // ...override gpsHwSerial with value passed.
|
||||
}
|
||||
|
||||
// Initialization code used by all constructor types
|
||||
void Adafruit_GPS::common_init(void) {
|
||||
#ifdef __AVR__
|
||||
gpsSwSerial = NULL; // Set both to NULL, then override correct
|
||||
#endif
|
||||
gpsHwSerial = NULL; // port pointer in corresponding constructor
|
||||
recvdflag = false;
|
||||
paused = false;
|
||||
lineidx = 0;
|
||||
currentline = line1;
|
||||
lastline = line2;
|
||||
|
||||
hour = minute = seconds = year = month = day =
|
||||
fixquality = satellites = 0; // uint8_t
|
||||
lat = lon = mag = 0; // char
|
||||
fix = false; // boolean
|
||||
milliseconds = 0; // uint16_t
|
||||
latitude = longitude = geoidheight = altitude =
|
||||
speed = angle = magvariation = HDOP = 0.0; // float
|
||||
}
|
||||
|
||||
void Adafruit_GPS::begin(uint16_t baud)
|
||||
{
|
||||
#ifdef __AVR__
|
||||
if(gpsSwSerial)
|
||||
gpsSwSerial->begin(baud);
|
||||
else
|
||||
gpsHwSerial->begin(baud);
|
||||
#endif
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void Adafruit_GPS::sendCommand(const char *str) {
|
||||
#ifdef __AVR__
|
||||
if(gpsSwSerial)
|
||||
gpsSwSerial->println(str);
|
||||
else
|
||||
#endif
|
||||
gpsHwSerial->println(str);
|
||||
}
|
||||
|
||||
boolean Adafruit_GPS::newNMEAreceived(void) {
|
||||
return recvdflag;
|
||||
}
|
||||
|
||||
void Adafruit_GPS::pause(boolean p) {
|
||||
paused = p;
|
||||
}
|
||||
|
||||
char *Adafruit_GPS::lastNMEA(void) {
|
||||
recvdflag = false;
|
||||
return (char *)lastline;
|
||||
}
|
||||
|
||||
// read a Hex value and return the decimal equivalent
|
||||
uint8_t Adafruit_GPS::parseHex(char c) {
|
||||
if (c < '0')
|
||||
return 0;
|
||||
if (c <= '9')
|
||||
return c - '0';
|
||||
if (c < 'A')
|
||||
return 0;
|
||||
if (c <= 'F')
|
||||
return (c - 'A')+10;
|
||||
// if (c > 'F')
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean Adafruit_GPS::waitForSentence(const char *wait4me, uint8_t max) {
|
||||
char str[20];
|
||||
|
||||
uint8_t i=0;
|
||||
while (i < max) {
|
||||
if (newNMEAreceived()) {
|
||||
char *nmea = lastNMEA();
|
||||
strncpy(str, nmea, 20);
|
||||
str[19] = 0;
|
||||
i++;
|
||||
|
||||
if (strstr(str, wait4me))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean Adafruit_GPS::LOCUS_StartLogger(void) {
|
||||
sendCommand(PMTK_LOCUS_STARTLOG);
|
||||
recvdflag = false;
|
||||
return waitForSentence(PMTK_LOCUS_STARTSTOPACK);
|
||||
}
|
||||
|
||||
boolean Adafruit_GPS::LOCUS_StopLogger(void) {
|
||||
sendCommand(PMTK_LOCUS_STOPLOG);
|
||||
recvdflag = false;
|
||||
return waitForSentence(PMTK_LOCUS_STARTSTOPACK);
|
||||
}
|
||||
|
||||
boolean Adafruit_GPS::LOCUS_ReadStatus(void) {
|
||||
sendCommand(PMTK_LOCUS_QUERY_STATUS);
|
||||
|
||||
if (! waitForSentence("$PMTKLOG"))
|
||||
return false;
|
||||
|
||||
char *response = lastNMEA();
|
||||
uint16_t parsed[10];
|
||||
uint8_t i;
|
||||
|
||||
for (i=0; i<10; i++) parsed[i] = -1;
|
||||
|
||||
response = strchr(response, ',');
|
||||
for (i=0; i<10; i++) {
|
||||
if (!response || (response[0] == 0) || (response[0] == '*'))
|
||||
break;
|
||||
response++;
|
||||
parsed[i]=0;
|
||||
while ((response[0] != ',') &&
|
||||
(response[0] != '*') && (response[0] != 0)) {
|
||||
parsed[i] *= 10;
|
||||
char c = response[0];
|
||||
if (isDigit(c))
|
||||
parsed[i] += c - '0';
|
||||
else
|
||||
parsed[i] = c;
|
||||
response++;
|
||||
}
|
||||
}
|
||||
LOCUS_serial = parsed[0];
|
||||
LOCUS_type = parsed[1];
|
||||
if (isAlpha(parsed[2])) {
|
||||
parsed[2] = parsed[2] - 'a' + 10;
|
||||
}
|
||||
LOCUS_mode = parsed[2];
|
||||
LOCUS_config = parsed[3];
|
||||
LOCUS_interval = parsed[4];
|
||||
LOCUS_distance = parsed[5];
|
||||
LOCUS_speed = parsed[6];
|
||||
LOCUS_status = !parsed[7];
|
||||
LOCUS_records = parsed[8];
|
||||
LOCUS_percent = parsed[9];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Standby Mode Switches
|
||||
boolean Adafruit_GPS::standby(void) {
|
||||
if (inStandbyMode) {
|
||||
return false; // Returns false if already in standby mode, so that you do not wake it up by sending commands to GPS
|
||||
}
|
||||
else {
|
||||
inStandbyMode = true;
|
||||
sendCommand(PMTK_STANDBY);
|
||||
//return waitForSentence(PMTK_STANDBY_SUCCESS); // don't seem to be fast enough to catch the message, or something else just is not working
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean Adafruit_GPS::wakeup(void) {
|
||||
if (inStandbyMode) {
|
||||
inStandbyMode = false;
|
||||
sendCommand(""); // send byte to wake it up
|
||||
return waitForSentence(PMTK_AWAKE);
|
||||
}
|
||||
else {
|
||||
return false; // Returns false if not in standby mode, nothing to wakeup
|
||||
}
|
||||
}
|
||||
168
Adafruit_GPS.h
Normal file
168
Adafruit_GPS.h
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/***********************************
|
||||
This is the Adafruit GPS library - the ultimate GPS library
|
||||
for the ultimate GPS module!
|
||||
|
||||
Tested and works great with the Adafruit Ultimate GPS module
|
||||
using MTK33x9 chipset
|
||||
------> http://www.adafruit.com/products/746
|
||||
Pick one up today at the Adafruit electronics shop
|
||||
and help support open source hardware & software! -ada
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, check license.txt for more information
|
||||
All text above must be included in any redistribution
|
||||
****************************************/
|
||||
// Fllybob added lines 34,35 and 40,41 to add 100mHz logging capability
|
||||
|
||||
#ifndef _ADAFRUIT_GPS_H
|
||||
#define _ADAFRUIT_GPS_H
|
||||
|
||||
#ifdef __AVR__
|
||||
#if ARDUINO >= 100
|
||||
#include <SoftwareSerial.h>
|
||||
#else
|
||||
#include <NewSoftSerial.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// different commands to set the update rate from once a second (1 Hz) to 10 times a second (10Hz)
|
||||
// Note that these only control the rate at which the position is echoed, to actually speed up the
|
||||
// position fix you must also send one of the position fix rate commands below too.
|
||||
#define PMTK_SET_NMEA_UPDATE_100_MILLIHERTZ "$PMTK220,10000*2F" // Once every 10 seconds, 100 millihertz.
|
||||
#define PMTK_SET_NMEA_UPDATE_200_MILLIHERTZ "$PMTK220,5000*1B" // Once every 5 seconds, 200 millihertz.
|
||||
#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F"
|
||||
#define PMTK_SET_NMEA_UPDATE_5HZ "$PMTK220,200*2C"
|
||||
#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F"
|
||||
// Position fix update rate commands.
|
||||
#define PMTK_API_SET_FIX_CTL_100_MILLIHERTZ "$PMTK300,10000,0,0,0,0*2C" // Once every 10 seconds, 100 millihertz.
|
||||
#define PMTK_API_SET_FIX_CTL_200_MILLIHERTZ "$PMTK300,5000,0,0,0,0*18" // Once every 5 seconds, 200 millihertz.
|
||||
#define PMTK_API_SET_FIX_CTL_1HZ "$PMTK300,1000,0,0,0,0*1C"
|
||||
#define PMTK_API_SET_FIX_CTL_5HZ "$PMTK300,200,0,0,0,0*2F"
|
||||
// Can't fix position faster than 5 times a second!
|
||||
|
||||
|
||||
#define PMTK_SET_BAUD_57600 "$PMTK251,57600*2C"
|
||||
#define PMTK_SET_BAUD_9600 "$PMTK251,9600*17"
|
||||
|
||||
// turn on only the second sentence (GPRMC)
|
||||
#define PMTK_SET_NMEA_OUTPUT_RMCONLY "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29"
|
||||
// turn on GPRMC and GGA
|
||||
#define PMTK_SET_NMEA_OUTPUT_RMCGGA "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28"
|
||||
// turn on ALL THE DATA
|
||||
#define PMTK_SET_NMEA_OUTPUT_ALLDATA "$PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28"
|
||||
// turn off output
|
||||
#define PMTK_SET_NMEA_OUTPUT_OFF "$PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28"
|
||||
|
||||
// to generate your own sentences, check out the MTK command datasheet and use a checksum calculator
|
||||
// such as the awesome http://www.hhhh.org/wiml/proj/nmeaxor.html
|
||||
|
||||
#define PMTK_LOCUS_STARTLOG "$PMTK185,0*22"
|
||||
#define PMTK_LOCUS_STOPLOG "$PMTK185,1*23"
|
||||
#define PMTK_LOCUS_STARTSTOPACK "$PMTK001,185,3*3C"
|
||||
#define PMTK_LOCUS_QUERY_STATUS "$PMTK183*38"
|
||||
#define PMTK_LOCUS_ERASE_FLASH "$PMTK184,1*22"
|
||||
#define LOCUS_OVERLAP 0
|
||||
#define LOCUS_FULLSTOP 1
|
||||
|
||||
#define PMTK_ENABLE_SBAS "$PMTK313,1*2E"
|
||||
#define PMTK_ENABLE_WAAS "$PMTK301,2*2E"
|
||||
|
||||
// standby command & boot successful message
|
||||
#define PMTK_STANDBY "$PMTK161,0*28"
|
||||
#define PMTK_STANDBY_SUCCESS "$PMTK001,161,3*36" // Not needed currently
|
||||
#define PMTK_AWAKE "$PMTK010,002*2D"
|
||||
|
||||
// ask for the release and version
|
||||
#define PMTK_Q_RELEASE "$PMTK605*31"
|
||||
|
||||
// request for updates on antenna status
|
||||
#define PGCMD_ANTENNA "$PGCMD,33,1*6C"
|
||||
#define PGCMD_NOANTENNA "$PGCMD,33,0*6D"
|
||||
|
||||
// how long to wait when we're looking for a response
|
||||
#define MAXWAITSENTENCE 5
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#if defined (__AVR__) && !defined(__AVR_ATmega32U4__)
|
||||
#include "SoftwareSerial.h"
|
||||
#endif
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#include "NewSoftSerial.h"
|
||||
#endif
|
||||
|
||||
|
||||
class Adafruit_GPS {
|
||||
public:
|
||||
void begin(uint16_t baud);
|
||||
|
||||
#ifdef __AVR__
|
||||
#if ARDUINO >= 100
|
||||
Adafruit_GPS(SoftwareSerial *ser); // Constructor when using SoftwareSerial
|
||||
#else
|
||||
Adafruit_GPS(NewSoftSerial *ser); // Constructor when using NewSoftSerial
|
||||
#endif
|
||||
#endif
|
||||
Adafruit_GPS(HardwareSerial *ser); // Constructor when using HardwareSerial
|
||||
|
||||
char *lastNMEA(void);
|
||||
boolean newNMEAreceived();
|
||||
void common_init(void);
|
||||
|
||||
void sendCommand(const char *);
|
||||
|
||||
void pause(boolean b);
|
||||
|
||||
boolean parseNMEA(char *response);
|
||||
uint8_t parseHex(char c);
|
||||
|
||||
char read(void);
|
||||
boolean parse(char *);
|
||||
void interruptReads(boolean r);
|
||||
|
||||
boolean wakeup(void);
|
||||
boolean standby(void);
|
||||
|
||||
uint8_t hour, minute, seconds, year, month, day;
|
||||
uint16_t milliseconds;
|
||||
// Floating point latitude and longitude value in degrees.
|
||||
float latitude, longitude;
|
||||
// Fixed point latitude and longitude value with degrees stored in units of 1/100000 degrees,
|
||||
// and minutes stored in units of 1/100000 degrees. See pull #13 for more details:
|
||||
// https://github.com/adafruit/Adafruit-GPS-Library/pull/13
|
||||
int32_t latitude_fixed, longitude_fixed;
|
||||
float latitudeDegrees, longitudeDegrees;
|
||||
float geoidheight, altitude;
|
||||
float speed, angle, magvariation, HDOP;
|
||||
char lat, lon, mag;
|
||||
boolean fix;
|
||||
uint8_t fixquality, satellites;
|
||||
|
||||
boolean waitForSentence(const char *wait, uint8_t max = MAXWAITSENTENCE);
|
||||
boolean LOCUS_StartLogger(void);
|
||||
boolean LOCUS_StopLogger(void);
|
||||
boolean LOCUS_ReadStatus(void);
|
||||
|
||||
uint16_t LOCUS_serial, LOCUS_records;
|
||||
uint8_t LOCUS_type, LOCUS_mode, LOCUS_config, LOCUS_interval, LOCUS_distance, LOCUS_speed, LOCUS_status, LOCUS_percent;
|
||||
private:
|
||||
boolean paused;
|
||||
|
||||
uint8_t parseResponse(char *response);
|
||||
#ifdef __AVR__
|
||||
#if ARDUINO >= 100
|
||||
SoftwareSerial *gpsSwSerial;
|
||||
#else
|
||||
NewSoftSerial *gpsSwSerial;
|
||||
#endif
|
||||
#endif
|
||||
HardwareSerial *gpsHwSerial;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
98
Adafruit_HTU21DF.cpp
Normal file
98
Adafruit_HTU21DF.cpp
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/***************************************************
|
||||
This is a library for the HTU21DF Humidity & Temp Sensor
|
||||
|
||||
Designed specifically to work with the HTU21DF sensor from Adafruit
|
||||
----> https://www.adafruit.com/products/1899
|
||||
|
||||
These displays use I2C to communicate, 2 pins are required to
|
||||
interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
#include "Adafruit_HTU21DF.h"
|
||||
//#include <util/delay.h>
|
||||
|
||||
Adafruit_HTU21DF::Adafruit_HTU21DF() {
|
||||
}
|
||||
|
||||
|
||||
boolean Adafruit_HTU21DF::begin(void) {
|
||||
Wire1.begin();
|
||||
|
||||
reset();
|
||||
|
||||
Wire1.beginTransmission(HTU21DF_I2CADDR);
|
||||
Wire1.write(HTU21DF_READREG);
|
||||
Wire1.endTransmission();
|
||||
Wire1.requestFrom(HTU21DF_I2CADDR, 1);
|
||||
return (Wire1.read() == 0x2); // after reset should be 0x2
|
||||
}
|
||||
|
||||
void Adafruit_HTU21DF::reset(void) {
|
||||
Wire1.beginTransmission(HTU21DF_I2CADDR);
|
||||
Wire1.write(HTU21DF_RESET);
|
||||
Wire1.endTransmission();
|
||||
delay(15);
|
||||
}
|
||||
|
||||
|
||||
float Adafruit_HTU21DF::readTemperature(void) {
|
||||
|
||||
// OK lets ready!
|
||||
Wire1.beginTransmission(HTU21DF_I2CADDR);
|
||||
Wire1.write(HTU21DF_READTEMP);
|
||||
Wire1.endTransmission();
|
||||
|
||||
delay(50); // add delay between request and actual read!
|
||||
|
||||
Wire1.requestFrom(HTU21DF_I2CADDR, 3);
|
||||
while (!Wire1.available()) {}
|
||||
|
||||
uint16_t t = Wire1.read();
|
||||
t <<= 8;
|
||||
t |= Wire1.read();
|
||||
|
||||
uint8_t crc = Wire1.read();
|
||||
|
||||
float temp = t;
|
||||
temp *= 175.72;
|
||||
temp /= 65536;
|
||||
temp -= 46.85;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
float Adafruit_HTU21DF::readHumidity(void) {
|
||||
// OK lets ready!
|
||||
Wire1.beginTransmission(HTU21DF_I2CADDR);
|
||||
Wire1.write(HTU21DF_READHUM);
|
||||
Wire1.endTransmission();
|
||||
|
||||
delay(50); // add delay between request and actual read!
|
||||
|
||||
Wire1.requestFrom(HTU21DF_I2CADDR, 3);
|
||||
while (!Wire1.available()) {}
|
||||
|
||||
uint16_t h = Wire1.read();
|
||||
h <<= 8;
|
||||
h |= Wire1.read();
|
||||
|
||||
uint8_t crc = Wire1.read();
|
||||
|
||||
float hum = h;
|
||||
hum *= 125;
|
||||
hum /= 65536;
|
||||
hum -= 6;
|
||||
|
||||
return hum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
45
Adafruit_HTU21DF.h
Normal file
45
Adafruit_HTU21DF.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/***************************************************
|
||||
This is a library for the HTU21D-F Humidity & Temp Sensor
|
||||
|
||||
Designed specifically to work with the HTU21D-F sensor from Adafruit
|
||||
----> https://www.adafruit.com/products/1899
|
||||
|
||||
These displays use I2C to communicate, 2 pins are required to
|
||||
interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#include "Wire.h"
|
||||
extern TwoWire Wire1;
|
||||
|
||||
#define HTU21DF_I2CADDR 0x40
|
||||
#define HTU21DF_READTEMP 0xE3
|
||||
#define HTU21DF_READHUM 0xE5
|
||||
#define HTU21DF_WRITEREG 0xE6
|
||||
#define HTU21DF_READREG 0xE7
|
||||
#define HTU21DF_RESET 0xFE
|
||||
|
||||
|
||||
|
||||
class Adafruit_HTU21DF {
|
||||
public:
|
||||
Adafruit_HTU21DF();
|
||||
boolean begin(void);
|
||||
float readTemperature(void);
|
||||
float readHumidity(void);
|
||||
void reset(void);
|
||||
private:
|
||||
boolean readData(void);
|
||||
float humidity, temp;
|
||||
};
|
||||
|
||||
364
Adafruit_L3GD20_U.cpp
Normal file
364
Adafruit_L3GD20_U.cpp
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
/***************************************************
|
||||
This is a library for the L3GD20 GYROSCOPE
|
||||
|
||||
Designed specifically to work with the Adafruit L3GD20 Breakout
|
||||
----> https://www.adafruit.com/products/1032
|
||||
|
||||
These sensors use I2C or SPI to communicate, 2 pins (I2C)
|
||||
or 4 pins (SPI) are required to interface.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Kevin "KTOWN" Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "Adafruit_L3GD20_U.h"
|
||||
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Abstract away platform differences in Arduino wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_L3GD20_Unified::write8(byte reg, byte value)
|
||||
{
|
||||
Wire.beginTransmission(L3GD20_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)value);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Abstract away platform differences in Arduino wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
byte Adafruit_L3GD20_Unified::read8(byte reg)
|
||||
{
|
||||
byte value;
|
||||
|
||||
Wire.beginTransmission((byte)L3GD20_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((byte)L3GD20_ADDRESS, (byte)1);
|
||||
while (!Wire.available()); // Wait for data to arrive.
|
||||
#if ARDUINO >= 100
|
||||
value = Wire.read();
|
||||
#else
|
||||
value = Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new Adafruit_L3GD20_Unified class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_L3GD20_Unified::Adafruit_L3GD20_Unified(int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
_autoRangeEnabled = false;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_L3GD20_Unified::begin(gyroRange_t rng)
|
||||
{
|
||||
/* Enable I2C */
|
||||
Wire.begin();
|
||||
|
||||
/* Set the range the an appropriate value */
|
||||
_range = rng;
|
||||
|
||||
/* Make sure we have the correct chip ID since this checks
|
||||
for correct address and that the IC is properly connected */
|
||||
uint8_t id = read8(GYRO_REGISTER_WHO_AM_I);
|
||||
//Serial.println(id, HEX);
|
||||
if ((id != L3GD20_ID) && (id != L3GD20H_ID))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set CTRL_REG1 (0x20)
|
||||
====================================================================
|
||||
BIT Symbol Description Default
|
||||
--- ------ --------------------------------------------- -------
|
||||
7-6 DR1/0 Output data rate 00
|
||||
5-4 BW1/0 Bandwidth selection 00
|
||||
3 PD 0 = Power-down mode, 1 = normal/sleep mode 0
|
||||
2 ZEN Z-axis enable (0 = disabled, 1 = enabled) 1
|
||||
1 YEN Y-axis enable (0 = disabled, 1 = enabled) 1
|
||||
0 XEN X-axis enable (0 = disabled, 1 = enabled) 1 */
|
||||
|
||||
/* Reset then switch to normal mode and enable all three channels */
|
||||
write8(GYRO_REGISTER_CTRL_REG1, 0x00);
|
||||
write8(GYRO_REGISTER_CTRL_REG1, 0x0F);
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* Set CTRL_REG2 (0x21)
|
||||
====================================================================
|
||||
BIT Symbol Description Default
|
||||
--- ------ --------------------------------------------- -------
|
||||
5-4 HPM1/0 High-pass filter mode selection 00
|
||||
3-0 HPCF3..0 High-pass filter cutoff frequency selection 0000 */
|
||||
|
||||
/* Nothing to do ... keep default values */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* Set CTRL_REG3 (0x22)
|
||||
====================================================================
|
||||
BIT Symbol Description Default
|
||||
--- ------ --------------------------------------------- -------
|
||||
7 I1_Int1 Interrupt enable on INT1 (0=disable,1=enable) 0
|
||||
6 I1_Boot Boot status on INT1 (0=disable,1=enable) 0
|
||||
5 H-Lactive Interrupt active config on INT1 (0=high,1=low) 0
|
||||
4 PP_OD Push-Pull/Open-Drain (0=PP, 1=OD) 0
|
||||
3 I2_DRDY Data ready on DRDY/INT2 (0=disable,1=enable) 0
|
||||
2 I2_WTM FIFO wtrmrk int on DRDY/INT2 (0=dsbl,1=enbl) 0
|
||||
1 I2_ORun FIFO overrun int on DRDY/INT2 (0=dsbl,1=enbl) 0
|
||||
0 I2_Empty FIFI empty int on DRDY/INT2 (0=dsbl,1=enbl) 0 */
|
||||
|
||||
/* Nothing to do ... keep default values */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* Set CTRL_REG4 (0x23)
|
||||
====================================================================
|
||||
BIT Symbol Description Default
|
||||
--- ------ --------------------------------------------- -------
|
||||
7 BDU Block Data Update (0=continuous, 1=LSB/MSB) 0
|
||||
6 BLE Big/Little-Endian (0=Data LSB, 1=Data MSB) 0
|
||||
5-4 FS1/0 Full scale selection 00
|
||||
00 = 250 dps
|
||||
01 = 500 dps
|
||||
10 = 2000 dps
|
||||
11 = 2000 dps
|
||||
0 SIM SPI Mode (0=4-wire, 1=3-wire) 0 */
|
||||
|
||||
/* Adjust resolution if requested */
|
||||
switch(_range)
|
||||
{
|
||||
case GYRO_RANGE_250DPS:
|
||||
write8(GYRO_REGISTER_CTRL_REG4, 0x00);
|
||||
break;
|
||||
case GYRO_RANGE_500DPS:
|
||||
write8(GYRO_REGISTER_CTRL_REG4, 0x10);
|
||||
break;
|
||||
case GYRO_RANGE_2000DPS:
|
||||
write8(GYRO_REGISTER_CTRL_REG4, 0x20);
|
||||
break;
|
||||
}
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* Set CTRL_REG5 (0x24)
|
||||
====================================================================
|
||||
BIT Symbol Description Default
|
||||
--- ------ --------------------------------------------- -------
|
||||
7 BOOT Reboot memory content (0=normal, 1=reboot) 0
|
||||
6 FIFO_EN FIFO enable (0=FIFO disable, 1=enable) 0
|
||||
4 HPen High-pass filter enable (0=disable,1=enable) 0
|
||||
3-2 INT1_SEL INT1 Selection config 00
|
||||
1-0 OUT_SEL Out selection config 00 */
|
||||
|
||||
/* Nothing to do ... keep default values */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enables or disables auto-ranging
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_L3GD20_Unified::enableAutoRange(bool enabled)
|
||||
{
|
||||
_autoRangeEnabled = enabled;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent sensor event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_L3GD20_Unified::getEvent(sensors_event_t* event)
|
||||
{
|
||||
bool readingValid = false;
|
||||
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_GYROSCOPE;
|
||||
|
||||
while(!readingValid)
|
||||
{
|
||||
event->timestamp = millis();
|
||||
|
||||
/* Read 6 bytes from the sensor */
|
||||
Wire.beginTransmission((byte)L3GD20_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(GYRO_REGISTER_OUT_X_L | 0x80);
|
||||
#else
|
||||
Wire.send(GYRO_REGISTER_OUT_X_L | 0x80);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((byte)L3GD20_ADDRESS, (byte)6);
|
||||
|
||||
/* Wait around until enough data is available */
|
||||
while (Wire.available() < 6);
|
||||
|
||||
#if ARDUINO >= 100
|
||||
uint8_t xlo = Wire.read();
|
||||
uint8_t xhi = Wire.read();
|
||||
uint8_t ylo = Wire.read();
|
||||
uint8_t yhi = Wire.read();
|
||||
uint8_t zlo = Wire.read();
|
||||
uint8_t zhi = Wire.read();
|
||||
#else
|
||||
uint8_t xlo = Wire.receive();
|
||||
uint8_t xhi = Wire.receive();
|
||||
uint8_t ylo = Wire.receive();
|
||||
uint8_t yhi = Wire.receive();
|
||||
uint8_t zlo = Wire.receive();
|
||||
uint8_t zhi = Wire.receive();
|
||||
#endif
|
||||
|
||||
/* Shift values to create properly formed integer (low byte first) */
|
||||
event->gyro.x = (int16_t)(xlo | (xhi << 8));
|
||||
event->gyro.y = (int16_t)(ylo | (yhi << 8));
|
||||
event->gyro.z = (int16_t)(zlo | (zhi << 8));
|
||||
|
||||
/* Make sure the sensor isn't saturating if auto-ranging is enabled */
|
||||
if (!_autoRangeEnabled)
|
||||
{
|
||||
readingValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if the sensor is saturating or not */
|
||||
if ( (event->gyro.x >= 32760) | (event->gyro.x <= -32760) |
|
||||
(event->gyro.y >= 32760) | (event->gyro.y <= -32760) |
|
||||
(event->gyro.z >= 32760) | (event->gyro.z <= -32760) )
|
||||
{
|
||||
/* Saturating .... increase the range if we can */
|
||||
switch(_range)
|
||||
{
|
||||
case GYRO_RANGE_500DPS:
|
||||
/* Push the range up to 2000dps */
|
||||
_range = GYRO_RANGE_2000DPS;
|
||||
write8(GYRO_REGISTER_CTRL_REG1, 0x00);
|
||||
write8(GYRO_REGISTER_CTRL_REG1, 0x0F);
|
||||
write8(GYRO_REGISTER_CTRL_REG4, 0x20);
|
||||
write8(GYRO_REGISTER_CTRL_REG5, 0x80);
|
||||
readingValid = false;
|
||||
// Serial.println("Changing range to 2000DPS");
|
||||
break;
|
||||
case GYRO_RANGE_250DPS:
|
||||
/* Push the range up to 500dps */
|
||||
_range = GYRO_RANGE_500DPS;
|
||||
write8(GYRO_REGISTER_CTRL_REG1, 0x00);
|
||||
write8(GYRO_REGISTER_CTRL_REG1, 0x0F);
|
||||
write8(GYRO_REGISTER_CTRL_REG4, 0x10);
|
||||
write8(GYRO_REGISTER_CTRL_REG5, 0x80);
|
||||
readingValid = false;
|
||||
// Serial.println("Changing range to 500DPS");
|
||||
break;
|
||||
default:
|
||||
readingValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* All values are withing range */
|
||||
readingValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compensate values depending on the resolution */
|
||||
switch(_range)
|
||||
{
|
||||
case GYRO_RANGE_250DPS:
|
||||
event->gyro.x *= GYRO_SENSITIVITY_250DPS;
|
||||
event->gyro.y *= GYRO_SENSITIVITY_250DPS;
|
||||
event->gyro.z *= GYRO_SENSITIVITY_250DPS;
|
||||
break;
|
||||
case GYRO_RANGE_500DPS:
|
||||
event->gyro.x *= GYRO_SENSITIVITY_500DPS;
|
||||
event->gyro.y *= GYRO_SENSITIVITY_500DPS;
|
||||
event->gyro.z *= GYRO_SENSITIVITY_500DPS;
|
||||
break;
|
||||
case GYRO_RANGE_2000DPS:
|
||||
event->gyro.x *= GYRO_SENSITIVITY_2000DPS;
|
||||
event->gyro.y *= GYRO_SENSITIVITY_2000DPS;
|
||||
event->gyro.z *= GYRO_SENSITIVITY_2000DPS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Convert values to rad/s */
|
||||
event->gyro.x *= SENSORS_DPS_TO_RADS;
|
||||
event->gyro.y *= SENSORS_DPS_TO_RADS;
|
||||
event->gyro.z *= SENSORS_DPS_TO_RADS;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_L3GD20_Unified::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, "L3GD20", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_GYROSCOPE;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = (float)this->_range * SENSORS_DPS_TO_RADS;
|
||||
sensor->min_value = (this->_range * -1.0) * SENSORS_DPS_TO_RADS;
|
||||
sensor->resolution = 0.0F; // TBD
|
||||
}
|
||||
104
Adafruit_L3GD20_U.h
Normal file
104
Adafruit_L3GD20_U.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/***************************************************
|
||||
This is a library for the L3GD20 GYROSCOPE
|
||||
|
||||
Designed specifically to work with the Adafruit L3GD20 Breakout
|
||||
----> https://www.adafruit.com/products/1032
|
||||
|
||||
These sensors use I2C or SPI to communicate, 2 pins (I2C)
|
||||
or 4 pins (SPI) are required to interface.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Kevin "KTOWN" Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
#ifndef __L3GD20_H__
|
||||
#define __L3GD20_H__
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "Adafruit_Sensor.h"
|
||||
#include <Wire.h>
|
||||
|
||||
/*=========================================================================
|
||||
I2C ADDRESS/BITS AND SETTINGS
|
||||
-----------------------------------------------------------------------*/
|
||||
#define L3GD20_ADDRESS (0x6B) // 1101011
|
||||
#define L3GD20_POLL_TIMEOUT (100) // Maximum number of read attempts
|
||||
#define L3GD20_ID 0xD4
|
||||
#define L3GD20H_ID 0xD7
|
||||
#define GYRO_SENSITIVITY_250DPS (0.00875F) // Roughly 22/256 for fixed point match
|
||||
#define GYRO_SENSITIVITY_500DPS (0.0175F) // Roughly 45/256
|
||||
#define GYRO_SENSITIVITY_2000DPS (0.070F) // Roughly 18/256
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
REGISTERS
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef enum
|
||||
{ // DEFAULT TYPE
|
||||
GYRO_REGISTER_WHO_AM_I = 0x0F, // 11010100 r
|
||||
GYRO_REGISTER_CTRL_REG1 = 0x20, // 00000111 rw
|
||||
GYRO_REGISTER_CTRL_REG2 = 0x21, // 00000000 rw
|
||||
GYRO_REGISTER_CTRL_REG3 = 0x22, // 00000000 rw
|
||||
GYRO_REGISTER_CTRL_REG4 = 0x23, // 00000000 rw
|
||||
GYRO_REGISTER_CTRL_REG5 = 0x24, // 00000000 rw
|
||||
GYRO_REGISTER_REFERENCE = 0x25, // 00000000 rw
|
||||
GYRO_REGISTER_OUT_TEMP = 0x26, // r
|
||||
GYRO_REGISTER_STATUS_REG = 0x27, // r
|
||||
GYRO_REGISTER_OUT_X_L = 0x28, // r
|
||||
GYRO_REGISTER_OUT_X_H = 0x29, // r
|
||||
GYRO_REGISTER_OUT_Y_L = 0x2A, // r
|
||||
GYRO_REGISTER_OUT_Y_H = 0x2B, // r
|
||||
GYRO_REGISTER_OUT_Z_L = 0x2C, // r
|
||||
GYRO_REGISTER_OUT_Z_H = 0x2D, // r
|
||||
GYRO_REGISTER_FIFO_CTRL_REG = 0x2E, // 00000000 rw
|
||||
GYRO_REGISTER_FIFO_SRC_REG = 0x2F, // r
|
||||
GYRO_REGISTER_INT1_CFG = 0x30, // 00000000 rw
|
||||
GYRO_REGISTER_INT1_SRC = 0x31, // r
|
||||
GYRO_REGISTER_TSH_XH = 0x32, // 00000000 rw
|
||||
GYRO_REGISTER_TSH_XL = 0x33, // 00000000 rw
|
||||
GYRO_REGISTER_TSH_YH = 0x34, // 00000000 rw
|
||||
GYRO_REGISTER_TSH_YL = 0x35, // 00000000 rw
|
||||
GYRO_REGISTER_TSH_ZH = 0x36, // 00000000 rw
|
||||
GYRO_REGISTER_TSH_ZL = 0x37, // 00000000 rw
|
||||
GYRO_REGISTER_INT1_DURATION = 0x38 // 00000000 rw
|
||||
} gyroRegisters_t;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
OPTIONAL SPEED SETTINGS
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
GYRO_RANGE_250DPS = 250,
|
||||
GYRO_RANGE_500DPS = 500,
|
||||
GYRO_RANGE_2000DPS = 2000
|
||||
} gyroRange_t;
|
||||
/*=========================================================================*/
|
||||
|
||||
class Adafruit_L3GD20_Unified : public Adafruit_Sensor
|
||||
{
|
||||
public:
|
||||
Adafruit_L3GD20_Unified(int32_t sensorID = -1);
|
||||
|
||||
bool begin ( gyroRange_t rng = GYRO_RANGE_250DPS );
|
||||
void enableAutoRange ( bool enabled );
|
||||
bool getEvent ( sensors_event_t* );
|
||||
void getSensor ( sensor_t* );
|
||||
|
||||
private:
|
||||
void write8 ( byte reg, byte value );
|
||||
byte read8 ( byte reg );
|
||||
gyroRange_t _range;
|
||||
int32_t _sensorID;
|
||||
bool _autoRangeEnabled;
|
||||
};
|
||||
|
||||
#endif
|
||||
569
Adafruit_LSM303_U.cpp
Normal file
569
Adafruit_LSM303_U.cpp
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
/***************************************************************************
|
||||
This is a library for the LSM303 Accelerometer and magnentometer/compass
|
||||
|
||||
Designed specifically to work with the Adafruit LSM303DLHC Breakout
|
||||
|
||||
These displays 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!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "Adafruit_LSM303_U.h"
|
||||
|
||||
/* enabling this #define will enable the debug print blocks
|
||||
#define LSM303_DEBUG
|
||||
*/
|
||||
|
||||
static float _lsm303Accel_MG_LSB = 0.001F; // 1, 2, 4 or 12 mg per lsb
|
||||
static float _lsm303Mag_Gauss_LSB_XY = 1100.0F; // Varies with gain
|
||||
static float _lsm303Mag_Gauss_LSB_Z = 980.0F; // Varies with gain
|
||||
|
||||
/***************************************************************************
|
||||
ACCELEROMETER
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Abstract away platform differences in Arduino wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Accel_Unified::write8(byte address, byte reg, byte value)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)value);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Abstract away platform differences in Arduino wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
byte Adafruit_LSM303_Accel_Unified::read8(byte address, byte reg)
|
||||
{
|
||||
byte value;
|
||||
|
||||
Wire.beginTransmission(address);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(address, (byte)1);
|
||||
#if ARDUINO >= 100
|
||||
value = Wire.read();
|
||||
#else
|
||||
value = Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the raw data from the sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Accel_Unified::read()
|
||||
{
|
||||
// Read the accelerometer
|
||||
Wire.beginTransmission((byte)LSM303_ADDRESS_ACCEL);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(LSM303_REGISTER_ACCEL_OUT_X_L_A | 0x80);
|
||||
#else
|
||||
Wire.send(LSM303_REGISTER_ACCEL_OUT_X_L_A | 0x80);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((byte)LSM303_ADDRESS_ACCEL, (byte)6);
|
||||
|
||||
// Wait around until enough data is available
|
||||
while (Wire.available() < 6);
|
||||
|
||||
#if ARDUINO >= 100
|
||||
uint8_t xlo = Wire.read();
|
||||
uint8_t xhi = Wire.read();
|
||||
uint8_t ylo = Wire.read();
|
||||
uint8_t yhi = Wire.read();
|
||||
uint8_t zlo = Wire.read();
|
||||
uint8_t zhi = Wire.read();
|
||||
#else
|
||||
uint8_t xlo = Wire.receive();
|
||||
uint8_t xhi = Wire.receive();
|
||||
uint8_t ylo = Wire.receive();
|
||||
uint8_t yhi = Wire.receive();
|
||||
uint8_t zlo = Wire.receive();
|
||||
uint8_t zhi = Wire.receive();
|
||||
#endif
|
||||
|
||||
// Shift values to create properly formed integer (low byte first)
|
||||
_accelData.x = (int16_t)(xlo | (xhi << 8)) >> 4;
|
||||
_accelData.y = (int16_t)(ylo | (yhi << 8)) >> 4;
|
||||
_accelData.z = (int16_t)(zlo | (zhi << 8)) >> 4;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new Adafruit_LSM303 class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_LSM303_Accel_Unified::Adafruit_LSM303_Accel_Unified(int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_LSM303_Accel_Unified::begin()
|
||||
{
|
||||
// Enable I2C
|
||||
Wire.begin();
|
||||
|
||||
// Enable the accelerometer (100Hz)
|
||||
write8(LSM303_ADDRESS_ACCEL, LSM303_REGISTER_ACCEL_CTRL_REG1_A, 0x57);
|
||||
|
||||
// LSM303DLHC has no WHOAMI register so read CTRL_REG1_A back to check
|
||||
// if we are connected or not
|
||||
uint8_t reg1_a = read8(LSM303_ADDRESS_ACCEL, LSM303_REGISTER_ACCEL_CTRL_REG1_A);
|
||||
if (reg1_a != 0x57)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent sensor event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_LSM303_Accel_Unified::getEvent(sensors_event_t *event) {
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
/* Read new data */
|
||||
read();
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_ACCELEROMETER;
|
||||
event->timestamp = millis();
|
||||
event->acceleration.x = _accelData.x * _lsm303Accel_MG_LSB * SENSORS_GRAVITY_STANDARD;
|
||||
event->acceleration.y = _accelData.y * _lsm303Accel_MG_LSB * SENSORS_GRAVITY_STANDARD;
|
||||
event->acceleration.z = _accelData.z * _lsm303Accel_MG_LSB * SENSORS_GRAVITY_STANDARD;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Accel_Unified::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, "LSM303", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_ACCELEROMETER;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 0.0F; // TBD
|
||||
sensor->min_value = 0.0F; // TBD
|
||||
sensor->resolution = 0.0F; // TBD
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
MAGNETOMETER
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Abstract away platform differences in Arduino wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Mag_Unified::write8(byte address, byte reg, byte value)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)value);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Abstract away platform differences in Arduino wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
byte Adafruit_LSM303_Mag_Unified::read8(byte address, byte reg)
|
||||
{
|
||||
byte value;
|
||||
|
||||
Wire.beginTransmission(address);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(address, (byte)1);
|
||||
#if ARDUINO >= 100
|
||||
value = Wire.read();
|
||||
#else
|
||||
value = Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the raw data from the sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Mag_Unified::read()
|
||||
{
|
||||
// Read the magnetometer
|
||||
Wire.beginTransmission((byte)LSM303_ADDRESS_MAG);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(LSM303_REGISTER_MAG_OUT_X_H_M);
|
||||
#else
|
||||
Wire.send(LSM303_REGISTER_MAG_OUT_X_H_M);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((byte)LSM303_ADDRESS_MAG, (byte)6);
|
||||
|
||||
// Wait around until enough data is available
|
||||
while (Wire.available() < 6);
|
||||
|
||||
// Note high before low (different than accel)
|
||||
#if ARDUINO >= 100
|
||||
uint8_t xhi = Wire.read();
|
||||
uint8_t xlo = Wire.read();
|
||||
uint8_t zhi = Wire.read();
|
||||
uint8_t zlo = Wire.read();
|
||||
uint8_t yhi = Wire.read();
|
||||
uint8_t ylo = Wire.read();
|
||||
#else
|
||||
uint8_t xhi = Wire.receive();
|
||||
uint8_t xlo = Wire.receive();
|
||||
uint8_t zhi = Wire.receive();
|
||||
uint8_t zlo = Wire.receive();
|
||||
uint8_t yhi = Wire.receive();
|
||||
uint8_t ylo = Wire.receive();
|
||||
#endif
|
||||
|
||||
// Shift values to create properly formed integer (low byte first)
|
||||
_magData.x = (int16_t)(xlo | ((int16_t)xhi << 8));
|
||||
_magData.y = (int16_t)(ylo | ((int16_t)yhi << 8));
|
||||
_magData.z = (int16_t)(zlo | ((int16_t)zhi << 8));
|
||||
|
||||
// ToDo: Calculate orientation
|
||||
// _magData.orientation = 0.0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new Adafruit_LSM303 class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_LSM303_Mag_Unified::Adafruit_LSM303_Mag_Unified(int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
_autoRangeEnabled = false;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_LSM303_Mag_Unified::begin()
|
||||
{
|
||||
// Enable I2C
|
||||
Wire.begin();
|
||||
|
||||
// Enable the magnetometer
|
||||
write8(LSM303_ADDRESS_MAG, LSM303_REGISTER_MAG_MR_REG_M, 0x00);
|
||||
|
||||
#ifdef RUBBISH
|
||||
|
||||
// LSM303DLHC has no WHOAMI register so read CRA_REG_M to check
|
||||
// the default value (0b00010000/0x10)
|
||||
uint8_t reg1_a = read8(LSM303_ADDRESS_MAG, LSM303_REGISTER_MAG_CRA_REG_M);
|
||||
if (reg1_a != 0x10)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the gain to a known level
|
||||
setMagGain(LSM303_MAGGAIN_1_3);
|
||||
|
||||
return true;
|
||||
|
||||
#else
|
||||
uint8_t ira=0, irb=0, irc=0;
|
||||
ira = read8(LSM303_ADDRESS_MAG, LSM303_REGISTER_MAG_IRA_REG_M);
|
||||
irb = read8(LSM303_ADDRESS_MAG, LSM303_REGISTER_MAG_IRB_REG_M);
|
||||
irc = read8(LSM303_ADDRESS_MAG, LSM303_REGISTER_MAG_IRC_REG_M);
|
||||
if ((ira = 0x48) && (irb == 0x34) && (irc == 0x33)) {
|
||||
setMagGain(LSM303_MAGGAIN_1_3);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enables or disables auto-ranging
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Mag_Unified::enableAutoRange(bool enabled)
|
||||
{
|
||||
_autoRangeEnabled = enabled;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the magnetometer's gain
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Mag_Unified::setMagGain(lsm303MagGain gain)
|
||||
{
|
||||
write8(LSM303_ADDRESS_MAG, LSM303_REGISTER_MAG_CRB_REG_M, (byte)gain);
|
||||
|
||||
_magGain = gain;
|
||||
|
||||
switch(gain)
|
||||
{
|
||||
case LSM303_MAGGAIN_1_3:
|
||||
_lsm303Mag_Gauss_LSB_XY = 1100;
|
||||
_lsm303Mag_Gauss_LSB_Z = 980;
|
||||
break;
|
||||
case LSM303_MAGGAIN_1_9:
|
||||
_lsm303Mag_Gauss_LSB_XY = 855;
|
||||
_lsm303Mag_Gauss_LSB_Z = 760;
|
||||
break;
|
||||
case LSM303_MAGGAIN_2_5:
|
||||
_lsm303Mag_Gauss_LSB_XY = 670;
|
||||
_lsm303Mag_Gauss_LSB_Z = 600;
|
||||
break;
|
||||
case LSM303_MAGGAIN_4_0:
|
||||
_lsm303Mag_Gauss_LSB_XY = 450;
|
||||
_lsm303Mag_Gauss_LSB_Z = 400;
|
||||
break;
|
||||
case LSM303_MAGGAIN_4_7:
|
||||
_lsm303Mag_Gauss_LSB_XY = 400;
|
||||
_lsm303Mag_Gauss_LSB_Z = 355;
|
||||
break;
|
||||
case LSM303_MAGGAIN_5_6:
|
||||
_lsm303Mag_Gauss_LSB_XY = 330;
|
||||
_lsm303Mag_Gauss_LSB_Z = 295;
|
||||
break;
|
||||
case LSM303_MAGGAIN_8_1:
|
||||
_lsm303Mag_Gauss_LSB_XY = 230;
|
||||
_lsm303Mag_Gauss_LSB_Z = 205;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the magnetometer's update rate
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Mag_Unified::setMagRate(lsm303MagRate rate)
|
||||
{
|
||||
byte reg_m = ((byte)rate & 0x07) << 2;
|
||||
write8(LSM303_ADDRESS_MAG, LSM303_REGISTER_MAG_CRA_REG_M, reg_m);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent sensor event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_LSM303_Mag_Unified::getEvent(sensors_event_t *event) {
|
||||
bool readingValid = false;
|
||||
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
while(!readingValid)
|
||||
{
|
||||
|
||||
uint8_t reg_mg = read8(LSM303_ADDRESS_MAG, LSM303_REGISTER_MAG_SR_REG_M);
|
||||
if (!(reg_mg & 0x1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read new data */
|
||||
read();
|
||||
|
||||
/* Make sure the sensor isn't saturating if auto-ranging is enabled */
|
||||
if (!_autoRangeEnabled)
|
||||
{
|
||||
readingValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef LSM303_DEBUG
|
||||
Serial.print(_magData.x); Serial.print(" ");
|
||||
Serial.print(_magData.y); Serial.print(" ");
|
||||
Serial.print(_magData.z); Serial.println(" ");
|
||||
#endif
|
||||
/* Check if the sensor is saturating or not */
|
||||
if ( (_magData.x >= 2040) | (_magData.x <= -2040) |
|
||||
(_magData.y >= 2040) | (_magData.y <= -2040) |
|
||||
(_magData.z >= 2040) | (_magData.z <= -2040) )
|
||||
{
|
||||
/* Saturating .... increase the range if we can */
|
||||
switch(_magGain)
|
||||
{
|
||||
case LSM303_MAGGAIN_5_6:
|
||||
setMagGain(LSM303_MAGGAIN_8_1);
|
||||
readingValid = false;
|
||||
#ifdef LSM303_DEBUG
|
||||
Serial.println("Changing range to +/- 8.1");
|
||||
#endif
|
||||
break;
|
||||
case LSM303_MAGGAIN_4_7:
|
||||
setMagGain(LSM303_MAGGAIN_5_6);
|
||||
readingValid = false;
|
||||
#ifdef LSM303_DEBUG
|
||||
Serial.println("Changing range to +/- 5.6");
|
||||
#endif
|
||||
break;
|
||||
case LSM303_MAGGAIN_4_0:
|
||||
setMagGain(LSM303_MAGGAIN_4_7);
|
||||
readingValid = false;
|
||||
#ifdef LSM303_DEBUG
|
||||
Serial.println("Changing range to +/- 4.7");
|
||||
#endif
|
||||
break;
|
||||
case LSM303_MAGGAIN_2_5:
|
||||
setMagGain(LSM303_MAGGAIN_4_0);
|
||||
readingValid = false;
|
||||
#ifdef LSM303_DEBUG
|
||||
Serial.println("Changing range to +/- 4.0");
|
||||
#endif
|
||||
break;
|
||||
case LSM303_MAGGAIN_1_9:
|
||||
setMagGain(LSM303_MAGGAIN_2_5);
|
||||
readingValid = false;
|
||||
#ifdef LSM303_DEBUG
|
||||
Serial.println("Changing range to +/- 2.5");
|
||||
#endif
|
||||
break;
|
||||
case LSM303_MAGGAIN_1_3:
|
||||
setMagGain(LSM303_MAGGAIN_1_9);
|
||||
readingValid = false;
|
||||
#ifdef LSM303_DEBUG
|
||||
Serial.println("Changing range to +/- 1.9");
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
readingValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* All values are withing range */
|
||||
readingValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_MAGNETIC_FIELD;
|
||||
event->timestamp = millis();
|
||||
event->magnetic.x = _magData.x / _lsm303Mag_Gauss_LSB_XY * SENSORS_GAUSS_TO_MICROTESLA;
|
||||
event->magnetic.y = _magData.y / _lsm303Mag_Gauss_LSB_XY * SENSORS_GAUSS_TO_MICROTESLA;
|
||||
event->magnetic.z = _magData.z / _lsm303Mag_Gauss_LSB_Z * SENSORS_GAUSS_TO_MICROTESLA;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM303_Mag_Unified::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, "LSM303", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_MAGNETIC_FIELD;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 0.0F; // TBD
|
||||
sensor->min_value = 0.0F; // TBD
|
||||
sensor->resolution = 0.0F; // TBD
|
||||
}
|
||||
200
Adafruit_LSM303_U.h
Normal file
200
Adafruit_LSM303_U.h
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
/***************************************************************************
|
||||
This is a library for the LSM303 Accelerometer and magnentometer/compass
|
||||
|
||||
Designed specifically to work with the Adafruit LSM303DLHC Breakout
|
||||
|
||||
These displays 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!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#ifndef __LSM303_H__
|
||||
#define __LSM303_H__
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "Adafruit_Sensor.h"
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
I2C ADDRESS/BITS
|
||||
-----------------------------------------------------------------------*/
|
||||
#define LSM303_ADDRESS_ACCEL (0x32 >> 1) // 0011001x
|
||||
#define LSM303_ADDRESS_MAG (0x3C >> 1) // 0011110x
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
REGISTERS
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef enum
|
||||
{ // DEFAULT TYPE
|
||||
LSM303_REGISTER_ACCEL_CTRL_REG1_A = 0x20, // 00000111 rw
|
||||
LSM303_REGISTER_ACCEL_CTRL_REG2_A = 0x21, // 00000000 rw
|
||||
LSM303_REGISTER_ACCEL_CTRL_REG3_A = 0x22, // 00000000 rw
|
||||
LSM303_REGISTER_ACCEL_CTRL_REG4_A = 0x23, // 00000000 rw
|
||||
LSM303_REGISTER_ACCEL_CTRL_REG5_A = 0x24, // 00000000 rw
|
||||
LSM303_REGISTER_ACCEL_CTRL_REG6_A = 0x25, // 00000000 rw
|
||||
LSM303_REGISTER_ACCEL_REFERENCE_A = 0x26, // 00000000 r
|
||||
LSM303_REGISTER_ACCEL_STATUS_REG_A = 0x27, // 00000000 r
|
||||
LSM303_REGISTER_ACCEL_OUT_X_L_A = 0x28,
|
||||
LSM303_REGISTER_ACCEL_OUT_X_H_A = 0x29,
|
||||
LSM303_REGISTER_ACCEL_OUT_Y_L_A = 0x2A,
|
||||
LSM303_REGISTER_ACCEL_OUT_Y_H_A = 0x2B,
|
||||
LSM303_REGISTER_ACCEL_OUT_Z_L_A = 0x2C,
|
||||
LSM303_REGISTER_ACCEL_OUT_Z_H_A = 0x2D,
|
||||
LSM303_REGISTER_ACCEL_FIFO_CTRL_REG_A = 0x2E,
|
||||
LSM303_REGISTER_ACCEL_FIFO_SRC_REG_A = 0x2F,
|
||||
LSM303_REGISTER_ACCEL_INT1_CFG_A = 0x30,
|
||||
LSM303_REGISTER_ACCEL_INT1_SOURCE_A = 0x31,
|
||||
LSM303_REGISTER_ACCEL_INT1_THS_A = 0x32,
|
||||
LSM303_REGISTER_ACCEL_INT1_DURATION_A = 0x33,
|
||||
LSM303_REGISTER_ACCEL_INT2_CFG_A = 0x34,
|
||||
LSM303_REGISTER_ACCEL_INT2_SOURCE_A = 0x35,
|
||||
LSM303_REGISTER_ACCEL_INT2_THS_A = 0x36,
|
||||
LSM303_REGISTER_ACCEL_INT2_DURATION_A = 0x37,
|
||||
LSM303_REGISTER_ACCEL_CLICK_CFG_A = 0x38,
|
||||
LSM303_REGISTER_ACCEL_CLICK_SRC_A = 0x39,
|
||||
LSM303_REGISTER_ACCEL_CLICK_THS_A = 0x3A,
|
||||
LSM303_REGISTER_ACCEL_TIME_LIMIT_A = 0x3B,
|
||||
LSM303_REGISTER_ACCEL_TIME_LATENCY_A = 0x3C,
|
||||
LSM303_REGISTER_ACCEL_TIME_WINDOW_A = 0x3D
|
||||
} lsm303AccelRegisters_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LSM303_REGISTER_MAG_CRA_REG_M = 0x00,
|
||||
LSM303_REGISTER_MAG_CRB_REG_M = 0x01,
|
||||
LSM303_REGISTER_MAG_MR_REG_M = 0x02,
|
||||
LSM303_REGISTER_MAG_OUT_X_H_M = 0x03,
|
||||
LSM303_REGISTER_MAG_OUT_X_L_M = 0x04,
|
||||
LSM303_REGISTER_MAG_OUT_Z_H_M = 0x05,
|
||||
LSM303_REGISTER_MAG_OUT_Z_L_M = 0x06,
|
||||
LSM303_REGISTER_MAG_OUT_Y_H_M = 0x07,
|
||||
LSM303_REGISTER_MAG_OUT_Y_L_M = 0x08,
|
||||
LSM303_REGISTER_MAG_SR_REG_M = 0x09,
|
||||
LSM303_REGISTER_MAG_IRA_REG_M = 0x0A,
|
||||
LSM303_REGISTER_MAG_IRB_REG_M = 0x0B,
|
||||
LSM303_REGISTER_MAG_IRC_REG_M = 0x0C,
|
||||
LSM303_REGISTER_MAG_TEMP_OUT_H_M = 0x31,
|
||||
LSM303_REGISTER_MAG_TEMP_OUT_L_M = 0x32
|
||||
} lsm303MagRegisters_t;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
MAGNETOMETER GAIN SETTINGS
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
LSM303_MAGGAIN_1_3 = 0x20, // +/- 1.3
|
||||
LSM303_MAGGAIN_1_9 = 0x40, // +/- 1.9
|
||||
LSM303_MAGGAIN_2_5 = 0x60, // +/- 2.5
|
||||
LSM303_MAGGAIN_4_0 = 0x80, // +/- 4.0
|
||||
LSM303_MAGGAIN_4_7 = 0xA0, // +/- 4.7
|
||||
LSM303_MAGGAIN_5_6 = 0xC0, // +/- 5.6
|
||||
LSM303_MAGGAIN_8_1 = 0xE0 // +/- 8.1
|
||||
} lsm303MagGain;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
MAGNETOMETER UPDATE RATE SETTINGS
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
LSM303_MAGRATE_0_7 = 0x00, // 0.75 Hz
|
||||
LSM303_MAGRATE_1_5 = 0x01, // 1.5 Hz
|
||||
LSM303_MAGRATE_3_0 = 0x62, // 3.0 Hz
|
||||
LSM303_MAGRATE_7_5 = 0x03, // 7.5 Hz
|
||||
LSM303_MAGRATE_15 = 0x04, // 15 Hz
|
||||
LSM303_MAGRATE_30 = 0x05, // 30 Hz
|
||||
LSM303_MAGRATE_75 = 0x06, // 75 Hz
|
||||
LSM303_MAGRATE_220 = 0x07 // 200 Hz
|
||||
} lsm303MagRate;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
INTERNAL MAGNETOMETER DATA TYPE
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef struct lsm303MagData_s
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} lsm303MagData;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
INTERNAL ACCELERATION DATA TYPE
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef struct lsm303AccelData_s
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} lsm303AccelData;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
CHIP ID
|
||||
-----------------------------------------------------------------------*/
|
||||
#define LSM303_ID (0b11010100)
|
||||
/*=========================================================================*/
|
||||
|
||||
/* Unified sensor driver for the accelerometer */
|
||||
class Adafruit_LSM303_Accel_Unified : public Adafruit_Sensor
|
||||
{
|
||||
public:
|
||||
Adafruit_LSM303_Accel_Unified(int32_t sensorID = -1);
|
||||
|
||||
bool begin(void);
|
||||
bool getEvent(sensors_event_t*);
|
||||
void getSensor(sensor_t*);
|
||||
|
||||
void write8(byte address, byte reg, byte value);
|
||||
byte read8(byte address, byte reg);
|
||||
void read(void);
|
||||
|
||||
private:
|
||||
lsm303AccelData _accelData; // Last read accelerometer data will be available here
|
||||
int32_t _sensorID;
|
||||
};
|
||||
|
||||
/* Unified sensor driver for the magnetometer */
|
||||
class Adafruit_LSM303_Mag_Unified : public Adafruit_Sensor
|
||||
{
|
||||
public:
|
||||
Adafruit_LSM303_Mag_Unified(int32_t sensorID = -1);
|
||||
|
||||
bool begin(void);
|
||||
void enableAutoRange(bool enable);
|
||||
void setMagGain(lsm303MagGain gain);
|
||||
void setMagRate(lsm303MagRate rate);
|
||||
bool getEvent(sensors_event_t*);
|
||||
void getSensor(sensor_t*);
|
||||
|
||||
void write8(byte address, byte reg, byte value);
|
||||
byte read8(byte address, byte reg);
|
||||
void read(void);
|
||||
|
||||
private:
|
||||
lsm303MagGain _magGain;
|
||||
lsm303MagData _magData; // Last read magnetometer data will be available here
|
||||
int32_t _sensorID;
|
||||
bool _autoRangeEnabled;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
2
Adafruit_Sensor.cpp
Normal file
2
Adafruit_Sensor.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#include "Adafruit_Sensor.h"
|
||||
#include <avr/pgmspace.h>
|
||||
154
Adafruit_Sensor.h
Normal file
154
Adafruit_Sensor.h
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software< /span>
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
|
||||
* extended sensor support to include color, voltage and current */
|
||||
|
||||
#ifndef _ADAFRUIT_SENSOR_H
|
||||
#define _ADAFRUIT_SENSOR_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
/* Intentionally modeled after sensors.h in the Android API:
|
||||
* https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */
|
||||
|
||||
/* Constants */
|
||||
#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH)
|
||||
#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */
|
||||
#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */
|
||||
#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */
|
||||
#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */
|
||||
#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */
|
||||
|
||||
/** Sensor types */
|
||||
typedef enum
|
||||
{
|
||||
SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
|
||||
SENSOR_TYPE_MAGNETIC_FIELD = (2),
|
||||
SENSOR_TYPE_ORIENTATION = (3),
|
||||
SENSOR_TYPE_GYROSCOPE = (4),
|
||||
SENSOR_TYPE_LIGHT = (5),
|
||||
SENSOR_TYPE_PRESSURE = (6),
|
||||
SENSOR_TYPE_PROXIMITY = (8),
|
||||
SENSOR_TYPE_GRAVITY = (9),
|
||||
SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */
|
||||
SENSOR_TYPE_ROTATION_VECTOR = (11),
|
||||
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
|
||||
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
|
||||
SENSOR_TYPE_VOLTAGE = (15),
|
||||
SENSOR_TYPE_CURRENT = (16),
|
||||
SENSOR_TYPE_COLOR = (17)
|
||||
} sensors_type_t;
|
||||
|
||||
/** struct sensors_vec_s is used to return a vector in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float v[3];
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
/* Orientation sensors */
|
||||
struct {
|
||||
float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */
|
||||
float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */
|
||||
float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */
|
||||
};
|
||||
};
|
||||
int8_t status;
|
||||
uint8_t reserved[3];
|
||||
} sensors_vec_t;
|
||||
|
||||
/** struct sensors_color_s is used to return color data in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float c[3];
|
||||
/* RGB color space */
|
||||
struct {
|
||||
float r; /**< Red component */
|
||||
float g; /**< Green component */
|
||||
float b; /**< Blue component */
|
||||
};
|
||||
};
|
||||
uint32_t rgba; /**< 24-bit RGBA value */
|
||||
} sensors_color_t;
|
||||
|
||||
/* Sensor event (36 bytes) */
|
||||
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
|
||||
typedef struct
|
||||
{
|
||||
int32_t version; /**< must be sizeof(struct sensors_event_t) */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< sensor type */
|
||||
int32_t reserved0; /**< reserved */
|
||||
int32_t timestamp; /**< time is in milliseconds */
|
||||
union
|
||||
{
|
||||
float data[4];
|
||||
sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */
|
||||
sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
|
||||
sensors_vec_t orientation; /**< orientation values are in degrees */
|
||||
sensors_vec_t gyro; /**< gyroscope values are in rad/s */
|
||||
float temperature; /**< temperature is in degrees centigrade (Celsius) */
|
||||
float distance; /**< distance in centimeters */
|
||||
float light; /**< light in SI lux units */
|
||||
float pressure; /**< pressure in hectopascal (hPa) */
|
||||
float relative_humidity; /**< relative humidity in percent */
|
||||
float current; /**< current in milliamps (mA) */
|
||||
float voltage; /**< voltage in volts (V) */
|
||||
sensors_color_t color; /**< color in RGB component values */
|
||||
};
|
||||
} sensors_event_t;
|
||||
|
||||
/* Sensor details (40 bytes) */
|
||||
/** struct sensor_s is used to describe basic information about a specific sensor. */
|
||||
typedef struct
|
||||
{
|
||||
char name[12]; /**< sensor name */
|
||||
int32_t version; /**< version of the hardware + driver */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
|
||||
float max_value; /**< maximum value of this sensor's value in SI units */
|
||||
float min_value; /**< minimum value of this sensor's value in SI units */
|
||||
float resolution; /**< smallest difference between two values reported by this sensor */
|
||||
int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */
|
||||
} sensor_t;
|
||||
|
||||
class Adafruit_Sensor {
|
||||
public:
|
||||
// Constructor(s)
|
||||
Adafruit_Sensor() {}
|
||||
virtual ~Adafruit_Sensor() {}
|
||||
|
||||
// These must be defined by the subclass
|
||||
virtual void enableAutoRange(bool enabled) {};
|
||||
virtual bool getEvent(sensors_event_t*) = 0;
|
||||
virtual void getSensor(sensor_t*) = 0;
|
||||
|
||||
private:
|
||||
bool _autoRange;
|
||||
};
|
||||
|
||||
#endif
|
||||
1
cosmicpi-arduino.cc
Symbolic link
1
cosmicpi-arduino.cc
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
cosmicpi-arduino.ino
|
||||
1104
cosmicpi-arduino.ino
Normal file
1104
cosmicpi-arduino.ino
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue