mirror of
https://github.com/cosmic-pi-deprecated/cosmicpi-arduino_V1.6.git
synced 2026-05-12 16:09:25 +00:00
working version
This commit is contained in:
parent
9a47221c51
commit
56d34a3959
11 changed files with 2271 additions and 0 deletions
529
cosmicpi-arduino_V1.6.ino
Normal file
529
cosmicpi-arduino_V1.6.ino
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
//Cosmic Pi software for Arduino - modified for STM32,
|
||||
//J. Devine
|
||||
//July 2019.
|
||||
//Licensed under GPL V3 or later.
|
||||
//cosmicpi.org
|
||||
|
||||
#include <Wire.h>
|
||||
// LPS lib from here: https://github.com/pololu/lps-arduino
|
||||
#include "src/LPS.h"
|
||||
// LSM9DS1 lib from here: https://github.com/adafruit/Adafruit_LSM9DS1
|
||||
//with some address tweaks
|
||||
|
||||
//#include "src/Adafruit_Sensor.h"
|
||||
#include "src/Adafruit_LSM9DS1.h"
|
||||
// HTU21D lib from here: https://github.com/adafruit/Adafruit_HTU21DF_Library
|
||||
#include "src/SparkFunHTU21D.h"
|
||||
|
||||
|
||||
//counter for how long the leds stay on.
|
||||
int last_event_LED = 0;
|
||||
|
||||
|
||||
// i2c
|
||||
Adafruit_LSM9DS1 lsm = Adafruit_LSM9DS1();
|
||||
|
||||
//declare pressure sensor
|
||||
LPS ps;
|
||||
|
||||
//Create an instance of the object
|
||||
HTU21D myHumidity;
|
||||
|
||||
|
||||
|
||||
// string used for passing data from the dump routines
|
||||
static const int TXTLEN = 512;
|
||||
static char txt[TXTLEN]; //internal buffer
|
||||
static char txts[TXTLEN]; //sensor buffer
|
||||
|
||||
|
||||
//pinouts
|
||||
/*
|
||||
PA0 - Pin 14 - Shaped Signal 1
|
||||
PA1 - Pin 15 - Shaped Signal 2
|
||||
PA2 - Pin 16 - TX0
|
||||
PA3 - Pin 16 - RX0
|
||||
PA4 - Pin 20 - LED1 - Power/GPS
|
||||
PA5 - Pin 21 - LED2 - Event
|
||||
PA6 - Pin 22 - Injection leds
|
||||
PA7 - Pin 23 - Bias FB1
|
||||
PA8 - Pin 41 - SCL_Slave
|
||||
PA9 - Pin 42 - USB_OTG_VBUS
|
||||
PA10 - Pin 43 - GPSTX
|
||||
PA11 - Pin 44 - USBOTG DM
|
||||
PA12 - Pin 45 - USBOTG DP
|
||||
PA13 - Pin 46 - SWDIO
|
||||
PA14 - Pin 49 - SWCLK
|
||||
PA15 - Pin 50 - GPSPPS Input
|
||||
PB0 - Pin 26 - Bias FB2
|
||||
PB1 - Pin 27 - Flag to RPi
|
||||
PB2 Pin 28 - NC
|
||||
PB 3 - Pin 55 - NC
|
||||
PB4 - Pin 56 - SDA_Slave
|
||||
PB5 - Pin 57 - NC
|
||||
PB6 - Pin 58 - GPSRX
|
||||
PB7 - Pin 59 - SDA0
|
||||
PB8 - Pin 61 - SCL0
|
||||
PB9 - Pin 62 - NC
|
||||
PB10 - Pin 29 - Trigout (input to STM)
|
||||
PB12 - Pin 33 - NC
|
||||
PB13 - Pin 34 0 HVPSU SCLK (Clock to MAX1932)
|
||||
PB14, PB15 - NC
|
||||
PC0 - Pin 8 - NC
|
||||
PC1 - Pin 9 - HVPSU CL1
|
||||
PC2 - Pin 10 - HVPSU CL2
|
||||
PC3 - Pin 11 - HV PSU DIN
|
||||
PC4, PC5, PC6- NC
|
||||
PC7 - Pin 38 - HVPSU CS2
|
||||
PC8 - Pin 39 - HVPSU CS1
|
||||
PC9 - Pin 40 - Mag Interrupt
|
||||
PC10 - Pin 51 - NC
|
||||
PC11 - Pin 52 - STRIGOUT B
|
||||
PC12 - Pin 53 - STRIGOUT A
|
||||
PC13 - Pin 2 - Baro Int
|
||||
PC14 - Pin 3 - Accelint 1
|
||||
PC15 - Pin 4 - Accelint 2.
|
||||
|
||||
*/
|
||||
|
||||
//eeprom writing table
|
||||
/*
|
||||
eeprom status byte - 00
|
||||
channel 0 high byte - 01
|
||||
channel 0 low byte - 02
|
||||
channel 1 high byte - 03
|
||||
channel 1 low byte - 04
|
||||
HV bias ch 0 value - 05
|
||||
HV bias ch 1 value - 06
|
||||
|
||||
if eeprom status byte = 1 then only one set of values are stored
|
||||
if =2 then a backup set are located higher in memory, not used at the moment
|
||||
*/
|
||||
|
||||
|
||||
#include <Wire.h>
|
||||
#include <EEPROM.h>
|
||||
static const int SERIAL_BAUD_RATE = 19200; // Serial baud rate for version 1.5 production
|
||||
static const int GPS_BAUD_RATE = 9600; // GPS and Serial1 line
|
||||
|
||||
// LED pins
|
||||
#define PPS_PIN PA4 // PPS (Pulse Per Second) and LED
|
||||
#define EVT_PIN PA5 // Cosmic ray event detected
|
||||
|
||||
char numconvbuff[16];
|
||||
|
||||
// Leds flag
|
||||
bool leds_on = true;
|
||||
|
||||
// How long the event LED should light up (in ms)
|
||||
static int event_LED_time = 15;
|
||||
|
||||
long eventCount = 0;
|
||||
int eventStack = 0;
|
||||
unsigned long pps_micros = 0;
|
||||
unsigned long pps_micros_old = 0;
|
||||
unsigned long micros_since_pps = 0;
|
||||
|
||||
#define maxevent 100 //we don't expect more events than this
|
||||
unsigned long evttime [maxevent];
|
||||
|
||||
//set up serial output buffer
|
||||
#define OutBuffSize 1024 //we don't expect more chars than this in the buffer
|
||||
char outputbuffer[OutBuffSize]; //1024 character output buffer
|
||||
int writeincounter = 0; //the place for writing to the buffer
|
||||
int readoutcounter = 0; //the place for reading out from the buffer
|
||||
|
||||
void WriteToOutputBuff(char *outstring)
|
||||
{
|
||||
int stringlengthmax = strlen(outstring);
|
||||
|
||||
for (int addchar = 0; addchar < stringlengthmax; addchar++) {
|
||||
outputbuffer[writeincounter] = outstring[addchar];
|
||||
writeincounter++;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadFromOutputBuff()
|
||||
{
|
||||
char digitout[2];
|
||||
if (writeincounter > readoutcounter)
|
||||
{
|
||||
digitout[0] = outputbuffer[readoutcounter];
|
||||
digitout[1] = '\0';
|
||||
Serial.print(digitout);
|
||||
readoutcounter++;
|
||||
}
|
||||
if (readoutcounter == writeincounter) {
|
||||
readoutcounter = 0;
|
||||
writeincounter = 0;
|
||||
//Serial.println("BUFFERCLEAR");
|
||||
}
|
||||
}
|
||||
|
||||
void setupSensor()
|
||||
{
|
||||
// 1.) Set the accelerometer range
|
||||
lsm.setupAccel(lsm.LSM9DS1_ACCELRANGE_2G);
|
||||
//lsm.setupAccel(lsm.LSM9DS1_ACCELRANGE_4G);
|
||||
//lsm.setupAccel(lsm.LSM9DS1_ACCELRANGE_8G);
|
||||
//lsm.setupAccel(lsm.LSM9DS1_ACCELRANGE_16G);
|
||||
|
||||
// 2.) Set the magnetometer sensitivity
|
||||
lsm.setupMag(lsm.LSM9DS1_MAGGAIN_4GAUSS);
|
||||
//lsm.setupMag(lsm.LSM9DS1_MAGGAIN_8GAUSS);
|
||||
//lsm.setupMag(lsm.LSM9DS1_MAGGAIN_12GAUSS);
|
||||
//lsm.setupMag(lsm.LSM9DS1_MAGGAIN_16GAUSS);
|
||||
|
||||
// 3.) Setup the gyroscope
|
||||
lsm.setupGyro(lsm.LSM9DS1_GYROSCALE_245DPS);
|
||||
//lsm.setupGyro(lsm.LSM9DS1_GYROSCALE_500DPS);
|
||||
//lsm.setupGyro(lsm.LSM9DS1_GYROSCALE_2000DPS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// GPS and time flags
|
||||
boolean gps_ok = false; // Chip OK flag
|
||||
boolean pps_recieved = false;
|
||||
|
||||
|
||||
|
||||
// ------------------------- Arudino Functions
|
||||
|
||||
// Arduino setup function, initialize hardware and software
|
||||
// This is the first function to be called when the sketch is started
|
||||
|
||||
//setup serials
|
||||
HardwareSerial GPS(PA10, PB6);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(SERIAL_BAUD_RATE);
|
||||
Serial.print("ON");
|
||||
|
||||
if (leds_on) {
|
||||
pinMode(EVT_PIN, OUTPUT); // Pin for the cosmic ray event
|
||||
pinMode(PPS_PIN, OUTPUT); // Pin for the PPS (LED pin)
|
||||
}
|
||||
if (leds_on) {
|
||||
digitalWrite(PPS_PIN, HIGH); // Turn on led
|
||||
}
|
||||
|
||||
// start the GPS
|
||||
GPS.begin(GPS_BAUD_RATE);
|
||||
GpsSetup();
|
||||
|
||||
// start the i2c bus
|
||||
Wire.begin();
|
||||
Wire.setSDA(PB7);
|
||||
Wire.setSCL(PB8);
|
||||
|
||||
//setup the thresholds
|
||||
//initialise to values from EEPROM, else use defaults.
|
||||
|
||||
int eeprom_read = 0;
|
||||
|
||||
eeprom_read = EEPROM.read(0x00);
|
||||
if (eeprom_read > 0) {
|
||||
|
||||
Serial.println("Found existing settings for Thresholds and HV, these will be applied");
|
||||
Serial.print("First channel threshold settings: 0x");
|
||||
Serial.print(EEPROM.read(0x01), HEX);
|
||||
Serial.println(EEPROM.read(0x02), HEX);
|
||||
Serial.print("Second channel threshold settings: 0x");
|
||||
Serial.print(EEPROM.read(0x03), HEX);
|
||||
Serial.println(EEPROM.read(0x04), HEX);
|
||||
|
||||
|
||||
|
||||
Wire.begin();
|
||||
Wire.beginTransmission(byte(0x60)); // transmit to device #112
|
||||
Wire.write(byte(0x00)); //sets value to the first channel
|
||||
eeprom_read = EEPROM.read(0x01);
|
||||
Wire.write(byte(eeprom_read));
|
||||
eeprom_read = EEPROM.read(0x02);
|
||||
Wire.write(byte(eeprom_read));
|
||||
Wire.endTransmission(); // stop transmitting
|
||||
|
||||
Wire.beginTransmission(byte(0x60)); // transmit to device #112
|
||||
Wire.write(byte(0x01)); //sets value to the first channel
|
||||
eeprom_read = EEPROM.read(0x03);
|
||||
Wire.write(byte(eeprom_read));
|
||||
eeprom_read = EEPROM.read(0x04);
|
||||
Wire.write(byte(eeprom_read));
|
||||
Wire.endTransmission(); // stop transmitting
|
||||
Serial.println("Threshold settings complete");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Serial.println("No existing settings for Thresholds and HV found, using defaults");
|
||||
Serial.print("First channel threshold settings: 0x");
|
||||
Serial.print(0x22F, HEX);
|
||||
Serial.print("Second channel threshold settings: 0x");
|
||||
Serial.print(0x22F, HEX);
|
||||
|
||||
|
||||
Wire.begin();
|
||||
Wire.beginTransmission(byte(0x60)); // transmit to device #112
|
||||
Wire.write(byte(0x00)); //sets value to the first channel
|
||||
Wire.write(byte(0x02));
|
||||
Wire.write(byte(0x2F));
|
||||
Wire.endTransmission(); // stop transmitting
|
||||
|
||||
Wire.beginTransmission(byte(0x60)); // transmit to device #112
|
||||
Wire.write(byte(0x01)); //sets value to the first channel
|
||||
Wire.write(byte(0x02));
|
||||
Wire.write(byte(0x2F));
|
||||
Wire.endTransmission(); // stop transmitting
|
||||
|
||||
Serial.println("Threshold settings complete");
|
||||
|
||||
|
||||
}
|
||||
|
||||
//set the high voltage
|
||||
|
||||
//config SPI pins
|
||||
pinMode(PC7, OUTPUT);
|
||||
pinMode(PC8, OUTPUT);
|
||||
pinMode(PC3, OUTPUT);
|
||||
pinMode(PB13, OUTPUT);
|
||||
|
||||
|
||||
eeprom_read = EEPROM.read(0x00);
|
||||
if (eeprom_read > 0) {
|
||||
Serial.println("Applying stored values for HV channels");
|
||||
|
||||
Serial.print("HV channel settings Ch1: ");
|
||||
Serial.print(EEPROM.read(0x05), HEX);
|
||||
Serial.print(" Ch2: ");
|
||||
Serial.println(EEPROM.read(0x06), HEX);
|
||||
|
||||
//set HV channel 1
|
||||
eeprom_read = EEPROM.read(0x05);
|
||||
digitalWrite(PC7, LOW);
|
||||
setHV(byte(eeprom_read));
|
||||
digitalWrite(PC7, HIGH);
|
||||
//set HV channel 2
|
||||
eeprom_read = EEPROM.read(0x06);
|
||||
digitalWrite(PC8, LOW);
|
||||
setHV(byte(eeprom_read));
|
||||
digitalWrite(PC8, HIGH);
|
||||
|
||||
Serial.println("HV channels set");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Applying default values for HV channels");
|
||||
|
||||
Serial.print("HV channel settings Ch1: ");
|
||||
Serial.print(0xAC, HEX);
|
||||
Serial.print(" Ch2: ");
|
||||
Serial.println(0xAC, HEX);
|
||||
|
||||
digitalWrite(PC7, LOW);
|
||||
setHV(0xAC);
|
||||
digitalWrite(PC7, HIGH);
|
||||
//set HV channel 2
|
||||
digitalWrite(PC8, LOW);
|
||||
setHV(0xAC);
|
||||
digitalWrite(PC8, HIGH);
|
||||
Serial.println("HV channels set");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//init the sensor suite
|
||||
|
||||
Serial.println("Cosmic Pi V1.6 sensor init routine");
|
||||
//init LSM9DS1
|
||||
//lsm.begin();
|
||||
|
||||
if (!lsm.begin())
|
||||
{
|
||||
Serial.println("Oops ... unable to initialize the LSM9DS1. Check your wiring!");
|
||||
while (1);
|
||||
}
|
||||
setupSensor();
|
||||
lsm.read(); /* ask it to read in the data */
|
||||
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t a, m, g, temp;
|
||||
|
||||
lsm.getEvent(&a, &m, &g, &temp);
|
||||
|
||||
//init lps
|
||||
ps.init();
|
||||
ps.enableDefault();
|
||||
|
||||
//init htu21d
|
||||
myHumidity.begin();
|
||||
|
||||
Serial.println("INFO: Sensor setup complete\n");
|
||||
//attach the interrupts
|
||||
attachInterrupt(digitalPinToInterrupt(PA15), GPS_PPS, RISING);
|
||||
attachInterrupt(digitalPinToInterrupt(PB10), Event_Int, RISING);
|
||||
|
||||
Serial.println("INFO: Running\n");
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
pipeGPS();
|
||||
ReadFromOutputBuff();
|
||||
|
||||
//turn off the event led after the set time
|
||||
if (millis() >= (last_event_LED + event_LED_time)){
|
||||
if (leds_on) {
|
||||
digitalWrite(EVT_PIN, LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPS_PPS()
|
||||
{
|
||||
|
||||
//stop listening for events while we process this interrupt
|
||||
detachInterrupt(digitalPinToInterrupt(PB10));
|
||||
|
||||
//now PPS is coming through, we can switch off the internal timer.
|
||||
pps_recieved = true;
|
||||
|
||||
//set the pps micros value as the micro time now, and buffer the last value;
|
||||
pps_micros_old = pps_micros;
|
||||
pps_micros = micros();
|
||||
//how many microseconds since the last pps? (just in case we're running fast/slow)
|
||||
micros_since_pps = pps_micros - pps_micros_old;
|
||||
|
||||
if (leds_on) {
|
||||
digitalWrite(PPS_PIN, !digitalRead(PPS_PIN)); // Toggle led
|
||||
}
|
||||
|
||||
|
||||
//Serial.println("pps");
|
||||
//process all events to the event buffer now that the second has ended
|
||||
//Serial.print("Dumping Event Buffer");
|
||||
//print out the event stack
|
||||
for (int i = 0; i < eventStack; i++) {
|
||||
sprintf(txt, "Event: sub second micros:%d/%d; Event Count:%d\n", evttime[i], micros_since_pps, (eventCount - eventStack + i));
|
||||
WriteToOutputBuff(txt);
|
||||
}
|
||||
sprintf(txt, "PPS: GPS lock:1;\n");
|
||||
WriteToOutputBuff(txt);
|
||||
|
||||
|
||||
//now print the sensors
|
||||
//Serial.print("Sensor section");
|
||||
lsm.read(); /* ask it to read in the data */
|
||||
|
||||
/* Get a new sensor event */
|
||||
|
||||
sensors_event_t a, m, g, temp;
|
||||
lsm.getEvent(&a, &m, &g, &temp);
|
||||
|
||||
float pressure = ps.readPressureMillibars();
|
||||
float altitude = ps.pressureToAltitudeMeters(pressure);
|
||||
float temperature = ps.readTemperatureC();
|
||||
|
||||
float humd = myHumidity.readHumidity();
|
||||
float temphum = myHumidity.readTemperature();
|
||||
|
||||
Serial.print("Altitude: ");
|
||||
Serial.print(altitude, 6);
|
||||
Serial.println(';');
|
||||
Serial.print("TemperatureCBaro: ");
|
||||
Serial.print(temperature, 6);
|
||||
Serial.println(';');
|
||||
|
||||
Serial.print("AccelX: ");
|
||||
Serial.print(a.acceleration.x, 6);
|
||||
Serial.println(';');
|
||||
Serial.print("AccelY: ");
|
||||
Serial.print(a.acceleration.y, 6);
|
||||
Serial.println(';');
|
||||
Serial.print("AccelZ: ");
|
||||
Serial.print(a.acceleration.z, 6);
|
||||
Serial.println(';');
|
||||
|
||||
Serial.print("MagX: ");
|
||||
Serial.print(m.magnetic.x, 6);
|
||||
Serial.println(';');
|
||||
Serial.print("MagY: ");
|
||||
Serial.print(m.magnetic.y, 6);
|
||||
Serial.println(';');
|
||||
Serial.print("MagZ: ");
|
||||
Serial.print(m.magnetic.z, 6);
|
||||
Serial.println(';');
|
||||
|
||||
Serial.print("TemperatureCHumid: ");
|
||||
Serial.print(temphum, 6);
|
||||
Serial.println(';');
|
||||
|
||||
Serial.print("Humidity: ");
|
||||
Serial.print(humd, 6);
|
||||
Serial.println(';');
|
||||
|
||||
//average temp from all 3 sensors
|
||||
float out = 0;
|
||||
out = temphum + temperature;
|
||||
out = out / 2;
|
||||
Serial.print("TemperatureC: ");
|
||||
Serial.print(out, 6);
|
||||
Serial.println(';');
|
||||
//Serial.print(txts);
|
||||
|
||||
|
||||
|
||||
|
||||
//now we can reset the event stack and listen for events again
|
||||
eventStack=0;
|
||||
attachInterrupt(digitalPinToInterrupt(PB10), Event_Int, RISING);
|
||||
}
|
||||
|
||||
|
||||
void Event_Int()
|
||||
{
|
||||
/* WriteToOutputBuff("evtx:");
|
||||
ltoa(eventCount,numconvbuff,10);
|
||||
WriteToOutputBuff(numconvbuff);
|
||||
|
||||
//Serial.print(name);
|
||||
Serial.print("count=");
|
||||
Serial.print(eventCount);
|
||||
Serial.print(" ");
|
||||
Serial.println(micros()-pps_micros);
|
||||
*/
|
||||
eventCount++;
|
||||
//Serial.println("e");
|
||||
//write this event to the stack of times
|
||||
evttime[eventStack] = micros() - pps_micros;
|
||||
//increment the stack counter
|
||||
eventStack++;
|
||||
|
||||
//turn on the event led
|
||||
last_event_LED = millis();
|
||||
if (leds_on) {
|
||||
digitalWrite(EVT_PIN, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
byte setHV(byte _send) // This function is what bitbangs the data
|
||||
{
|
||||
if (_send > 0x5F) {
|
||||
for (int i = 0; i < 8; i++) // There are 8 bits in a byte
|
||||
{
|
||||
digitalWrite(PC3, bitRead(_send, 7 - i)); // Set MOSI
|
||||
//delay(1);
|
||||
digitalWrite(PB13, HIGH); // SCK high
|
||||
//bitWrite(_receive, i, digitalRead(MISO_pin)); // Capture MISO
|
||||
digitalWrite(PB13, LOW); // SCK low
|
||||
//digitalWrite(MOSI_pin, LOW); // Set MOSI
|
||||
|
||||
}
|
||||
//digitalWrite(SS_pin[j], HIGH); // SS high again
|
||||
}
|
||||
}
|
||||
;
|
||||
50
gps_reading.ino
Normal file
50
gps_reading.ino
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
// WARNING: One up the spout !!
|
||||
// The GPS chip puts the next nmea string in its output buffer
|
||||
// only if its been read, IE its empty.
|
||||
// So if you read infrequently the string in the buffer is old and
|
||||
// has the WRONG time !!! The string lies around like a bullet in
|
||||
// the breach waiting for some mug.
|
||||
|
||||
//I don't know who wrote that comment.. I'm guessing it was Julian!
|
||||
|
||||
boolean pipeGPS() {
|
||||
while (GPS.available()) {
|
||||
char c[2];
|
||||
c[0] = GPS.read();
|
||||
c[1]='\0'; //null character for termination required.
|
||||
//Serial.print(c);
|
||||
WriteToOutputBuff(c);
|
||||
}
|
||||
}
|
||||
|
||||
// GPS setup
|
||||
|
||||
void GpsSetup() {
|
||||
|
||||
// definitions for different outputs
|
||||
// only one of these strings can be used at a time
|
||||
// otherwise they will overwrite each other
|
||||
// for more information take a look at the QUECTEL L70 protocoll specification: http://docs-europe.electrocomponents.com/webdocs/147d/0900766b8147dbdd.pdf
|
||||
#define RMCGGA "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28" // RCM & GGA
|
||||
#define ZDA "$PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0*29" // ZDA
|
||||
#define GGAZDA "$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0*28" // GGA & ZDA
|
||||
#define GGA "$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" // GGA
|
||||
|
||||
// gets the firmware version
|
||||
#define FMWVERS "$PMTK605*31" // PMTK_Q_RELEASE
|
||||
// Sets the update intervall
|
||||
#define NORMAL "$PMTK220,1000*1F" // PMTK_SET_NMEA_UPDATE_1HZ
|
||||
// disables updates for the antenna status (only Adafruit ultimate GPS?)
|
||||
#define NOANTENNA "$PGCMD,33,0*6D" // PGCMD_NOAN
|
||||
delay(500); //added delay to give GPS time to boot.
|
||||
GPS.println(NOANTENNA);
|
||||
GPS.println(GGAZDA);
|
||||
GPS.println(NORMAL);
|
||||
GPS.println(FMWVERS);
|
||||
delay(1000); //wait a bit longer and repeat just in case it hasn't booted
|
||||
GPS.println(NOANTENNA);
|
||||
GPS.println(GGAZDA);
|
||||
GPS.println(NORMAL);
|
||||
GPS.println(FMWVERS);
|
||||
}
|
||||
594
src/Adafruit_LSM9DS1.cpp
Normal file
594
src/Adafruit_LSM9DS1.cpp
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
/***************************************************************************
|
||||
This is a library for the LSM9DS1 Accelerometer and magnentometer/compass
|
||||
|
||||
Designed specifically to work with the Adafruit LSM9DS1 Breakouts
|
||||
|
||||
These sensors use I2C to communicate, 2 pins are required to interface.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit andopen-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#include "Adafruit_LSM9DS1.h"
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
void Adafruit_LSM9DS1::initI2C( TwoWire* wireBus, int32_t sensorID ) {
|
||||
_i2c = true;
|
||||
_wire = wireBus;
|
||||
_lsm9dso_sensorid_accel = sensorID + 1;
|
||||
_lsm9dso_sensorid_mag = sensorID + 2;
|
||||
_lsm9dso_sensorid_gyro = sensorID + 3;
|
||||
_lsm9dso_sensorid_temp = sensorID + 4;
|
||||
_accelSensor = Sensor(this, &Adafruit_LSM9DS1::readAccel, &Adafruit_LSM9DS1::getAccelEvent, &Adafruit_LSM9DS1::getAccelSensor);
|
||||
_magSensor = Sensor(this, &Adafruit_LSM9DS1::readMag, &Adafruit_LSM9DS1::getMagEvent, &Adafruit_LSM9DS1::getMagSensor);
|
||||
_gyroSensor = Sensor(this, &Adafruit_LSM9DS1::readGyro, &Adafruit_LSM9DS1::getGyroEvent, &Adafruit_LSM9DS1::getGyroSensor);
|
||||
_tempSensor = Sensor(this, &Adafruit_LSM9DS1::readTemp, &Adafruit_LSM9DS1::getTempEvent, &Adafruit_LSM9DS1::getTempSensor);
|
||||
}
|
||||
|
||||
|
||||
// default
|
||||
Adafruit_LSM9DS1::Adafruit_LSM9DS1( int32_t sensorID ) {
|
||||
initI2C(&Wire, sensorID);
|
||||
}
|
||||
|
||||
Adafruit_LSM9DS1::Adafruit_LSM9DS1( TwoWire* wireBus, int32_t sensorID ) {
|
||||
initI2C(wireBus, sensorID);
|
||||
}
|
||||
|
||||
Adafruit_LSM9DS1::Adafruit_LSM9DS1(int8_t xgcs, int8_t mcs, int32_t sensorID ) {
|
||||
_i2c = false;
|
||||
// hardware SPI!
|
||||
_csm = mcs;
|
||||
_csxg = xgcs;
|
||||
_mosi = _miso = _clk = -1;
|
||||
_lsm9dso_sensorid_accel = sensorID + 1;
|
||||
_lsm9dso_sensorid_mag = sensorID + 2;
|
||||
_lsm9dso_sensorid_gyro = sensorID + 3;
|
||||
_lsm9dso_sensorid_temp = sensorID + 4;
|
||||
_accelSensor = Sensor(this, &Adafruit_LSM9DS1::readAccel, &Adafruit_LSM9DS1::getAccelEvent, &Adafruit_LSM9DS1::getAccelSensor);
|
||||
_magSensor = Sensor(this, &Adafruit_LSM9DS1::readMag, &Adafruit_LSM9DS1::getMagEvent, &Adafruit_LSM9DS1::getMagSensor);
|
||||
_gyroSensor = Sensor(this, &Adafruit_LSM9DS1::readGyro, &Adafruit_LSM9DS1::getGyroEvent, &Adafruit_LSM9DS1::getGyroSensor);
|
||||
_tempSensor = Sensor(this, &Adafruit_LSM9DS1::readTemp, &Adafruit_LSM9DS1::getTempEvent, &Adafruit_LSM9DS1::getTempSensor);
|
||||
}
|
||||
|
||||
Adafruit_LSM9DS1::Adafruit_LSM9DS1(int8_t sclk, int8_t smiso, int8_t smosi, int8_t xgcs, int8_t mcs, int32_t sensorID ) {
|
||||
_i2c = false;
|
||||
// software SPI!
|
||||
_csm = mcs;
|
||||
_csxg = xgcs;
|
||||
_mosi = smosi;
|
||||
_miso = smiso;
|
||||
_clk = sclk;
|
||||
_lsm9dso_sensorid_accel = sensorID + 1;
|
||||
_lsm9dso_sensorid_mag = sensorID + 2;
|
||||
_lsm9dso_sensorid_gyro = sensorID + 3;
|
||||
_lsm9dso_sensorid_temp = sensorID + 4;
|
||||
_accelSensor = Sensor(this, &Adafruit_LSM9DS1::readAccel, &Adafruit_LSM9DS1::getAccelEvent, &Adafruit_LSM9DS1::getAccelSensor);
|
||||
_magSensor = Sensor(this, &Adafruit_LSM9DS1::readMag, &Adafruit_LSM9DS1::getMagEvent, &Adafruit_LSM9DS1::getMagSensor);
|
||||
_gyroSensor = Sensor(this, &Adafruit_LSM9DS1::readGyro, &Adafruit_LSM9DS1::getGyroEvent, &Adafruit_LSM9DS1::getGyroSensor);
|
||||
_tempSensor = Sensor(this, &Adafruit_LSM9DS1::readTemp, &Adafruit_LSM9DS1::getTempEvent, &Adafruit_LSM9DS1::getTempSensor);
|
||||
}
|
||||
|
||||
bool Adafruit_LSM9DS1::begin()
|
||||
{
|
||||
if (_i2c) {
|
||||
_wire->setSDA(PB7);
|
||||
_wire->setSCL(PB8);
|
||||
_wire->begin();
|
||||
} else if (_clk == -1) {
|
||||
// Hardware SPI
|
||||
pinMode(_csxg, OUTPUT);
|
||||
pinMode(_csm, OUTPUT);
|
||||
digitalWrite(_csxg, HIGH);
|
||||
digitalWrite(_csm, HIGH);
|
||||
SPI.begin();
|
||||
} else {
|
||||
//Serial.println("softSPI");
|
||||
// Sofware SPI
|
||||
pinMode(_clk, OUTPUT);
|
||||
pinMode(_mosi, OUTPUT);
|
||||
pinMode(_miso, INPUT);
|
||||
pinMode(_csxg, OUTPUT);
|
||||
pinMode(_csm, OUTPUT);
|
||||
digitalWrite(_csxg, HIGH);
|
||||
digitalWrite(_csm, HIGH);
|
||||
digitalWrite(_clk, HIGH);
|
||||
}
|
||||
|
||||
|
||||
// soft reset & reboot accel/gyro
|
||||
write8(XGTYPE, LSM9DS1_REGISTER_CTRL_REG8, 0x05);
|
||||
// soft reset & reboot magnetometer
|
||||
write8(MAGTYPE, LSM9DS1_REGISTER_CTRL_REG2_M, 0x0C);
|
||||
|
||||
delay(10);
|
||||
|
||||
|
||||
/*
|
||||
for (uint8_t i=0; i<0x30; i++) {
|
||||
Serial.print("XG $"); Serial.print(i, HEX); Serial.print(" = 0x");
|
||||
Serial.println(read8(XGTYPE, i), HEX);
|
||||
}
|
||||
for (uint8_t i=0; i<0x30; i++) {
|
||||
Serial.print("M $"); Serial.print(i, HEX); Serial.print(" = 0x");
|
||||
Serial.println(read8(MAGTYPE, i), HEX);
|
||||
}
|
||||
*/
|
||||
|
||||
uint8_t id = read8(XGTYPE, LSM9DS1_REGISTER_WHO_AM_I_XG);
|
||||
//Serial.print ("XG whoami: 0x"); Serial.println(id, HEX);
|
||||
if (id != LSM9DS1_XG_ID)
|
||||
return false;
|
||||
|
||||
id = read8(MAGTYPE, LSM9DS1_REGISTER_WHO_AM_I_M);
|
||||
//Serial.print ("MAG whoami: 0x"); Serial.println(id, HEX);
|
||||
if (id != LSM9DS1_MAG_ID)
|
||||
return false;
|
||||
|
||||
// enable gyro continuous
|
||||
write8(XGTYPE, LSM9DS1_REGISTER_CTRL_REG1_G, 0xC0); // on XYZ
|
||||
|
||||
// Enable the accelerometer continous
|
||||
write8(XGTYPE, LSM9DS1_REGISTER_CTRL_REG5_XL, 0x38); // enable X Y and Z axis
|
||||
write8(XGTYPE, LSM9DS1_REGISTER_CTRL_REG6_XL, 0xC0); // 1 KHz out data rate, BW set by ODR, 408Hz anti-aliasing
|
||||
|
||||
|
||||
// enable mag continuous
|
||||
//write8(MAGTYPE, LSM9DS1_REGISTER_CTRL_REG1_M, 0xFC); // high perf XY, 80 Hz ODR
|
||||
write8(MAGTYPE, LSM9DS1_REGISTER_CTRL_REG3_M, 0x00); // continuous mode
|
||||
//write8(MAGTYPE, LSM9DS1_REGISTER_CTRL_REG4_M, 0x0C); // high perf Z mode
|
||||
|
||||
|
||||
|
||||
// Set default ranges for the various sensors
|
||||
setupAccel(LSM9DS1_ACCELRANGE_2G);
|
||||
setupMag(LSM9DS1_MAGGAIN_4GAUSS);
|
||||
setupGyro(LSM9DS1_GYROSCALE_245DPS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
void Adafruit_LSM9DS1::read()
|
||||
{
|
||||
/* Read all the sensors. */
|
||||
readAccel();
|
||||
readMag();
|
||||
readGyro();
|
||||
readTemp();
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::readAccel() {
|
||||
// Read the accelerometer
|
||||
byte buffer[6];
|
||||
readBuffer(XGTYPE,
|
||||
0x80 | LSM9DS1_REGISTER_OUT_X_L_XL,
|
||||
6, buffer);
|
||||
|
||||
uint8_t xlo = buffer[0];
|
||||
int16_t xhi = buffer[1];
|
||||
uint8_t ylo = buffer[2];
|
||||
int16_t yhi = buffer[3];
|
||||
uint8_t zlo = buffer[4];
|
||||
int16_t zhi = buffer[5];
|
||||
|
||||
// Shift values to create properly formed integer (low byte first)
|
||||
xhi <<= 8; xhi |= xlo;
|
||||
yhi <<= 8; yhi |= ylo;
|
||||
zhi <<= 8; zhi |= zlo;
|
||||
accelData.x = xhi;
|
||||
accelData.y = yhi;
|
||||
accelData.z = zhi;
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::readMag() {
|
||||
// Read the magnetometer
|
||||
byte buffer[6];
|
||||
readBuffer(MAGTYPE,
|
||||
0x80 | LSM9DS1_REGISTER_OUT_X_L_M,
|
||||
6, buffer);
|
||||
|
||||
uint8_t xlo = buffer[0];
|
||||
int16_t xhi = buffer[1];
|
||||
uint8_t ylo = buffer[2];
|
||||
int16_t yhi = buffer[3];
|
||||
uint8_t zlo = buffer[4];
|
||||
int16_t zhi = buffer[5];
|
||||
|
||||
// Shift values to create properly formed integer (low byte first)
|
||||
xhi <<= 8; xhi |= xlo;
|
||||
yhi <<= 8; yhi |= ylo;
|
||||
zhi <<= 8; zhi |= zlo;
|
||||
magData.x = xhi;
|
||||
magData.y = yhi;
|
||||
magData.z = zhi;
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::readGyro() {
|
||||
// Read gyro
|
||||
byte buffer[6];
|
||||
readBuffer(XGTYPE,
|
||||
0x80 | LSM9DS1_REGISTER_OUT_X_L_G,
|
||||
6, buffer);
|
||||
|
||||
uint8_t xlo = buffer[0];
|
||||
int16_t xhi = buffer[1];
|
||||
uint8_t ylo = buffer[2];
|
||||
int16_t yhi = buffer[3];
|
||||
uint8_t zlo = buffer[4];
|
||||
int16_t zhi = buffer[5];
|
||||
|
||||
// Shift values to create properly formed integer (low byte first)
|
||||
xhi <<= 8; xhi |= xlo;
|
||||
yhi <<= 8; yhi |= ylo;
|
||||
zhi <<= 8; zhi |= zlo;
|
||||
|
||||
gyroData.x = xhi;
|
||||
gyroData.y = yhi;
|
||||
gyroData.z = zhi;
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::readTemp() {
|
||||
// Read temp sensor
|
||||
byte buffer[2];
|
||||
readBuffer(XGTYPE,
|
||||
0x80 | LSM9DS1_REGISTER_TEMP_OUT_L,
|
||||
2, buffer);
|
||||
uint8_t xlo = buffer[0];
|
||||
int16_t xhi = buffer[1];
|
||||
|
||||
xhi <<= 8; xhi |= xlo;
|
||||
|
||||
// Shift values to create properly formed integer (low byte first)
|
||||
temperature = xhi;
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::setupAccel ( lsm9ds1AccelRange_t range )
|
||||
{
|
||||
uint8_t reg = read8(XGTYPE, LSM9DS1_REGISTER_CTRL_REG6_XL);
|
||||
reg &= ~(0b00011000);
|
||||
reg |= range;
|
||||
//Serial.println("set range: ");
|
||||
write8(XGTYPE, LSM9DS1_REGISTER_CTRL_REG6_XL, reg );
|
||||
|
||||
switch (range)
|
||||
{
|
||||
case LSM9DS1_ACCELRANGE_2G:
|
||||
_accel_mg_lsb = LSM9DS1_ACCEL_MG_LSB_2G;
|
||||
break;
|
||||
case LSM9DS1_ACCELRANGE_4G:
|
||||
_accel_mg_lsb = LSM9DS1_ACCEL_MG_LSB_4G;
|
||||
break;
|
||||
case LSM9DS1_ACCELRANGE_8G:
|
||||
_accel_mg_lsb = LSM9DS1_ACCEL_MG_LSB_8G;
|
||||
break;
|
||||
case LSM9DS1_ACCELRANGE_16G:
|
||||
_accel_mg_lsb =LSM9DS1_ACCEL_MG_LSB_16G;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::setupMag ( lsm9ds1MagGain_t gain )
|
||||
{
|
||||
uint8_t reg = read8(MAGTYPE, LSM9DS1_REGISTER_CTRL_REG2_M);
|
||||
reg &= ~(0b01100000);
|
||||
reg |= gain;
|
||||
write8(MAGTYPE, LSM9DS1_REGISTER_CTRL_REG2_M, reg );
|
||||
|
||||
switch(gain)
|
||||
{
|
||||
case LSM9DS1_MAGGAIN_4GAUSS:
|
||||
_mag_mgauss_lsb = LSM9DS1_MAG_MGAUSS_4GAUSS;
|
||||
break;
|
||||
case LSM9DS1_MAGGAIN_8GAUSS:
|
||||
_mag_mgauss_lsb = LSM9DS1_MAG_MGAUSS_8GAUSS;
|
||||
break;
|
||||
case LSM9DS1_MAGGAIN_12GAUSS:
|
||||
_mag_mgauss_lsb = LSM9DS1_MAG_MGAUSS_12GAUSS;
|
||||
break;
|
||||
case LSM9DS1_MAGGAIN_16GAUSS:
|
||||
_mag_mgauss_lsb = LSM9DS1_MAG_MGAUSS_16GAUSS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::setupGyro ( lsm9ds1GyroScale_t scale )
|
||||
{
|
||||
uint8_t reg = read8(XGTYPE, LSM9DS1_REGISTER_CTRL_REG1_G);
|
||||
reg &= ~(0b00011000);
|
||||
reg |= scale;
|
||||
write8(XGTYPE, LSM9DS1_REGISTER_CTRL_REG1_G, reg );
|
||||
|
||||
switch(scale)
|
||||
{
|
||||
case LSM9DS1_GYROSCALE_245DPS:
|
||||
_gyro_dps_digit = LSM9DS1_GYRO_DPS_DIGIT_245DPS;
|
||||
break;
|
||||
case LSM9DS1_GYROSCALE_500DPS:
|
||||
_gyro_dps_digit = LSM9DS1_GYRO_DPS_DIGIT_500DPS;
|
||||
break;
|
||||
case LSM9DS1_GYROSCALE_2000DPS:
|
||||
_gyro_dps_digit = LSM9DS1_GYRO_DPS_DIGIT_2000DPS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
UNIFIED SENSOR FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent accel sensor event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_LSM9DS1::getEvent(sensors_event_t *accelEvent,
|
||||
sensors_event_t *magEvent,
|
||||
sensors_event_t *gyroEvent,
|
||||
sensors_event_t *tempEvent )
|
||||
{
|
||||
/* Grab new sensor reading and timestamp. */
|
||||
read();
|
||||
uint32_t timestamp = millis();
|
||||
|
||||
/* Update appropriate sensor events. */
|
||||
if (accelEvent) getAccelEvent(accelEvent, timestamp);
|
||||
if (magEvent) getMagEvent(magEvent, timestamp);
|
||||
if (gyroEvent) getGyroEvent(gyroEvent, timestamp);
|
||||
if (tempEvent) getTempEvent(tempEvent, timestamp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_LSM9DS1::getSensor(sensor_t *accel, sensor_t *mag,
|
||||
sensor_t *gyro, sensor_t *temp )
|
||||
{
|
||||
/* Update appropriate sensor metadata. */
|
||||
if (accel) getAccelSensor(accel);
|
||||
if (mag) getMagSensor(mag);
|
||||
if (gyro) getGyroSensor(gyro);
|
||||
if (temp) getTempSensor(temp);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
void Adafruit_LSM9DS1::write8(boolean type, byte reg, byte value)
|
||||
{
|
||||
byte address, _cs;
|
||||
|
||||
if (type == MAGTYPE) {
|
||||
address = LSM9DS1_ADDRESS_MAG;
|
||||
_cs = _csm;
|
||||
} else {
|
||||
address = LSM9DS1_ADDRESS_ACCELGYRO;
|
||||
_cs = _csxg;
|
||||
}
|
||||
if (_i2c) {
|
||||
_wire->beginTransmission(address);
|
||||
_wire->write(reg);
|
||||
_wire->write(value);
|
||||
_wire->endTransmission();
|
||||
/*
|
||||
Serial.print("0x"); Serial.print(address, HEX);
|
||||
Serial.print(" $"); Serial.print(reg, HEX); Serial.print(" = ");
|
||||
Serial.println(value, HEX);
|
||||
*/
|
||||
} else {
|
||||
digitalWrite(_cs, LOW);
|
||||
if (_clk == -1) // hardware SPI
|
||||
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE3));
|
||||
// set address
|
||||
spixfer(reg & 0x7F); // write data
|
||||
spixfer(value);
|
||||
if (_clk == -1) // hardware SPI
|
||||
SPI.endTransaction();
|
||||
digitalWrite(_cs, HIGH);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
byte Adafruit_LSM9DS1::read8(boolean type, byte reg)
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
readBuffer(type, reg, 1, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
byte Adafruit_LSM9DS1::readBuffer(boolean type, byte reg, byte len, uint8_t *buffer)
|
||||
{
|
||||
byte address, _cs;
|
||||
|
||||
if (type == MAGTYPE) {
|
||||
address = LSM9DS1_ADDRESS_MAG;
|
||||
_cs = _csm;
|
||||
} else {
|
||||
address = LSM9DS1_ADDRESS_ACCELGYRO;
|
||||
_cs = _csxg;
|
||||
}
|
||||
|
||||
if (_i2c) {
|
||||
_wire->beginTransmission(address);
|
||||
_wire->write(reg);
|
||||
_wire->endTransmission();
|
||||
if (_wire->requestFrom(address, (byte)len) != len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Serial.print("0x"); Serial.print(address, HEX);
|
||||
Serial.print(" $"); Serial.print(reg, HEX); Serial.print(": ");
|
||||
*/
|
||||
|
||||
for (uint8_t i=0; i<len; i++) {
|
||||
buffer[i] = _wire->read();
|
||||
//Serial.print(buffer[i], HEX); Serial.print(", ");
|
||||
}
|
||||
//Serial.println();
|
||||
|
||||
} else {
|
||||
if (_clk == -1) // hardware SPI
|
||||
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE3));
|
||||
else
|
||||
digitalWrite(_clk, HIGH);
|
||||
// set address
|
||||
|
||||
digitalWrite(_cs, LOW);
|
||||
|
||||
if(type == MAGTYPE)
|
||||
reg |= 0x40;
|
||||
|
||||
spixfer(reg | 0x80 ); // readdata
|
||||
for (uint8_t i=0; i<len; i++) {
|
||||
buffer[i] = spixfer(0);
|
||||
}
|
||||
if (_clk == -1) // hardware SPI
|
||||
SPI.endTransaction();
|
||||
else
|
||||
digitalWrite(_clk, HIGH);
|
||||
digitalWrite(_cs, HIGH);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t Adafruit_LSM9DS1::spixfer(uint8_t data) {
|
||||
|
||||
if (_clk == -1) {
|
||||
//Serial.println("Hardware SPI");
|
||||
return SPI.transfer(data);
|
||||
} else {
|
||||
//Serial.println("Software SPI");
|
||||
uint8_t reply = 0;
|
||||
for (int i=7; i>=0; i--) {
|
||||
reply <<= 1;
|
||||
digitalWrite(_clk, LOW);
|
||||
digitalWrite(_mosi, data & (1<<i));
|
||||
digitalWrite(_clk, HIGH);
|
||||
if (digitalRead(_miso))
|
||||
reply |= 1;
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::getAccelEvent(sensors_event_t* event, uint32_t timestamp) {
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _lsm9dso_sensorid_accel;
|
||||
event->type = SENSOR_TYPE_ACCELEROMETER;
|
||||
event->timestamp = timestamp;
|
||||
event->acceleration.x = accelData.x * _accel_mg_lsb;
|
||||
event->acceleration.x /= 1000;
|
||||
event->acceleration.x *= SENSORS_GRAVITY_STANDARD;
|
||||
event->acceleration.y = accelData.y * _accel_mg_lsb;
|
||||
event->acceleration.y /= 1000;
|
||||
event->acceleration.y *= SENSORS_GRAVITY_STANDARD;
|
||||
event->acceleration.z = accelData.z * _accel_mg_lsb;
|
||||
event->acceleration.z /= 1000;
|
||||
event->acceleration.z *= SENSORS_GRAVITY_STANDARD;
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::getMagEvent(sensors_event_t* event, uint32_t timestamp) {
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _lsm9dso_sensorid_mag;
|
||||
event->type = SENSOR_TYPE_MAGNETIC_FIELD;
|
||||
event->timestamp = timestamp;
|
||||
event->magnetic.x = magData.x * _mag_mgauss_lsb;
|
||||
event->magnetic.x /= 1000;
|
||||
event->magnetic.y = magData.y * _mag_mgauss_lsb;
|
||||
event->magnetic.y /= 1000;
|
||||
event->magnetic.z = magData.z * _mag_mgauss_lsb;
|
||||
event->magnetic.z /= 1000;
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::getGyroEvent(sensors_event_t* event, uint32_t timestamp) {
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _lsm9dso_sensorid_accel;
|
||||
event->type = SENSOR_TYPE_GYROSCOPE;
|
||||
event->timestamp = timestamp;
|
||||
event->gyro.x = gyroData.x * _gyro_dps_digit;
|
||||
event->gyro.y = gyroData.y * _gyro_dps_digit;
|
||||
event->gyro.z = gyroData.z * _gyro_dps_digit;
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::getTempEvent(sensors_event_t* event, uint32_t timestamp) {
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _lsm9dso_sensorid_temp;
|
||||
event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
|
||||
event->timestamp = timestamp;
|
||||
// This is just a guess since the staring point (21C here) isn't documented :(
|
||||
event->temperature = 21.0 + (float)temperature/8;
|
||||
//event->temperature /= LSM9DS1_TEMP_LSB_DEGREE_CELSIUS;
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::getAccelSensor(sensor_t* sensor) {
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
strncpy (sensor->name, "LSM9DS1_A", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _lsm9dso_sensorid_accel;
|
||||
sensor->type = SENSOR_TYPE_ACCELEROMETER;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 0.0; // ToDo
|
||||
sensor->min_value = 0.0; // ToDo
|
||||
sensor->resolution = 0.0; // ToDo
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::getMagSensor(sensor_t* sensor) {
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
strncpy (sensor->name, "LSM9DS1_M", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _lsm9dso_sensorid_mag;
|
||||
sensor->type = SENSOR_TYPE_MAGNETIC_FIELD;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 0.0; // ToDo
|
||||
sensor->min_value = 0.0; // ToDo
|
||||
sensor->resolution = 0.0; // ToDo
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::getGyroSensor(sensor_t* sensor) {
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
strncpy (sensor->name, "LSM9DS1_G", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _lsm9dso_sensorid_gyro;
|
||||
sensor->type = SENSOR_TYPE_GYROSCOPE;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 0.0; // ToDo
|
||||
sensor->min_value = 0.0; // ToDo
|
||||
sensor->resolution = 0.0; // ToDo
|
||||
}
|
||||
|
||||
void Adafruit_LSM9DS1::getTempSensor(sensor_t* sensor) {
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
strncpy (sensor->name, "LSM9DS1_T", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _lsm9dso_sensorid_temp;
|
||||
sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 0.0; // ToDo
|
||||
sensor->min_value = 0.0; // ToDo
|
||||
sensor->resolution = 0.0; // ToDo
|
||||
}
|
||||
280
src/Adafruit_LSM9DS1.h
Normal file
280
src/Adafruit_LSM9DS1.h
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
/***************************************************************************
|
||||
This is a library for the LSM9DS1 Accelerometer and magnentometer/compass
|
||||
|
||||
Designed specifically to work with the Adafruit LSM9DS1 Breakouts
|
||||
|
||||
These sensors use I2C to communicate, 2 pins are required to interface.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit andopen-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
|
||||
Written by Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
#ifndef __LSM9DS1_H__
|
||||
#define __LSM9DS1_H__
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#include "Wire.h"
|
||||
#include <SPI.h>
|
||||
#include "Adafruit_Sensor.h"
|
||||
|
||||
#define LSM9DS1_ADDRESS_ACCELGYRO (0x6A)
|
||||
#define LSM9DS1_ADDRESS_MAG (0x1C)
|
||||
#define LSM9DS1_XG_ID (0b01101000)
|
||||
#define LSM9DS1_MAG_ID (0b00111101)
|
||||
|
||||
|
||||
// Linear Acceleration: mg per LSB
|
||||
#define LSM9DS1_ACCEL_MG_LSB_2G (0.061F)
|
||||
#define LSM9DS1_ACCEL_MG_LSB_4G (0.122F)
|
||||
#define LSM9DS1_ACCEL_MG_LSB_8G (0.244F)
|
||||
#define LSM9DS1_ACCEL_MG_LSB_16G (0.732F)
|
||||
|
||||
// Magnetic Field Strength: gauss range
|
||||
#define LSM9DS1_MAG_MGAUSS_4GAUSS (0.14F)
|
||||
#define LSM9DS1_MAG_MGAUSS_8GAUSS (0.29F)
|
||||
#define LSM9DS1_MAG_MGAUSS_12GAUSS (0.43F)
|
||||
#define LSM9DS1_MAG_MGAUSS_16GAUSS (0.58F)
|
||||
|
||||
// Angular Rate: dps per LSB
|
||||
#define LSM9DS1_GYRO_DPS_DIGIT_245DPS (0.00875F)
|
||||
#define LSM9DS1_GYRO_DPS_DIGIT_500DPS (0.01750F)
|
||||
#define LSM9DS1_GYRO_DPS_DIGIT_2000DPS (0.07000F)
|
||||
|
||||
// Temperature: LSB per degree celsius
|
||||
#define LSM9DS1_TEMP_LSB_DEGREE_CELSIUS (8) // 1°C = 8, 25° = 200, etc.
|
||||
|
||||
#define MAGTYPE (true)
|
||||
#define XGTYPE (false)
|
||||
|
||||
/* Forward reference required for function pointers below. */
|
||||
class Adafruit_LSM9DS1;
|
||||
|
||||
/* Pointer to member functions for read, get event, and get sensor. These are used */
|
||||
/* by the Adafruit_LSM9DS1::Sensor class to read and retrieve individual sensors. */
|
||||
typedef void (Adafruit_LSM9DS1::*lsm9ds1_read_func)(void);
|
||||
typedef void (Adafruit_LSM9DS1::*lsm9ds1_get_event_func)(sensors_event_t*, uint32_t);
|
||||
typedef void (Adafruit_LSM9DS1::*lsm9ds1_get_sensor_func)(sensor_t*);
|
||||
|
||||
class Adafruit_LSM9DS1
|
||||
{
|
||||
public:
|
||||
Adafruit_LSM9DS1 ( int32_t sensorID = 0 );
|
||||
Adafruit_LSM9DS1 ( TwoWire* wireBus, int32_t sensorID = 0 );
|
||||
Adafruit_LSM9DS1 ( int8_t xmcs, int8_t gcs, int32_t sensorID = 0 );
|
||||
Adafruit_LSM9DS1 ( int8_t clk, int8_t miso, int8_t mosi, int8_t xmcs, int8_t gcs, int32_t sensorID = 0 );
|
||||
|
||||
void initI2C( TwoWire* wireBus, int32_t sensorID );
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LSM9DS1_REGISTER_WHO_AM_I_XG = 0x0F,
|
||||
LSM9DS1_REGISTER_CTRL_REG1_G = 0x10,
|
||||
LSM9DS1_REGISTER_CTRL_REG2_G = 0x11,
|
||||
LSM9DS1_REGISTER_CTRL_REG3_G = 0x12,
|
||||
LSM9DS1_REGISTER_TEMP_OUT_L = 0x15,
|
||||
LSM9DS1_REGISTER_TEMP_OUT_H = 0x16,
|
||||
LSM9DS1_REGISTER_STATUS_REG = 0x17,
|
||||
LSM9DS1_REGISTER_OUT_X_L_G = 0x18,
|
||||
LSM9DS1_REGISTER_OUT_X_H_G = 0x19,
|
||||
LSM9DS1_REGISTER_OUT_Y_L_G = 0x1A,
|
||||
LSM9DS1_REGISTER_OUT_Y_H_G = 0x1B,
|
||||
LSM9DS1_REGISTER_OUT_Z_L_G = 0x1C,
|
||||
LSM9DS1_REGISTER_OUT_Z_H_G = 0x1D,
|
||||
LSM9DS1_REGISTER_CTRL_REG4 = 0x1E,
|
||||
LSM9DS1_REGISTER_CTRL_REG5_XL = 0x1F,
|
||||
LSM9DS1_REGISTER_CTRL_REG6_XL = 0x20,
|
||||
LSM9DS1_REGISTER_CTRL_REG7_XL = 0x21,
|
||||
LSM9DS1_REGISTER_CTRL_REG8 = 0x22,
|
||||
LSM9DS1_REGISTER_CTRL_REG9 = 0x23,
|
||||
LSM9DS1_REGISTER_CTRL_REG10 = 0x24,
|
||||
|
||||
LSM9DS1_REGISTER_OUT_X_L_XL = 0x28,
|
||||
LSM9DS1_REGISTER_OUT_X_H_XL = 0x29,
|
||||
LSM9DS1_REGISTER_OUT_Y_L_XL = 0x2A,
|
||||
LSM9DS1_REGISTER_OUT_Y_H_XL = 0x2B,
|
||||
LSM9DS1_REGISTER_OUT_Z_L_XL = 0x2C,
|
||||
LSM9DS1_REGISTER_OUT_Z_H_XL = 0x2D,
|
||||
|
||||
} lsm9ds1AccGyroRegisters_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
||||
LSM9DS1_REGISTER_WHO_AM_I_M = 0x0F,
|
||||
LSM9DS1_REGISTER_CTRL_REG1_M = 0x20,
|
||||
LSM9DS1_REGISTER_CTRL_REG2_M = 0x21,
|
||||
LSM9DS1_REGISTER_CTRL_REG3_M = 0x22,
|
||||
LSM9DS1_REGISTER_CTRL_REG4_M = 0x23,
|
||||
LSM9DS1_REGISTER_CTRL_REG5_M = 0x24,
|
||||
LSM9DS1_REGISTER_STATUS_REG_M = 0x27,
|
||||
LSM9DS1_REGISTER_OUT_X_L_M = 0x28,
|
||||
LSM9DS1_REGISTER_OUT_X_H_M = 0x29,
|
||||
LSM9DS1_REGISTER_OUT_Y_L_M = 0x2A,
|
||||
LSM9DS1_REGISTER_OUT_Y_H_M = 0x2B,
|
||||
LSM9DS1_REGISTER_OUT_Z_L_M = 0x2C,
|
||||
LSM9DS1_REGISTER_OUT_Z_H_M = 0x2D,
|
||||
LSM9DS1_REGISTER_CFG_M = 0x30,
|
||||
LSM9DS1_REGISTER_INT_SRC_M = 0x31,
|
||||
} lsm9ds1MagRegisters_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LSM9DS1_ACCELRANGE_2G = (0b00 << 3),
|
||||
LSM9DS1_ACCELRANGE_16G = (0b01 << 3),
|
||||
LSM9DS1_ACCELRANGE_4G = (0b10 << 3),
|
||||
LSM9DS1_ACCELRANGE_8G = (0b11 << 3),
|
||||
} lsm9ds1AccelRange_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LSM9DS1_ACCELDATARATE_POWERDOWN = (0b0000 << 4),
|
||||
LSM9DS1_ACCELDATARATE_3_125HZ = (0b0001 << 4),
|
||||
LSM9DS1_ACCELDATARATE_6_25HZ = (0b0010 << 4),
|
||||
LSM9DS1_ACCELDATARATE_12_5HZ = (0b0011 << 4),
|
||||
LSM9DS1_ACCELDATARATE_25HZ = (0b0100 << 4),
|
||||
LSM9DS1_ACCELDATARATE_50HZ = (0b0101 << 4),
|
||||
LSM9DS1_ACCELDATARATE_100HZ = (0b0110 << 4),
|
||||
LSM9DS1_ACCELDATARATE_200HZ = (0b0111 << 4),
|
||||
LSM9DS1_ACCELDATARATE_400HZ = (0b1000 << 4),
|
||||
LSM9DS1_ACCELDATARATE_800HZ = (0b1001 << 4),
|
||||
LSM9DS1_ACCELDATARATE_1600HZ = (0b1010 << 4)
|
||||
} lm9ds1AccelDataRate_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LSM9DS1_MAGGAIN_4GAUSS = (0b00 << 5), // +/- 4 gauss
|
||||
LSM9DS1_MAGGAIN_8GAUSS = (0b01 << 5), // +/- 8 gauss
|
||||
LSM9DS1_MAGGAIN_12GAUSS = (0b10 << 5), // +/- 12 gauss
|
||||
LSM9DS1_MAGGAIN_16GAUSS = (0b11 << 5) // +/- 16 gauss
|
||||
} lsm9ds1MagGain_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LSM9DS1_MAGDATARATE_3_125HZ = (0b000 << 2),
|
||||
LSM9DS1_MAGDATARATE_6_25HZ = (0b001 << 2),
|
||||
LSM9DS1_MAGDATARATE_12_5HZ = (0b010 << 2),
|
||||
LSM9DS1_MAGDATARATE_25HZ = (0b011 << 2),
|
||||
LSM9DS1_MAGDATARATE_50HZ = (0b100 << 2),
|
||||
LSM9DS1_MAGDATARATE_100HZ = (0b101 << 2)
|
||||
} lsm9ds1MagDataRate_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LSM9DS1_GYROSCALE_245DPS = (0b00 << 3), // +/- 245 degrees per second rotation
|
||||
LSM9DS1_GYROSCALE_500DPS = (0b01 << 3), // +/- 500 degrees per second rotation
|
||||
LSM9DS1_GYROSCALE_2000DPS = (0b11 << 3) // +/- 2000 degrees per second rotation
|
||||
} lsm9ds1GyroScale_t;
|
||||
|
||||
typedef struct vector_s
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} lsm9ds1Vector_t;
|
||||
|
||||
lsm9ds1Vector_t accelData; // Last read accelerometer data will be available here
|
||||
lsm9ds1Vector_t magData; // Last read magnetometer data will be available here
|
||||
lsm9ds1Vector_t gyroData; // Last read gyroscope data will be available here
|
||||
int16_t temperature; // Last read temperzture data will be available here
|
||||
|
||||
bool begin ( void );
|
||||
void read ( void );
|
||||
void readAccel ( void );
|
||||
void readMag ( void );
|
||||
void readGyro ( void );
|
||||
void readTemp ( void );
|
||||
void setupAccel ( lsm9ds1AccelRange_t range );
|
||||
void setupMag ( lsm9ds1MagGain_t gain );
|
||||
void setupGyro ( lsm9ds1GyroScale_t scale );
|
||||
void write8 ( boolean type, byte reg, byte value );
|
||||
byte read8 ( boolean type, byte reg);
|
||||
byte readBuffer ( boolean type, byte reg, byte len, uint8_t *buffer);
|
||||
uint8_t spixfer ( uint8_t data );
|
||||
|
||||
/* Adafruit Unified Sensor Functions (not standard yet ... the current base class only */
|
||||
/* supports one sensor type, and we need to update the unified base class to support */
|
||||
/* multiple sensors in a single driver, returning an array */
|
||||
bool getEvent ( sensors_event_t* accel, sensors_event_t* mag, sensors_event_t* gyro, sensors_event_t* temp );
|
||||
void getSensor ( sensor_t* accel, sensor_t* mag, sensor_t* gyro, sensor_t* temp );
|
||||
|
||||
/* Subclass to expose each sensor on the LSM9DS1 as an Adafruit_Sensor instance. */
|
||||
class Sensor: public Adafruit_Sensor {
|
||||
public:
|
||||
Sensor() {}
|
||||
Sensor(const Sensor& copy):
|
||||
_parent(copy._parent),
|
||||
_readFunc(copy._readFunc),
|
||||
_eventFunc(copy._eventFunc),
|
||||
_sensorFunc(copy._sensorFunc)
|
||||
{}
|
||||
Sensor(Adafruit_LSM9DS1* parent, lsm9ds1_read_func readFunc,
|
||||
lsm9ds1_get_event_func eventFunc, lsm9ds1_get_sensor_func sensorFunc):
|
||||
_parent(parent),
|
||||
_readFunc(readFunc),
|
||||
_eventFunc(eventFunc),
|
||||
_sensorFunc(sensorFunc)
|
||||
{}
|
||||
virtual bool getEvent(sensors_event_t* event) {
|
||||
/* Take new reading. */
|
||||
(_parent->*_readFunc)();
|
||||
/* Fill in event data. */
|
||||
(_parent->*_eventFunc)(event, millis());
|
||||
}
|
||||
virtual void getSensor(sensor_t* sensor) {
|
||||
/* Fill in sensor metadata. */
|
||||
(_parent->*_sensorFunc)(sensor);
|
||||
}
|
||||
|
||||
private:
|
||||
Adafruit_LSM9DS1* _parent;
|
||||
lsm9ds1_read_func _readFunc;
|
||||
lsm9ds1_get_event_func _eventFunc;
|
||||
lsm9ds1_get_sensor_func _sensorFunc;
|
||||
};
|
||||
|
||||
/* Individual Adafruit_Sensor instances for each sensor on the board. */
|
||||
Sensor& getAccel ( void ) { return _accelSensor; }
|
||||
Sensor& getMag ( void ) { return _magSensor; }
|
||||
Sensor& getGyro ( void ) { return _gyroSensor; }
|
||||
Sensor& getTemp ( void ) { return _tempSensor; }
|
||||
|
||||
private:
|
||||
boolean _i2c;
|
||||
TwoWire* _wire;
|
||||
int8_t _csm, _csxg, _mosi, _miso, _clk;
|
||||
float _accel_mg_lsb;
|
||||
float _mag_mgauss_lsb;
|
||||
float _gyro_dps_digit;
|
||||
int32_t _lsm9dso_sensorid_accel;
|
||||
int32_t _lsm9dso_sensorid_mag;
|
||||
int32_t _lsm9dso_sensorid_gyro;
|
||||
int32_t _lsm9dso_sensorid_temp;
|
||||
Sensor _accelSensor;
|
||||
Sensor _magSensor;
|
||||
Sensor _gyroSensor;
|
||||
Sensor _tempSensor;
|
||||
|
||||
/* Functions to get individual sensor measurements and metadata. */
|
||||
/* Note that these functions will NOT update the sensor state before getting */
|
||||
/* a new reading. You MUST call read() manually to update the sensor state */
|
||||
/* before calling these functions! */
|
||||
void getAccelEvent ( sensors_event_t* event, uint32_t timestamp );
|
||||
void getMagEvent ( sensors_event_t* event, uint32_t timestamp );
|
||||
void getGyroEvent ( sensors_event_t* event, uint32_t timestamp );
|
||||
void getTempEvent ( sensors_event_t* event, uint32_t timestamp );
|
||||
void getAccelSensor ( sensor_t* sensor );
|
||||
void getMagSensor ( sensor_t* sensor );
|
||||
void getGyroSensor ( sensor_t* sensor );
|
||||
void getTempSensor ( sensor_t* sensor );
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
156
src/Adafruit_Sensor.h
Normal file
156
src/Adafruit_Sensor.h
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
#ifndef ARDUINO
|
||||
#include <stdint.h>
|
||||
#elif 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) { (void)enabled; /* suppress unused warning */ };
|
||||
virtual bool getEvent(sensors_event_t*) = 0;
|
||||
virtual void getSensor(sensor_t*) = 0;
|
||||
|
||||
private:
|
||||
bool _autoRange;
|
||||
};
|
||||
|
||||
#endif
|
||||
25
src/LICENSE_LPS_LSM303.txt
Normal file
25
src/LICENSE_LPS_LSM303.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2013 Pololu Corporation. For more information, see
|
||||
|
||||
http://www.pololu.com/
|
||||
http://forum.pololu.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
9
src/LICENSE_sparkfun.md
Normal file
9
src/LICENSE_sparkfun.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
License Information
|
||||
-------------------
|
||||
|
||||
The hardware is released under [Creative Commons Share-alike 3.0](http://creativecommons.org/licenses/by-sa/3.0/).
|
||||
|
||||
All other code is open source so please feel free to do anything you want with it; you buy me a beer if you use this and we meet someday ([Beerware license](http://en.wikipedia.org/wiki/Beerware)).
|
||||
|
||||
|
||||
235
src/LPS.cpp
Normal file
235
src/LPS.cpp
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
#include "LPS.h"
|
||||
#include <Wire.h>
|
||||
|
||||
// Defines ///////////////////////////////////////////////////////////
|
||||
|
||||
// The Arduino two-wire interface uses a 7-bit number for the address,
|
||||
// and sets the last bit correctly based on reads and writes
|
||||
#define SA0_LOW_ADDRESS 0b1011100
|
||||
#define SA0_HIGH_ADDRESS 0b1011101
|
||||
|
||||
#define TEST_REG_NACK -1
|
||||
|
||||
#define LPS331AP_WHO_ID 0xBB
|
||||
#define LPS25H_WHO_ID 0xBD
|
||||
|
||||
// Constructors //////////////////////////////////////////////////////
|
||||
|
||||
LPS::LPS(void)
|
||||
{
|
||||
_device = device_auto;
|
||||
|
||||
// Pololu board pulls SA0 high, so default assumption is that it is
|
||||
// high
|
||||
address = SA0_LOW_ADDRESS;
|
||||
}
|
||||
|
||||
// Public Methods ////////////////////////////////////////////////////
|
||||
|
||||
// sets or detects device type and slave address; returns bool indicating success
|
||||
bool LPS::init(deviceType device, byte sa0)
|
||||
{
|
||||
if (!detectDeviceAndAddress(device, (sa0State)sa0))
|
||||
return false;
|
||||
|
||||
switch (_device)
|
||||
{
|
||||
case device_25H:
|
||||
translated_regs[-INTERRUPT_CFG] = LPS25H_INTERRUPT_CFG;
|
||||
translated_regs[-INT_SOURCE] = LPS25H_INT_SOURCE;
|
||||
translated_regs[-THS_P_L] = LPS25H_THS_P_L;
|
||||
translated_regs[-THS_P_H] = LPS25H_THS_P_H;
|
||||
return true;
|
||||
break;
|
||||
|
||||
case device_331AP:
|
||||
translated_regs[-INTERRUPT_CFG] = LPS331AP_INTERRUPT_CFG;
|
||||
translated_regs[-INT_SOURCE] = LPS331AP_INT_SOURCE;
|
||||
translated_regs[-THS_P_L] = LPS331AP_THS_P_L;
|
||||
translated_regs[-THS_P_H] = LPS331AP_THS_P_H;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// turns on sensor and enables continuous output
|
||||
void LPS::enableDefault(void)
|
||||
{
|
||||
if (_device == device_25H)
|
||||
{
|
||||
// 0xB0 = 0b10110000
|
||||
// PD = 1 (active mode); ODR = 011 (12.5 Hz pressure & temperature output data rate)
|
||||
writeReg(CTRL_REG1, 0xB0);
|
||||
}
|
||||
else if (_device == device_331AP)
|
||||
{
|
||||
// 0xE0 = 0b11100000
|
||||
// PD = 1 (active mode); ODR = 110 (12.5 Hz pressure & temperature output data rate)
|
||||
writeReg(CTRL_REG1, 0xE0);
|
||||
}
|
||||
}
|
||||
|
||||
// writes register
|
||||
void LPS::writeReg(int reg, byte value)
|
||||
{
|
||||
// if dummy register address, look up actual translated address (based on device type)
|
||||
if (reg < 0)
|
||||
{
|
||||
reg = translated_regs[-reg];
|
||||
}
|
||||
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(reg);
|
||||
Wire.write(value);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
// reads register
|
||||
byte LPS::readReg(int reg)
|
||||
{
|
||||
byte value;
|
||||
|
||||
// if dummy register address, look up actual translated address (based on device type)
|
||||
if (reg < 0)
|
||||
{
|
||||
reg = translated_regs[-reg];
|
||||
}
|
||||
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission(false); // restart
|
||||
Wire.requestFrom(address, (byte)1);
|
||||
value = Wire.read();
|
||||
Wire.endTransmission();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// reads pressure in millibars (mbar)/hectopascals (hPa)
|
||||
float LPS::readPressureMillibars(void)
|
||||
{
|
||||
return (float)readPressureRaw() / 4096;
|
||||
}
|
||||
|
||||
// reads pressure in inches of mercury (inHg)
|
||||
float LPS::readPressureInchesHg(void)
|
||||
{
|
||||
return (float)readPressureRaw() / 138706.5;
|
||||
}
|
||||
|
||||
// reads pressure and returns raw 24-bit sensor output
|
||||
int32_t LPS::readPressureRaw(void)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
// assert MSB to enable register address auto-increment
|
||||
Wire.write(PRESS_OUT_XL | (1 << 7));
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(address, (byte)3);
|
||||
|
||||
while (Wire.available() < 3);
|
||||
|
||||
uint8_t pxl = Wire.read();
|
||||
uint8_t pl = Wire.read();
|
||||
uint8_t ph = Wire.read();
|
||||
|
||||
// combine bytes
|
||||
return (int32_t)(int8_t)ph << 16 | (uint16_t)pl << 8 | pxl;
|
||||
}
|
||||
|
||||
// reads temperature in degrees C
|
||||
float LPS::readTemperatureC(void)
|
||||
{
|
||||
return 42.5 + (float)readTemperatureRaw() / 480;
|
||||
}
|
||||
|
||||
// reads temperature in degrees F
|
||||
float LPS::readTemperatureF(void)
|
||||
{
|
||||
return 108.5 + (float)readTemperatureRaw() / 480 * 1.8;
|
||||
}
|
||||
|
||||
// reads temperature and returns raw 16-bit sensor output
|
||||
int16_t LPS::readTemperatureRaw(void)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
// assert MSB to enable register address auto-increment
|
||||
Wire.write(TEMP_OUT_L | (1 << 7));
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(address, (byte)2);
|
||||
|
||||
while (Wire.available() < 2);
|
||||
|
||||
uint8_t tl = Wire.read();
|
||||
uint8_t th = Wire.read();
|
||||
|
||||
// combine bytes
|
||||
return (int16_t)(th << 8 | tl);
|
||||
}
|
||||
|
||||
// converts pressure in mbar to altitude in meters, using 1976 US
|
||||
// Standard Atmosphere model (note that this formula only applies to a
|
||||
// height of 11 km, or about 36000 ft)
|
||||
// If altimeter setting (QNH, barometric pressure adjusted to sea
|
||||
// level) is given, this function returns an indicated altitude
|
||||
// compensated for actual regional pressure; otherwise, it returns
|
||||
// the pressure altitude above the standard pressure level of 1013.25
|
||||
// mbar or 29.9213 inHg
|
||||
float LPS::pressureToAltitudeMeters(float pressure_mbar, float altimeter_setting_mbar)
|
||||
{
|
||||
return (1 - pow(pressure_mbar / altimeter_setting_mbar, 0.190263)) * 44330.8;
|
||||
}
|
||||
|
||||
// converts pressure in inHg to altitude in feet; see notes above
|
||||
float LPS::pressureToAltitudeFeet(float pressure_inHg, float altimeter_setting_inHg)
|
||||
{
|
||||
return (1 - pow(pressure_inHg / altimeter_setting_inHg, 0.190263)) * 145442;
|
||||
}
|
||||
|
||||
// Private Methods ///////////////////////////////////////////////////
|
||||
|
||||
bool LPS::detectDeviceAndAddress(deviceType device, sa0State sa0)
|
||||
{
|
||||
if (sa0 == sa0_auto || sa0 == sa0_high)
|
||||
{
|
||||
address = SA0_HIGH_ADDRESS;
|
||||
if (detectDevice(device)) return true;
|
||||
}
|
||||
if (sa0 == sa0_auto || sa0 == sa0_low)
|
||||
{
|
||||
address = SA0_LOW_ADDRESS;
|
||||
if (detectDevice(device)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LPS::detectDevice(deviceType device)
|
||||
{
|
||||
int id = testWhoAmI(address);
|
||||
|
||||
if ((device == device_auto || device == device_25H) && id == LPS25H_WHO_ID)
|
||||
{
|
||||
_device = device_25H;
|
||||
return true;
|
||||
}
|
||||
if ((device == device_auto || device == device_331AP) && id == LPS331AP_WHO_ID)
|
||||
{
|
||||
_device = device_331AP;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int LPS::testWhoAmI(byte address)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(WHO_AM_I);
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(address, (byte)1);
|
||||
if (Wire.available())
|
||||
return Wire.read();
|
||||
else
|
||||
return TEST_REG_NACK;
|
||||
}
|
||||
110
src/LPS.h
Normal file
110
src/LPS.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#ifndef LPS_h
|
||||
#define LPS_h
|
||||
|
||||
#include <Arduino.h> // for byte data type
|
||||
|
||||
class LPS
|
||||
{
|
||||
public:
|
||||
enum deviceType { device_331AP, device_25H, device_auto };
|
||||
enum sa0State { sa0_low, sa0_high, sa0_auto };
|
||||
|
||||
// register addresses
|
||||
// Note: where register names differ between the register mapping table and
|
||||
// the register descriptions in the datasheets, the names from the register
|
||||
// descriptions are used here.
|
||||
enum regAddr
|
||||
{
|
||||
REF_P_XL = 0x08,
|
||||
REF_P_L = 0x09,
|
||||
REF_P_H = 0x0A,
|
||||
|
||||
WHO_AM_I = 0x0F,
|
||||
|
||||
RES_CONF = 0x10,
|
||||
|
||||
CTRL_REG1 = 0x20,
|
||||
CTRL_REG2 = 0x21,
|
||||
CTRL_REG3 = 0x22,
|
||||
CTRL_REG4 = 0x23, // 25H
|
||||
|
||||
STATUS_REG = 0x27,
|
||||
|
||||
PRESS_OUT_XL = 0x28,
|
||||
PRESS_OUT_L = 0x29,
|
||||
PRESS_OUT_H = 0x2A,
|
||||
|
||||
TEMP_OUT_L = 0x2B,
|
||||
TEMP_OUT_H = 0x2C,
|
||||
|
||||
FIFO_CTRL = 0x2E, // 25H
|
||||
FIFO_STATUS = 0x2F, // 25H
|
||||
|
||||
AMP_CTRL = 0x30, // 331AP
|
||||
|
||||
RPDS_L = 0x39, // 25H
|
||||
RPDS_H = 0x3A, // 25H
|
||||
|
||||
DELTA_PRESS_XL = 0x3C, // 331AP
|
||||
DELTA_PRESS_L = 0x3D, // 331AP
|
||||
DELTA_PRESS_H = 0x3E, // 331AP
|
||||
|
||||
|
||||
// dummy addresses for registers in different locations on different devices;
|
||||
// the library translates these based on device type
|
||||
// value with sign flipped is used as index into translated_regs array
|
||||
|
||||
INTERRUPT_CFG = -1,
|
||||
INT_SOURCE = -2,
|
||||
THS_P_L = -3,
|
||||
THS_P_H = -4,
|
||||
// update dummy_reg_count if registers are added here!
|
||||
|
||||
|
||||
// device-specific register addresses
|
||||
|
||||
LPS331AP_INTERRUPT_CFG = 0x23,
|
||||
LPS331AP_INT_SOURCE = 0x24,
|
||||
LPS331AP_THS_P_L = 0x25,
|
||||
LPS331AP_THS_P_H = 0x26,
|
||||
|
||||
LPS25H_INTERRUPT_CFG = 0x24,
|
||||
LPS25H_INT_SOURCE = 0x25,
|
||||
LPS25H_THS_P_L = 0x30,
|
||||
LPS25H_THS_P_H = 0x31,
|
||||
};
|
||||
|
||||
LPS(void);
|
||||
|
||||
bool init(deviceType device = device_auto, byte sa0 = sa0_auto);
|
||||
deviceType getDeviceType(void) { return _device; }
|
||||
byte getAddress(void) { return address; }
|
||||
|
||||
void enableDefault(void);
|
||||
|
||||
void writeReg(int reg, byte value);
|
||||
byte readReg(int reg);
|
||||
|
||||
float readPressureMillibars(void);
|
||||
float readPressureInchesHg(void);
|
||||
int32_t readPressureRaw(void);
|
||||
float readTemperatureC(void);
|
||||
float readTemperatureF(void);
|
||||
int16_t readTemperatureRaw(void);
|
||||
|
||||
static float pressureToAltitudeMeters(float pressure_mbar, float altimeter_setting_mbar = 1013.25);
|
||||
static float pressureToAltitudeFeet(float pressure_inHg, float altimeter_setting_inHg = 29.9213);
|
||||
|
||||
private:
|
||||
deviceType _device; // chip type (331AP or 25H)
|
||||
byte address;
|
||||
|
||||
static const int dummy_reg_count = 4;
|
||||
regAddr translated_regs[dummy_reg_count + 1]; // index 0 not used
|
||||
|
||||
bool detectDeviceAndAddress(deviceType device, sa0State sa0);
|
||||
bool detectDevice(deviceType device);
|
||||
int testWhoAmI(byte address);
|
||||
};
|
||||
|
||||
#endif
|
||||
211
src/SparkFunHTU21D.cpp
Normal file
211
src/SparkFunHTU21D.cpp
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
HTU21D Humidity Sensor Library
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: September 22nd, 2013
|
||||
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
|
||||
|
||||
This library allows an Arduino to read from the HTU21D low-cost high-precision humidity sensor.
|
||||
|
||||
If you have feature suggestions or need support please use the github support page: https://github.com/sparkfun/HTU21D
|
||||
|
||||
Hardware Setup: The HTU21D lives on the I2C bus. Attach the SDA pin to A4, SCL to A5. If you are using the SparkFun
|
||||
breakout board you *do not* need 4.7k pull-up resistors on the bus (they are built-in).
|
||||
|
||||
Link to the breakout board product:
|
||||
|
||||
Software:
|
||||
Call HTU21D.Begin() in setup.
|
||||
HTU21D.ReadHumidity() will return a float containing the humidity. Ex: 54.7
|
||||
HTU21D.ReadTemperature() will return a float containing the temperature in Celsius. Ex: 24.1
|
||||
HTU21D.SetResolution(byte: 0b.76543210) sets the resolution of the readings.
|
||||
HTU21D.check_crc(message, check_value) verifies the 8-bit CRC generated by the sensor
|
||||
HTU21D.read_user_register() returns the user register. Used to set resolution.
|
||||
*/
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#include "SparkFunHTU21D.h"
|
||||
|
||||
HTU21D::HTU21D()
|
||||
{
|
||||
//Set initial values for private vars
|
||||
}
|
||||
|
||||
//Begin
|
||||
/*******************************************************************************************/
|
||||
//Start I2C communication
|
||||
bool HTU21D::begin(TwoWire &wirePort)
|
||||
{
|
||||
_i2cPort = &wirePort; //Grab which port the user wants us to use
|
||||
_i2cPort->setSDA(PB7);
|
||||
_i2cPort->setSCL(PB8);
|
||||
_i2cPort->begin();
|
||||
|
||||
// check availability
|
||||
/*_i2cPort->beginTransmission(HTU21D_ADDRESS);
|
||||
int err = _i2cPort->beginTransmission(HTU21D_ADDRESS);
|
||||
if (err == 0){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define MAX_WAIT 100
|
||||
#define DELAY_INTERVAL 10
|
||||
#define MAX_COUNTER (MAX_WAIT/DELAY_INTERVAL)
|
||||
|
||||
//Given a command, reads a given 2-byte value with CRC from the HTU21D
|
||||
uint16_t HTU21D::readValue(byte cmd)
|
||||
{
|
||||
//Request a humidity reading
|
||||
_i2cPort->beginTransmission(HTU21D_ADDRESS);
|
||||
_i2cPort->write(cmd); //Measure value (prefer no hold!)
|
||||
_i2cPort->endTransmission();
|
||||
|
||||
//Hang out while measurement is taken. datasheet says 50ms, practice may call for more
|
||||
bool validResult;
|
||||
byte counter;
|
||||
for (counter = 0, validResult = 0 ; counter < MAX_COUNTER && !validResult ; counter++)
|
||||
{
|
||||
delay(DELAY_INTERVAL);
|
||||
|
||||
//Comes back in three bytes, data(MSB) / data(LSB) / Checksum
|
||||
validResult = (3 == _i2cPort->requestFrom(HTU21D_ADDRESS, 3));
|
||||
}
|
||||
|
||||
if (!validResult) return (ERROR_I2C_TIMEOUT); //Error out
|
||||
|
||||
byte msb, lsb, checksum;
|
||||
msb = _i2cPort->read();
|
||||
lsb = _i2cPort->read();
|
||||
checksum = _i2cPort->read();
|
||||
|
||||
uint16_t rawValue = ((uint16_t) msb << 8) | (uint16_t) lsb;
|
||||
|
||||
if (checkCRC(rawValue, checksum) != 0) return (ERROR_BAD_CRC); //Error out
|
||||
|
||||
return rawValue & 0xFFFC; // Zero out the status bits
|
||||
}
|
||||
|
||||
//Read the humidity
|
||||
/*******************************************************************************************/
|
||||
//Calc humidity and return it to the user
|
||||
//Returns 998 if I2C timed out
|
||||
//Returns 999 if CRC is wrong
|
||||
float HTU21D::readHumidity(void)
|
||||
{
|
||||
uint16_t rawHumidity = readValue(TRIGGER_HUMD_MEASURE_NOHOLD);
|
||||
|
||||
if(rawHumidity == ERROR_I2C_TIMEOUT || rawHumidity == ERROR_BAD_CRC) return(rawHumidity);
|
||||
|
||||
//Given the raw humidity data, calculate the actual relative humidity
|
||||
float tempRH = rawHumidity * (125.0 / 65536.0); //2^16 = 65536
|
||||
float rh = tempRH - 6.0; //From page 14
|
||||
|
||||
return (rh);
|
||||
}
|
||||
|
||||
//Read the temperature
|
||||
/*******************************************************************************************/
|
||||
//Calc temperature and return it to the user
|
||||
//Returns 998 if I2C timed out
|
||||
//Returns 999 if CRC is wrong
|
||||
float HTU21D::readTemperature(void)
|
||||
{
|
||||
uint16_t rawTemperature = readValue(TRIGGER_TEMP_MEASURE_NOHOLD);
|
||||
|
||||
if(rawTemperature == ERROR_I2C_TIMEOUT || rawTemperature == ERROR_BAD_CRC) return(rawTemperature);
|
||||
|
||||
//Given the raw temperature data, calculate the actual temperature
|
||||
float tempTemperature = rawTemperature * (175.72 / 65536.0); //2^16 = 65536
|
||||
float realTemperature = tempTemperature - 46.85; //From page 14
|
||||
|
||||
return (realTemperature);
|
||||
}
|
||||
|
||||
//Set sensor resolution
|
||||
/*******************************************************************************************/
|
||||
//Sets the sensor resolution to one of four levels
|
||||
//Page 12:
|
||||
// 0/0 = 12bit RH, 14bit Temp
|
||||
// 0/1 = 8bit RH, 12bit Temp
|
||||
// 1/0 = 10bit RH, 13bit Temp
|
||||
// 1/1 = 11bit RH, 11bit Temp
|
||||
//Power on default is 0/0
|
||||
|
||||
void HTU21D::setResolution(byte resolution)
|
||||
{
|
||||
byte userRegister = readUserRegister(); //Go get the current register state
|
||||
userRegister &= B01111110; //Turn off the resolution bits
|
||||
resolution &= B10000001; //Turn off all other bits but resolution bits
|
||||
userRegister |= resolution; //Mask in the requested resolution bits
|
||||
|
||||
//Request a write to user register
|
||||
writeUserRegister(userRegister);
|
||||
}
|
||||
|
||||
//Read the user register
|
||||
byte HTU21D::readUserRegister(void)
|
||||
{
|
||||
byte userRegister;
|
||||
|
||||
//Request the user register
|
||||
_i2cPort->beginTransmission(HTU21D_ADDRESS);
|
||||
_i2cPort->write(READ_USER_REG); //Read the user register
|
||||
_i2cPort->endTransmission();
|
||||
|
||||
//Read result
|
||||
_i2cPort->requestFrom(HTU21D_ADDRESS, 1);
|
||||
|
||||
userRegister = _i2cPort->read();
|
||||
|
||||
return (userRegister);
|
||||
}
|
||||
|
||||
void HTU21D::writeUserRegister(byte val)
|
||||
{
|
||||
_i2cPort->beginTransmission(HTU21D_ADDRESS);
|
||||
_i2cPort->write(WRITE_USER_REG); //Write to the user register
|
||||
_i2cPort->write(val); //Write the new resolution bits
|
||||
_i2cPort->endTransmission();
|
||||
}
|
||||
|
||||
//Give this function the 2 byte message (measurement) and the check_value byte from the HTU21D
|
||||
//If it returns 0, then the transmission was good
|
||||
//If it returns something other than 0, then the communication was corrupted
|
||||
//From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html
|
||||
//POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks
|
||||
#define SHIFTED_DIVISOR 0x988000 //This is the 0x0131 polynomial shifted to farthest left of three bytes
|
||||
|
||||
byte HTU21D::checkCRC(uint16_t message_from_sensor, uint8_t check_value_from_sensor)
|
||||
{
|
||||
//Test cases from datasheet:
|
||||
//message = 0xDC, checkvalue is 0x79
|
||||
//message = 0x683A, checkvalue is 0x7C
|
||||
//message = 0x4E85, checkvalue is 0x6B
|
||||
|
||||
uint32_t remainder = (uint32_t)message_from_sensor << 8; //Pad with 8 bits because we have to add in the check value
|
||||
remainder |= check_value_from_sensor; //Add on the check value
|
||||
|
||||
uint32_t divsor = (uint32_t)SHIFTED_DIVISOR;
|
||||
|
||||
for (int i = 0 ; i < 16 ; i++) //Operate on only 16 positions of max 24. The remaining 8 are our remainder and should be zero when we're done.
|
||||
{
|
||||
//Serial.print("remainder: ");
|
||||
//Serial.println(remainder, BIN);
|
||||
//Serial.print("divsor: ");
|
||||
//Serial.println(divsor, BIN);
|
||||
//Serial.println();
|
||||
|
||||
if ( remainder & (uint32_t)1 << (23 - i) ) //Check if there is a one in the left position
|
||||
remainder ^= divsor;
|
||||
|
||||
divsor >>= 1; //Rotate the divsor max 16 times so that we have 8 bits left of a remainder
|
||||
}
|
||||
|
||||
return (byte)remainder;
|
||||
}
|
||||
72
src/SparkFunHTU21D.h
Normal file
72
src/SparkFunHTU21D.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
HTU21D Humidity Sensor Library
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: September 22nd, 2013
|
||||
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
|
||||
|
||||
Get humidity and temperature from the HTU21D sensor.
|
||||
|
||||
This same library should work for the other similar sensors including the Si
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#define HTU21D_ADDRESS 0x40 //Unshifted 7-bit I2C address for the sensor
|
||||
|
||||
#define ERROR_I2C_TIMEOUT 998
|
||||
#define ERROR_BAD_CRC 999
|
||||
|
||||
#define TRIGGER_TEMP_MEASURE_HOLD 0xE3
|
||||
#define TRIGGER_HUMD_MEASURE_HOLD 0xE5
|
||||
#define TRIGGER_TEMP_MEASURE_NOHOLD 0xF3
|
||||
#define TRIGGER_HUMD_MEASURE_NOHOLD 0xF5
|
||||
#define WRITE_USER_REG 0xE6
|
||||
#define READ_USER_REG 0xE7
|
||||
#define SOFT_RESET 0xFE
|
||||
|
||||
#define USER_REGISTER_RESOLUTION_MASK 0x81
|
||||
#define USER_REGISTER_RESOLUTION_RH12_TEMP14 0x00
|
||||
#define USER_REGISTER_RESOLUTION_RH8_TEMP12 0x01
|
||||
#define USER_REGISTER_RESOLUTION_RH10_TEMP13 0x80
|
||||
#define USER_REGISTER_RESOLUTION_RH11_TEMP11 0x81
|
||||
|
||||
#define USER_REGISTER_END_OF_BATTERY 0x40
|
||||
#define USER_REGISTER_HEATER_ENABLED 0x04
|
||||
#define USER_REGISTER_DISABLE_OTP_RELOAD 0x02
|
||||
|
||||
class HTU21D {
|
||||
|
||||
public:
|
||||
HTU21D();
|
||||
|
||||
//Public Functions
|
||||
bool begin(TwoWire &wirePort = Wire); //If user doesn't specificy then Wire will be used
|
||||
float readHumidity(void);
|
||||
float readTemperature(void);
|
||||
void setResolution(byte resBits);
|
||||
|
||||
byte readUserRegister(void);
|
||||
void writeUserRegister(byte val);
|
||||
|
||||
//Public Variables
|
||||
|
||||
private:
|
||||
//Private Functions
|
||||
TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware
|
||||
|
||||
byte checkCRC(uint16_t message_from_sensor, uint8_t check_value_from_sensor);
|
||||
uint16_t readValue(byte cmd);
|
||||
|
||||
//Private Variables
|
||||
|
||||
};
|
||||
Loading…
Reference in a new issue