From bf31806c9d7388d09872a0d6a56dca74ebf7c37b Mon Sep 17 00:00:00 2001 From: loraxipam Date: Mon, 13 May 2019 19:35:27 -0400 Subject: [PATCH 1/5] Additions for 3.1 --- LICENSE.txt | 25 ++ LPS.cpp | 354 +++++++++++++++++++++++++ LPS.h | 137 ++++++++++ README.md | 224 ++++++++++++++++ examples/OPCHelper/OPCHelper.ino | 61 +++++ examples/SerialMetric/SerialMetric.ino | 35 +++ examples/SerialUS/SerialUS.ino | 35 +++ keywords.txt | 79 ++++++ library.properties | 9 + 9 files changed, 959 insertions(+) create mode 100644 LICENSE.txt create mode 100644 LPS.cpp create mode 100644 LPS.h create mode 100644 README.md create mode 100644 examples/OPCHelper/OPCHelper.ino create mode 100644 examples/SerialMetric/SerialMetric.ino create mode 100644 examples/SerialUS/SerialUS.ino create mode 100644 keywords.txt create mode 100644 library.properties diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..9beb3da --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,25 @@ +Copyright (c) 2014 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. diff --git a/LPS.cpp b/LPS.cpp new file mode 100644 index 0000000..49c6c77 --- /dev/null +++ b/LPS.cpp @@ -0,0 +1,354 @@ +#include "LPS.h" +#include + +/* + * For a rigorously complete implementation of the LPS25HB, see ST's github + * version at https://github.com/stm32duino/LPS25HB + */ + +// 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_HIGH_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; + } + return false; +} + +// turns on sensor and enables 1Hz continuous output +// WARNING, this is absolute, intended for init section. +void LPS::enable1Hz(void) +{ + if (_device == device_25H || _device == device_331AP) + { + // 0x90 = 0b10010000 + // PD = 1 (active mode); ODR = 001b (1 Hz pressure & temperature output data rate) + writeReg(CTRL_REG1, 0x90); + } +} + + +// turns on sensor and enables continuous output at 12.5 Hz +// WARNING, this is absolute, intended for init section. +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); + } +} + +// sets the device to a specific FIFO mode +void LPS::enableFifo(fifoMode mode, bool decimate) { + if (_device == device_25H || _device == device_331AP){ + + // Set the correct FIFO_CTRL (2Eh) + byte fiforeg = readReg(FIFO_CTRL); + // The FIFO mode range is 3 bits wide at [7:5] + fiforeg &= ~(0b111 << 5); + fiforeg |= mode << 5; + writeReg(FIFO_CTRL, fiforeg); + + // enable the FIFO mode in CTRL_REG2 (21h). + byte ctrlreg = readReg(CTRL_REG2); + bitSet(ctrlreg, 6); + // You can also decimate the FIFO in 1Hz mode here if you raise bit 4. + // Be sure to set the ODR to 0b001 in CTRL_REG1:[6:4] if you do. See enable1Hz() above. + if (decimate) bitSet(ctrlreg, 4); + writeReg(CTRL_REG2, ctrlreg); + + } +} + +// 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.0; +} + +// 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.0; +} + +// reads temperature in degrees F +float LPS::readTemperatureF(void) +{ + return 108.5 + (float)readTemperatureRaw() / 480.0 * 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 standard 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.921 inHg +float LPS::pressureToAltitudeMeters(float pressure_mbar, float altimeter_setting_mbar) +{ + return (1.0 - 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.0 - pow(pressure_inHg / altimeter_setting_inHg, 0.190263)) * 145442.0; +} + +// Generic extension of the above two functions. +float LPS::pressureToAltitude(float pressure, float altimeter_setting, bool metric) +{ + const float factor = (metric ? 44330.8 : 145442.0); + return (1.0 - pow(pressure / altimeter_setting, 0.190263)) * factor; +} + +// Pressure (hPa), temp (C) and altitude (m), return sea level barometric pressure +// QFF is returned in millibars unless politely declined, in which case you get inHg +float LPS::altitudeToQFF(float altitude_meters, float tempC, bool please_return_mbars) { + const float factor = (please_return_mbars ? 1.0 : 33.864); + float pressure_mbar = LPS::readPressureMillibars(); + + float qff = pressure_mbar / + pow(((-0.0065 * altitude_meters) / + ( 0.0065 * altitude_meters + 273.15 + tempC)), 5.2559); + + return (qff / factor); +} + +/* + * Use this when you first get your device. Tell it your local info and it will help + * you see what your RPDS_L (0x39) and/or RPDS_H (0x3A) should be. Then you can use the + * above to report accurately your local true sea level barometric pressure (QFF). + */ +int16_t LPS::opcHelper(float my_local_qff_mbar, float my_local_altitude_meters) { + // real programmers would turn on BDU here, first. + int32_t currentRawPressure = LPS::readPressureRaw(); + byte rpds_low, rpds_high; + int16_t returnVal; + + rpds_low = readReg(LPS::RPDS_L); + rpds_high = readReg(LPS::RPDS_H); + + Serial.print("Your local pressure:\t\t"); + Serial.print(my_local_qff_mbar); + Serial.print(" mbar, which is "); + + Serial.print((int32_t)(my_local_qff_mbar * 4096.0)); + Serial.println(" int32_t"); + + Serial.print("Your local altitude:\t\t"); + Serial.print(my_local_altitude_meters); + Serial.println(" m"); + + Serial.println("According to the current device state, your local QFF should be:"); + Serial.println(LPS::altitudeToQFF(my_local_altitude_meters)); + + Serial.print("Sensor raw pressure:\t\t"); + Serial.print(currentRawPressure); + Serial.println(" int32_t"); + + Serial.print("Sensor millibars:\t\t"); + Serial.print((float)currentRawPressure / 4096.0); + Serial.println(" mbar"); + + Serial.print("Current RPDS_L:\t\t"); + Serial.print(rpds_low, BIN); + Serial.println(" binary"); + Serial.print("Current RPDS_H:\t\t"); + Serial.print(rpds_high, BIN); + Serial.println(" binary"); + + returnVal = (currentRawPressure - (int32_t)(my_local_qff_mbar * 4096.0)); + + Serial.print("Raw - local:\t\t"); + Serial.print(returnVal); + Serial.println(" int16_t"); + Serial.print("High byte:\t\t"); + Serial.print(highByte(returnVal), BIN); + Serial.print("\tLow byte: "); + Serial.println(lowByte(returnVal), BIN); + + return returnVal; + +} + +// 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; +} diff --git a/LPS.h b/LPS.h new file mode 100644 index 0000000..df5f26d --- /dev/null +++ b/LPS.h @@ -0,0 +1,137 @@ +#ifndef LPS_h +#define LPS_h + +#include // for byte data type + +class LPS +{ + public: + enum deviceType { device_331AP, device_25H, device_25HB = device_25H, device_auto }; + enum sa0State { sa0_low, sa0_high, sa0_auto }; + + /// Size of the hardware moving average depth, from 2 to 32 samples + enum fifoMeanModeSize { + SAMPLES_1 = 0b00001, // 2 + SAMPLES_2 = 0b00011, // 4 + SAMPLES_3 = 0b00111, // 8 + SAMPLES_4 = 0b01111, // 16 + SAMPLES_5 = 0b11111 // 32 + }; + + enum fifoMode { + BYPASS, + FIFO, + STREAM, + STREAM2FIFO, + BYPASS2STREAM, + FIFOMEAN = 0b110, + BYPASS2FIFO + }; + + // 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 enable1Hz(void); + + void enableFifo(fifoMode mode, bool decimate = false); + + 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); + static float pressureToAltitude(float pressure, float altimeter_setting, bool metric = true); + + float altitudeToQFF(float altitude_meters, float tempC = 15.0, bool please_return_mbars = true); + + int16_t opcHelper(float my_local_qff_mbar, float my_local_altitude_meters); + + 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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..2e7624d --- /dev/null +++ b/README.md @@ -0,0 +1,224 @@ +# Arduino library for Pololu LPS pressure sensor boards + +Version: 3.1.0
+Release date: 2019-05-11
+[![Build Status](https://travis-ci.org/pololu/lps-arduino.svg?branch=master)](https://travis-ci.org/pololu/lps-arduino)
+[www.pololu.com](https://www.pololu.com/) + + +## Summary + +This is a library for an +[Arduino-compatible controller](https://www.pololu.com/arduino) that +interfaces with ST LPS25H/B and LPS331AP pressure sensors on Pololu +boards. The library makes it simple to read the raw pressure data from +these boards: + +* [Pololu LPS25HB pressure/altitude sensor carrier](https://www.pololu.com/catalog/product/2867) +* [Pololu LPS25H pressure/altitude sensor carrier](https://www.pololu.com/catalog/product/2724) (deprecated) +* [Pololu LPS331AP pressure/altitude sensor carrier](https://www.pololu.com/catalog/product/2126) (deprecated) +* [AltIMU-10 v5 (LSM6DS33, LIS3MDL, and LPS25H carrier)](https://www.pololu.com/catalog/product/2739) +* [AltIMU-10 v4 (L3GD20H, LSM303D, and LPS25H carrier)](https://www.pololu.com/catalog/product/2468) (deprecated) +* [AltIMU-10 v3 (L3GD20H, LSM303D, and LSM331AP carrier)](https://www.pololu.com/catalog/product/2469) (deprecated) +* [AltIMU-10 (L3GD20, LSM303DLHC, and LSM331AP carrier)](https://www.pololu.com/catalog/product/1269) (discontinued) + +The library also provides functions to help calculate altitude based +on the measured pressure. + +## Getting started + +### Hardware + +A LPS carrier can be purchased from Pololu's website. Before +continuing, careful reading of the product page as well as the chip +datasheet is recommended. + +Make the following connections with wires between the Arduino and the +LPS board: + +#### 5V Arduino boards + +(including Arduino Uno, Leonardo, Mega; Pololu A-Star 32U4) + + Arduino LPS board + ------- --------- + 5V - VIN + GND - GND + SDA - SDA + SCL - SCL + +#### 3.3V Arduino boards + +(including Arduino Due) + + Arduino LPS board + ------- --------- + 3V3 - VIN + GND - GND + SDA - SDA + SCL - SCL + +### Software + +If you are using version 1.6.2 or later of the +[Arduino software (IDE)](https://www.arduino.cc/en/Main/Software), you can use +the Library Manager to install this library: + +1. In the Arduino IDE, open the "Sketch" menu, select "Include Library", then + "Manage Libraries...". +2. Search for "LPS". +3. Click the LPS entry in the list. +4. Click "Install". + +If this does not work, you can manually install the library: + +1. Download the + [latest release archive from GitHub](https://github.com/pololu/lps-arduino/releases) + and decompress it. +2. Rename the folder "lps-arduino-xxxx" to "LPS". +3. Drag the "LPS" folder into the "libraries" directory inside your + Arduino sketchbook directory. You can view your sketchbook location by + opening the "File" menu and selecting "Preferences" in the Arduino IDE. If + there is not already a "libraries" folder in that location, you should make + the folder yourself. +4. After installing the library, restart the Arduino IDE. + +## Examples + +Several example sketches are available that show how to use the +library. You can access them from the Arduino IDE by opening the +"File" menu, selecting "Examples", and then selecting "LPS". If +you cannot find these examples, the library was probably installed +incorrectly and you should retry the installation instructions above. + +### SerialMetric + +This program continuously takes pressure and temperature readings from +the sensor and calculates an altitude from the pressure. It shows the +data in metric units: pressure in millibars (mbar) (which are +equivalent to hectopascals (hPa)), altitude in meters, and temperature +in degrees Celsius. The program's output is sent over the serial +interface, and you can display it with the Arduino Serial Monitor. + +Example output: + + p: 931.93 mbar a: 700.02 m t: 29.92 deg C + p: 931.85 mbar a: 700.73 m t: 29.92 deg C + p: 931.75 mbar a: 701.68 m t: 29.89 deg C + +### SerialUS + +This program is the same as SerialMetric, except that it shows the +data in United States customary units: pressure in inches of mercury +(inHg), altitude in feet, and temperature in degrees Fahrenheit. + +Example output: + + p: 27.52 inHg a: 2296.55 ft t: 83.19 deg F + p: 27.52 inHg a: 2295.50 ft t: 83.18 deg F + p: 27.52 inHg a: 2296.42 ft t: 83.17 deg F + + +### OPCHelper + +This program helps to determine what the RPDS registers should be after you have +soldered it. It helps to have some idea what the values should be instead of +hunting and pecking with trial and error. This may help for you to zero in on a +value much more quickly. + +Example output: + + Pololu LPS OPC Helper + Your local pressure: 1016.40 mbar, which is 4163174 int32_t + Your local altitude: 419.70 m + According to the current device state, your local QFF should be: + + Sensor raw pressure: 4153535 int32_t + Sensor millibars: 1014.05 mbar + Current RPDS_L: 1010001 binary + Current RPDS_H: 0 binary + +## Library reference + +- `bool init(deviceType device, byte sa0)`
Initializes the + library with the device being used (`LPS::device_331AP`, + `LPS::device_25H`, or `LPS::device_auto`) and the state of the SA0 + pin (`LPS::sa0_low`, `LPS::sa0_high`, or `LPS::sa0_auto`; `LOW` or + `HIGH` also work), which determines the least significant bit of the + sensor's address. Both of these arguments are optional; if they are + not specified, the library will try to automatically detect the + device and address. The return value is a boolean indicating whether + a device was successfully detected. +- `deviceType getDeviceType(void)`
Returns the device type + detected by `init()`. +- `byte getAddress(void)`
Returns the address detected by + `init()`. +- `void enableDefault(void)`
Turns on the pressure sensor in a + default configuration that gives continuous output at 12.5 Hz. +- `void enable1Hz(void)`
Turns on the pressure sensor in a + default configuration that gives continuous output at 1Hz. +- `void enableFifo(fifoMode mode)`
Enables the hardware FIFO + for the given mode. +- `void writeReg(int reg, byte value)`
Writes a pressure sensor + register with the given value. Register addresses are defined by the + regAddr enumeration type in LPS.h. Example use: + `ps.writeReg(LPS::CTRL_REG1, 0xE0);` +- `byte readReg(int reg)`
Reads a pressure sensor register and + returns the value read. +- `float readPressureMillibars(void)`
Returns a pressure reading + from the sensor in units of millibars (mbar)/hectopascals (hPa). +- `float readPressureInchesHg(void)`
Returns a pressure reading + from the sensor in units of inches of mercury (inHg). +- `long readPressureRaw(void)`
Returns a raw 24-bit pressure + reading from the sensor. +- `float readTemperatureC(void)`
Returns a temperature reading + from the sensor in units of degrees Celsius. +- `float readTemperatureF(void)`
Returns a temperature reading + from the sensor in units of degrees Fahrenheit. +- `int readTemperatureRaw(void)`
Returns a raw 16-bit temperature + reading from the sensor. +- `float pressureToAltitudeMeters(float pressure_mbar, float + altimeter_setting_mbar)`
Converts a pressure in mbar to an + altitude in meters, using the 1976 + [U.S. Standard Atmosphere](https://en.wikipedia.org/wiki/U.S._Standard_Atmosphere) + model (note that this formula only applies up to an altitude of 11 + km, or about 36000 ft). If the optional `altimeter_setting_mbar` + argument is given, specifying an "altimeter setting" or "QNH" + (barometric pressure adjusted to sea level, often used in aviation + and obtained from a local weather monitoring station), this function + returns an indicated altitude compensated for the actual regional + pressure. Otherwise, it returns a pressure altitude above the + standard pressure level of 1013.25 mbar (29.9213 inHg). +- `float pressureToAltitudeFeet(float pressure_inHg, float + altimeter_setting_inHg)`
Converts a pressure in inHg to an + altitude in feet. See the preceding description of + `pressureToAltitudeMeters()` for details. +- `float pressureToAltitude(float pressure, float altimeter_setting, bool metric)`
+ Converts a pressure to an altitude. A generic version of the above two functions. Metric pressure and altimeter are expected to be mbars and + meters. Otherwise inHg and feet, respectively. +- `float altitudeToQFF(float altitude_meters, float tempC, bool return_mbars)`
+ Useful for reporting sea level pressure assuming you know the altitude of your + sensor. Once your device is calibrated, you can use this to report local pressure. +- `int16_t opcHelper(float my_local_qff_mbar, float my_local_altitude_meters)`
+ Useful for calibrating the device so you can assign RPDS registers to correct for + changes to pressure value reporting from the device due to soldering. + + +## Version history + +* 3.1.0 (2018-05-07): Added helper functions and variables + * Enums for FIFO modes + * Enable FIFO function + * Altitude to sea level pressure function + * OPC helper to determine post-solder offsets +* 3.0.0 (2016-08-17): Updated library to work with the Arduino Library Manager. +* 2.0.0 (2014-06-03): Major rewrite. List of significant changes: + * Renamed library to LPS. + * Added support for LPS25H and automatic detection of device type. + * Library constants converted to enums. +* 1.0.1 (2014-01-08): Changed raw output byte combination logic to work properly on 32-bit microcontrollers and be more portable. +* 1.0.0 (2013-03-22): Original release of LPS331 library. + + +_For a rigorously complete implementation of the LPS25HB, ST's :octocat: github +version at https://github.com/stm32duino/LPS25HB provides interfaces for almost every function on the chip._ diff --git a/examples/OPCHelper/OPCHelper.ino b/examples/OPCHelper/OPCHelper.ino new file mode 100644 index 0000000..4f7b857 --- /dev/null +++ b/examples/OPCHelper/OPCHelper.ino @@ -0,0 +1,61 @@ +#include +#include + +LPS ps; + +/*** + * So, you have a brand new LPS sensor and you have soldered on the pins. + * Now you need to see if it reports true pressure readings. I assume you + * know your true altitude. I assume, also, that you can find an accurate + * local pressure reading from nearby weather stations or extrapolating + * from your weather authority's isoline maps. Using those two "true" values + * and the pressure from the sensor, we should be able to show what you ought + * to use for setting the RPDS registers. + + * Why do you want to set the RPDS registers? Glad you asked. + * If your sensor is not going to move in any vertical direction, say, it's + * stuck on a pole in your backyard, then it is easy to report your local + * "weather" pressure by adjusting those registers. Set those in your init + * section and then your pressure values will show your adjusted sea level + * pressure. + + * If you just want to report your actual air pressure, then just move along + * because this function may not be helpful. But you still ought to calibrate + * your unit to make sure that it's reporting accurately. +***/ + +/* Assign these two values from your current local references */ +static const float pressure = 1016.4; +static const float altitude = 419.7; + +bool delaying(int msdelay){ + delay(msdelay); + return true; +} + +void setup() +{ + Serial.begin(115200); + Wire.begin(); + + if (!ps.init()) + { + Serial.println("Failed to autodetect pressure sensor!"); + while (delaying(60)); + } + + Serial.println("Pololu LPS OPC Helper"); + + delay(100); + ps.enableDefault(); + + delay(100); + +} + +void loop() +{ + ps.opcHelper(pressure, altitude); + + delay(90000); +} diff --git a/examples/SerialMetric/SerialMetric.ino b/examples/SerialMetric/SerialMetric.ino new file mode 100644 index 0000000..d590e35 --- /dev/null +++ b/examples/SerialMetric/SerialMetric.ino @@ -0,0 +1,35 @@ +#include +#include + +LPS ps; + +void setup() +{ + Serial.begin(9600); + Wire.begin(); + + if (!ps.init()) + { + Serial.println("Failed to autodetect pressure sensor!"); + while (1); + } + + ps.enableDefault(); +} + +void loop() +{ + float pressure = ps.readPressureMillibars(); + float altitude = ps.pressureToAltitudeMeters(pressure); + float temperature = ps.readTemperatureC(); + + Serial.print("p: "); + Serial.print(pressure); + Serial.print(" mbar\ta: "); + Serial.print(altitude); + Serial.print(" m\tt: "); + Serial.print(temperature); + Serial.println(" deg C"); + + delay(100); +} diff --git a/examples/SerialUS/SerialUS.ino b/examples/SerialUS/SerialUS.ino new file mode 100644 index 0000000..1e6e93b --- /dev/null +++ b/examples/SerialUS/SerialUS.ino @@ -0,0 +1,35 @@ +#include +#include + +LPS ps; + +void setup() +{ + Serial.begin(9600); + Wire.begin(); + + if (!ps.init()) + { + Serial.println("Failed to autodetect pressure sensor!"); + while (1); + } + + ps.enableDefault(); +} + +void loop() +{ + float pressure = ps.readPressureInchesHg(); + float altitude = ps.pressureToAltitudeFeet(pressure); + float temperature = ps.readTemperatureF(); + + Serial.print("p: "); + Serial.print(pressure); + Serial.print(" inHg\ta: "); + Serial.print(altitude); + Serial.print(" ft\tt: "); + Serial.print(temperature); + Serial.println(" deg F"); + + delay(100); +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..6afc4e4 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,79 @@ +LPS KEYWORD1 + +init KEYWORD2 +getDeviceType KEYWORD2 +getAddress KEYWORD2 +enableDefault KEYWORD2 +enable1Hz KEYWORD2 +enableFifo KEYWORD2 +writeReg KEYWORD2 +readReg KEYWORD2 +readPressureMillibars KEYWORD2 +readPressureInchesHg KEYWORD2 +readPressureRaw KEYWORD2 +readTemperatureC KEYWORD2 +readTemperatureF KEYWORD2 +readTemperatureRaw KEYWORD2 +pressureToAltitudeMeters KEYWORD2 +pressureToAltitudeFeet KEYWORD2 +pressureToAltitude KEYWORD2 +altitudeToQFF KEYWORD2 +opcHelper KEYWORD2 + +device_331AP LITERAL1 +device_25H LITERAL1 +device_25HB LITERAL1 +device_auto LITERAL1 +sa0_low LITERAL1 +sa0_high LITERAL1 +sa0_auto LITERAL1 +SA0_LOW LITERAL1 +SA0_HIGH LITERAL1 +SA0_AUTO LITERAL1 +SAMPLES_1 LITERAL1 +SAMPLES_2 LITERAL1 +SAMPLES_3 LITERAL1 +SAMPLES_4 LITERAL1 +SAMPLES_5 LITERAL1 +BYPASS LITERAL1 +FIFO LITERAL1 +STREAM LITERAL1 +STREAM2FIFO LITERAL1 +BYPASS2STREAM LITERAL1 +FIFOMEAN LITERAL1 +BYPASS2FIFO LITERAL1 +REF_P_XL LITERAL1 +REF_P_L LITERAL1 +REF_P_H LITERAL1 +WHO_AM_I LITERAL1 +RES_CONF LITERAL1 +CTRL_REG1 LITERAL1 +CTRL_REG2 LITERAL1 +CTRL_REG3 LITERAL1 +CTRL_REG4 LITERAL1 +STATUS_REG LITERAL1 +PRESS_OUT_XL LITERAL1 +PRESS_OUT_L LITERAL1 +PRESS_OUT_H LITERAL1 +TEMP_OUT_L LITERAL1 +TEMP_OUT_H LITERAL1 +FIFO_CTRL LITERAL1 +FIFO_STATUS LITERAL1 +AMP_CTRL LITERAL1 +RPDS_L LITERAL1 +RPDS_H LITERAL1 +DELTA_PRESS_XL LITERAL1 +DELTA_PRESS_L LITERAL1 +DELTA_PRESS_H LITERAL1 +INTERRUPT_CFG LITERAL1 +INT_SOURCE LITERAL1 +THS_P_L LITERAL1 +THS_P_H LITERAL1 +LPS331AP_INTERRUPT_CFG LITERAL1 +LPS331AP_INT_SOURCE LITERAL1 +LPS331AP_THS_P_L LITERAL1 +LPS331AP_THS_P_H LITERAL1 +LPS25H_INTERRUPT_CFG LITERAL1 +LPS25H_INT_SOURCE LITERAL1 +LPS25H_THS_P_L LITERAL1 +LPS25H_THS_P_H LITERAL1 diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..877264f --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=LPS +version=3.1.0 +author=Pololu +maintainer=Pololu +sentence=Arduino library for Pololu LPS25H/B and LPS331AP boards +paragraph=This is a library for an Arduino-compatible controller that interfaces with ST LPS25H and LPS331AP pressure sensors on Pololu boards. +category=Sensors +url=https://github.com/pololu/lps-arduino +architectures=* From 07476fbe839b044127ec76e0ec1f0d520f74111b Mon Sep 17 00:00:00 2001 From: loraxipam Date: Mon, 13 May 2019 20:13:44 -0400 Subject: [PATCH 2/5] Commit for 3.1.0 --- LPS.cpp | 149 +++++++++++++++++++++++++++---- LPS.h | 65 ++++++++++---- README.md | 59 ++++++++++-- examples/OPCHelper/OPCHelper.ino | 61 +++++++++++++ keywords.txt | 20 ++++- library.properties | 6 +- 6 files changed, 314 insertions(+), 46 deletions(-) create mode 100644 examples/OPCHelper/OPCHelper.ino diff --git a/LPS.cpp b/LPS.cpp index 42041a9..49c6c77 100644 --- a/LPS.cpp +++ b/LPS.cpp @@ -1,6 +1,11 @@ -#include +#include "LPS.h" #include +/* + * For a rigorously complete implementation of the LPS25HB, see ST's github + * version at https://github.com/stm32duino/LPS25HB + */ + // Defines /////////////////////////////////////////////////////////// // The Arduino two-wire interface uses a 7-bit number for the address, @@ -18,7 +23,7 @@ LPS::LPS(void) { _device = device_auto; - + // Pololu board pulls SA0 high, so default assumption is that it is // high address = SA0_HIGH_ADDRESS; @@ -31,7 +36,7 @@ bool LPS::init(deviceType device, byte sa0) { if (!detectDeviceAndAddress(device, (sa0State)sa0)) return false; - + switch (_device) { case device_25H: @@ -41,7 +46,7 @@ bool LPS::init(deviceType device, byte sa0) 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; @@ -50,9 +55,24 @@ bool LPS::init(deviceType device, byte sa0) return true; break; } + return false; +} + +// turns on sensor and enables 1Hz continuous output +// WARNING, this is absolute, intended for init section. +void LPS::enable1Hz(void) +{ + if (_device == device_25H || _device == device_331AP) + { + // 0x90 = 0b10010000 + // PD = 1 (active mode); ODR = 001b (1 Hz pressure & temperature output data rate) + writeReg(CTRL_REG1, 0x90); + } } -// turns on sensor and enables continuous output + +// turns on sensor and enables continuous output at 12.5 Hz +// WARNING, this is absolute, intended for init section. void LPS::enableDefault(void) { if (_device == device_25H) @@ -69,6 +89,28 @@ void LPS::enableDefault(void) } } +// sets the device to a specific FIFO mode +void LPS::enableFifo(fifoMode mode, bool decimate) { + if (_device == device_25H || _device == device_331AP){ + + // Set the correct FIFO_CTRL (2Eh) + byte fiforeg = readReg(FIFO_CTRL); + // The FIFO mode range is 3 bits wide at [7:5] + fiforeg &= ~(0b111 << 5); + fiforeg |= mode << 5; + writeReg(FIFO_CTRL, fiforeg); + + // enable the FIFO mode in CTRL_REG2 (21h). + byte ctrlreg = readReg(CTRL_REG2); + bitSet(ctrlreg, 6); + // You can also decimate the FIFO in 1Hz mode here if you raise bit 4. + // Be sure to set the ODR to 0b001 in CTRL_REG1:[6:4] if you do. See enable1Hz() above. + if (decimate) bitSet(ctrlreg, 4); + writeReg(CTRL_REG2, ctrlreg); + + } +} + // writes register void LPS::writeReg(int reg, byte value) { @@ -88,7 +130,7 @@ void LPS::writeReg(int reg, byte value) byte LPS::readReg(int reg) { byte value; - + // if dummy register address, look up actual translated address (based on device type) if (reg < 0) { @@ -108,7 +150,7 @@ byte LPS::readReg(int reg) // reads pressure in millibars (mbar)/hectopascals (hPa) float LPS::readPressureMillibars(void) { - return (float)readPressureRaw() / 4096; + return (float)readPressureRaw() / 4096.0; } // reads pressure in inches of mercury (inHg) @@ -139,13 +181,13 @@ int32_t LPS::readPressureRaw(void) // reads temperature in degrees C float LPS::readTemperatureC(void) { - return 42.5 + (float)readTemperatureRaw() / 480; + return 42.5 + (float)readTemperatureRaw() / 480.0; } // reads temperature in degrees F float LPS::readTemperatureF(void) { - return 108.5 + (float)readTemperatureRaw() / 480 * 1.8; + return 108.5 + (float)readTemperatureRaw() / 480.0 * 1.8; } // reads temperature and returns raw 16-bit sensor output @@ -169,20 +211,97 @@ int16_t LPS::readTemperatureRaw(void) // 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 +// If altimeter setting (QNH, barometric pressure adjusted to standard 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 +// mbar or 29.921 inHg float LPS::pressureToAltitudeMeters(float pressure_mbar, float altimeter_setting_mbar) { - return (1 - pow(pressure_mbar / altimeter_setting_mbar, 0.190263)) * 44330.8; + return (1.0 - 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; + return (1.0 - pow(pressure_inHg / altimeter_setting_inHg, 0.190263)) * 145442.0; +} + +// Generic extension of the above two functions. +float LPS::pressureToAltitude(float pressure, float altimeter_setting, bool metric) +{ + const float factor = (metric ? 44330.8 : 145442.0); + return (1.0 - pow(pressure / altimeter_setting, 0.190263)) * factor; +} + +// Pressure (hPa), temp (C) and altitude (m), return sea level barometric pressure +// QFF is returned in millibars unless politely declined, in which case you get inHg +float LPS::altitudeToQFF(float altitude_meters, float tempC, bool please_return_mbars) { + const float factor = (please_return_mbars ? 1.0 : 33.864); + float pressure_mbar = LPS::readPressureMillibars(); + + float qff = pressure_mbar / + pow(((-0.0065 * altitude_meters) / + ( 0.0065 * altitude_meters + 273.15 + tempC)), 5.2559); + + return (qff / factor); +} + +/* + * Use this when you first get your device. Tell it your local info and it will help + * you see what your RPDS_L (0x39) and/or RPDS_H (0x3A) should be. Then you can use the + * above to report accurately your local true sea level barometric pressure (QFF). + */ +int16_t LPS::opcHelper(float my_local_qff_mbar, float my_local_altitude_meters) { + // real programmers would turn on BDU here, first. + int32_t currentRawPressure = LPS::readPressureRaw(); + byte rpds_low, rpds_high; + int16_t returnVal; + + rpds_low = readReg(LPS::RPDS_L); + rpds_high = readReg(LPS::RPDS_H); + + Serial.print("Your local pressure:\t\t"); + Serial.print(my_local_qff_mbar); + Serial.print(" mbar, which is "); + + Serial.print((int32_t)(my_local_qff_mbar * 4096.0)); + Serial.println(" int32_t"); + + Serial.print("Your local altitude:\t\t"); + Serial.print(my_local_altitude_meters); + Serial.println(" m"); + + Serial.println("According to the current device state, your local QFF should be:"); + Serial.println(LPS::altitudeToQFF(my_local_altitude_meters)); + + Serial.print("Sensor raw pressure:\t\t"); + Serial.print(currentRawPressure); + Serial.println(" int32_t"); + + Serial.print("Sensor millibars:\t\t"); + Serial.print((float)currentRawPressure / 4096.0); + Serial.println(" mbar"); + + Serial.print("Current RPDS_L:\t\t"); + Serial.print(rpds_low, BIN); + Serial.println(" binary"); + Serial.print("Current RPDS_H:\t\t"); + Serial.print(rpds_high, BIN); + Serial.println(" binary"); + + returnVal = (currentRawPressure - (int32_t)(my_local_qff_mbar * 4096.0)); + + Serial.print("Raw - local:\t\t"); + Serial.print(returnVal); + Serial.println(" int16_t"); + Serial.print("High byte:\t\t"); + Serial.print(highByte(returnVal), BIN); + Serial.print("\tLow byte: "); + Serial.println(lowByte(returnVal), BIN); + + return returnVal; + } // Private Methods /////////////////////////////////////////////////// @@ -206,7 +325,7 @@ bool LPS::detectDeviceAndAddress(deviceType device, sa0State sa0) bool LPS::detectDevice(deviceType device) { int id = testWhoAmI(address); - + if ((device == device_auto || device == device_25H) && id == LPS25H_WHO_ID) { _device = device_25H; @@ -232,4 +351,4 @@ int LPS::testWhoAmI(byte address) return Wire.read(); else return TEST_REG_NACK; -} \ No newline at end of file +} diff --git a/LPS.h b/LPS.h index 63143cc..df5f26d 100644 --- a/LPS.h +++ b/LPS.h @@ -6,9 +6,28 @@ class LPS { public: - enum deviceType { device_331AP, device_25H, device_auto }; + enum deviceType { device_331AP, device_25H, device_25HB = device_25H, device_auto }; enum sa0State { sa0_low, sa0_high, sa0_auto }; + /// Size of the hardware moving average depth, from 2 to 32 samples + enum fifoMeanModeSize { + SAMPLES_1 = 0b00001, // 2 + SAMPLES_2 = 0b00011, // 4 + SAMPLES_3 = 0b00111, // 8 + SAMPLES_4 = 0b01111, // 16 + SAMPLES_5 = 0b11111 // 32 + }; + + enum fifoMode { + BYPASS, + FIFO, + STREAM, + STREAM2FIFO, + BYPASS2STREAM, + FIFOMEAN = 0b110, + BYPASS2FIFO + }; + // register addresses // Note: where register names differ between the register mapping table and // the register descriptions in the datasheets, the names from the register @@ -18,56 +37,56 @@ class LPS 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, @@ -81,6 +100,9 @@ class LPS byte getAddress(void) { return address; } void enableDefault(void); + void enable1Hz(void); + + void enableFifo(fifoMode mode, bool decimate = false); void writeReg(int reg, byte value); byte readReg(int reg); @@ -94,11 +116,16 @@ class LPS static float pressureToAltitudeMeters(float pressure_mbar, float altimeter_setting_mbar = 1013.25); static float pressureToAltitudeFeet(float pressure_inHg, float altimeter_setting_inHg = 29.9213); + static float pressureToAltitude(float pressure, float altimeter_setting, bool metric = true); + + float altitudeToQFF(float altitude_meters, float tempC = 15.0, bool please_return_mbars = true); + + int16_t opcHelper(float my_local_qff_mbar, float my_local_altitude_meters); 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 @@ -107,4 +134,4 @@ class LPS int testWhoAmI(byte address); }; -#endif \ No newline at end of file +#endif diff --git a/README.md b/README.md index caea344..2e7624d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Arduino library for Pololu LPS pressure sensor boards -Version: 3.0.0
-Release date: 2016-08-17
+Version: 3.1.0
+Release date: 2019-05-11
[![Build Status](https://travis-ci.org/pololu/lps-arduino.svg?branch=master)](https://travis-ci.org/pololu/lps-arduino)
[www.pololu.com](https://www.pololu.com/) @@ -10,19 +10,21 @@ Release date: 2016-08-17
This is a library for an [Arduino-compatible controller](https://www.pololu.com/arduino) that -interfaces with ST LPS25H and LPS331AP pressure sensors on Pololu +interfaces with ST LPS25H/B and LPS331AP pressure sensors on Pololu boards. The library makes it simple to read the raw pressure data from these boards: -* [Pololu LPS25H pressure/altitude sensor carrier](https://www.pololu.com/catalog/product/2724) -* [Pololu LPS331AP pressure/altitude sensor carrier](https://www.pololu.com/catalog/product/2126) -* [AltIMU-10 v3 (L3GD20H, LSM303D, and LSM331AP carrier)](https://www.pololu.com/catalog/product/2469) +* [Pololu LPS25HB pressure/altitude sensor carrier](https://www.pololu.com/catalog/product/2867) +* [Pololu LPS25H pressure/altitude sensor carrier](https://www.pololu.com/catalog/product/2724) (deprecated) +* [Pololu LPS331AP pressure/altitude sensor carrier](https://www.pololu.com/catalog/product/2126) (deprecated) +* [AltIMU-10 v5 (LSM6DS33, LIS3MDL, and LPS25H carrier)](https://www.pololu.com/catalog/product/2739) +* [AltIMU-10 v4 (L3GD20H, LSM303D, and LPS25H carrier)](https://www.pololu.com/catalog/product/2468) (deprecated) +* [AltIMU-10 v3 (L3GD20H, LSM303D, and LSM331AP carrier)](https://www.pololu.com/catalog/product/2469) (deprecated) * [AltIMU-10 (L3GD20, LSM303DLHC, and LSM331AP carrier)](https://www.pololu.com/catalog/product/1269) (discontinued) The library also provides functions to help calculate altitude based on the measured pressure. - ## Getting started ### Hardware @@ -117,6 +119,25 @@ Example output: p: 27.52 inHg a: 2296.42 ft t: 83.17 deg F +### OPCHelper + +This program helps to determine what the RPDS registers should be after you have +soldered it. It helps to have some idea what the values should be instead of +hunting and pecking with trial and error. This may help for you to zero in on a +value much more quickly. + +Example output: + + Pololu LPS OPC Helper + Your local pressure: 1016.40 mbar, which is 4163174 int32_t + Your local altitude: 419.70 m + According to the current device state, your local QFF should be: + + Sensor raw pressure: 4153535 int32_t + Sensor millibars: 1014.05 mbar + Current RPDS_L: 1010001 binary + Current RPDS_H: 0 binary + ## Library reference - `bool init(deviceType device, byte sa0)`
Initializes the @@ -133,7 +154,11 @@ Example output: - `byte getAddress(void)`
Returns the address detected by `init()`. - `void enableDefault(void)`
Turns on the pressure sensor in a - default configuration that gives continous output at 12.5 Hz. + default configuration that gives continuous output at 12.5 Hz. +- `void enable1Hz(void)`
Turns on the pressure sensor in a + default configuration that gives continuous output at 1Hz. +- `void enableFifo(fifoMode mode)`
Enables the hardware FIFO + for the given mode. - `void writeReg(int reg, byte value)`
Writes a pressure sensor register with the given value. Register addresses are defined by the regAddr enumeration type in LPS.h. Example use: @@ -168,10 +193,24 @@ Example output: altimeter_setting_inHg)`
Converts a pressure in inHg to an altitude in feet. See the preceding description of `pressureToAltitudeMeters()` for details. +- `float pressureToAltitude(float pressure, float altimeter_setting, bool metric)`
+ Converts a pressure to an altitude. A generic version of the above two functions. Metric pressure and altimeter are expected to be mbars and + meters. Otherwise inHg and feet, respectively. +- `float altitudeToQFF(float altitude_meters, float tempC, bool return_mbars)`
+ Useful for reporting sea level pressure assuming you know the altitude of your + sensor. Once your device is calibrated, you can use this to report local pressure. +- `int16_t opcHelper(float my_local_qff_mbar, float my_local_altitude_meters)`
+ Useful for calibrating the device so you can assign RPDS registers to correct for + changes to pressure value reporting from the device due to soldering. ## Version history +* 3.1.0 (2018-05-07): Added helper functions and variables + * Enums for FIFO modes + * Enable FIFO function + * Altitude to sea level pressure function + * OPC helper to determine post-solder offsets * 3.0.0 (2016-08-17): Updated library to work with the Arduino Library Manager. * 2.0.0 (2014-06-03): Major rewrite. List of significant changes: * Renamed library to LPS. @@ -179,3 +218,7 @@ Example output: * Library constants converted to enums. * 1.0.1 (2014-01-08): Changed raw output byte combination logic to work properly on 32-bit microcontrollers and be more portable. * 1.0.0 (2013-03-22): Original release of LPS331 library. + + +_For a rigorously complete implementation of the LPS25HB, ST's :octocat: github +version at https://github.com/stm32duino/LPS25HB provides interfaces for almost every function on the chip._ diff --git a/examples/OPCHelper/OPCHelper.ino b/examples/OPCHelper/OPCHelper.ino new file mode 100644 index 0000000..4f7b857 --- /dev/null +++ b/examples/OPCHelper/OPCHelper.ino @@ -0,0 +1,61 @@ +#include +#include + +LPS ps; + +/*** + * So, you have a brand new LPS sensor and you have soldered on the pins. + * Now you need to see if it reports true pressure readings. I assume you + * know your true altitude. I assume, also, that you can find an accurate + * local pressure reading from nearby weather stations or extrapolating + * from your weather authority's isoline maps. Using those two "true" values + * and the pressure from the sensor, we should be able to show what you ought + * to use for setting the RPDS registers. + + * Why do you want to set the RPDS registers? Glad you asked. + * If your sensor is not going to move in any vertical direction, say, it's + * stuck on a pole in your backyard, then it is easy to report your local + * "weather" pressure by adjusting those registers. Set those in your init + * section and then your pressure values will show your adjusted sea level + * pressure. + + * If you just want to report your actual air pressure, then just move along + * because this function may not be helpful. But you still ought to calibrate + * your unit to make sure that it's reporting accurately. +***/ + +/* Assign these two values from your current local references */ +static const float pressure = 1016.4; +static const float altitude = 419.7; + +bool delaying(int msdelay){ + delay(msdelay); + return true; +} + +void setup() +{ + Serial.begin(115200); + Wire.begin(); + + if (!ps.init()) + { + Serial.println("Failed to autodetect pressure sensor!"); + while (delaying(60)); + } + + Serial.println("Pololu LPS OPC Helper"); + + delay(100); + ps.enableDefault(); + + delay(100); + +} + +void loop() +{ + ps.opcHelper(pressure, altitude); + + delay(90000); +} diff --git a/keywords.txt b/keywords.txt index 96eb300..6afc4e4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -4,6 +4,8 @@ init KEYWORD2 getDeviceType KEYWORD2 getAddress KEYWORD2 enableDefault KEYWORD2 +enable1Hz KEYWORD2 +enableFifo KEYWORD2 writeReg KEYWORD2 readReg KEYWORD2 readPressureMillibars KEYWORD2 @@ -14,9 +16,13 @@ readTemperatureF KEYWORD2 readTemperatureRaw KEYWORD2 pressureToAltitudeMeters KEYWORD2 pressureToAltitudeFeet KEYWORD2 +pressureToAltitude KEYWORD2 +altitudeToQFF KEYWORD2 +opcHelper KEYWORD2 device_331AP LITERAL1 device_25H LITERAL1 +device_25HB LITERAL1 device_auto LITERAL1 sa0_low LITERAL1 sa0_high LITERAL1 @@ -24,6 +30,18 @@ sa0_auto LITERAL1 SA0_LOW LITERAL1 SA0_HIGH LITERAL1 SA0_AUTO LITERAL1 +SAMPLES_1 LITERAL1 +SAMPLES_2 LITERAL1 +SAMPLES_3 LITERAL1 +SAMPLES_4 LITERAL1 +SAMPLES_5 LITERAL1 +BYPASS LITERAL1 +FIFO LITERAL1 +STREAM LITERAL1 +STREAM2FIFO LITERAL1 +BYPASS2STREAM LITERAL1 +FIFOMEAN LITERAL1 +BYPASS2FIFO LITERAL1 REF_P_XL LITERAL1 REF_P_L LITERAL1 REF_P_H LITERAL1 @@ -58,4 +76,4 @@ LPS331AP_THS_P_H LITERAL1 LPS25H_INTERRUPT_CFG LITERAL1 LPS25H_INT_SOURCE LITERAL1 LPS25H_THS_P_L LITERAL1 -LPS25H_THS_P_H LITERAL1 \ No newline at end of file +LPS25H_THS_P_H LITERAL1 diff --git a/library.properties b/library.properties index 3d9e9e0..877264f 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=LPS -version=3.0.0 +version=3.1.0 author=Pololu maintainer=Pololu -sentence=Arduino library for Pololu LPS25H and LPS331AP boards +sentence=Arduino library for Pololu LPS25H/B and LPS331AP boards paragraph=This is a library for an Arduino-compatible controller that interfaces with ST LPS25H and LPS331AP pressure sensors on Pololu boards. category=Sensors url=https://github.com/pololu/lps-arduino -architectures=* \ No newline at end of file +architectures=* From 63511e0cc3b22db4daadfc47613494a4a23e8470 Mon Sep 17 00:00:00 2001 From: loraxipam Date: Mon, 13 May 2019 20:25:28 -0400 Subject: [PATCH 3/5] Removed diff --- LPS.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/LPS.cpp b/LPS.cpp index 49c6c77..8a0b688 100644 --- a/LPS.cpp +++ b/LPS.cpp @@ -292,14 +292,6 @@ int16_t LPS::opcHelper(float my_local_qff_mbar, float my_local_altitude_meters) returnVal = (currentRawPressure - (int32_t)(my_local_qff_mbar * 4096.0)); - Serial.print("Raw - local:\t\t"); - Serial.print(returnVal); - Serial.println(" int16_t"); - Serial.print("High byte:\t\t"); - Serial.print(highByte(returnVal), BIN); - Serial.print("\tLow byte: "); - Serial.println(lowByte(returnVal), BIN); - return returnVal; } From 87ae4fda2ac14afd8cbca9c51e37d9a473a1633b Mon Sep 17 00:00:00 2001 From: loraxipam Date: Mon, 13 May 2019 20:56:02 -0400 Subject: [PATCH 4/5] Fixed opcHelper return type --- LPS.cpp | 2 +- LPS.h | 2 +- README.md | 2 +- examples/OPCHelper/OPCHelper.ino | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LPS.cpp b/LPS.cpp index 8a0b688..2a2ce4e 100644 --- a/LPS.cpp +++ b/LPS.cpp @@ -252,7 +252,7 @@ float LPS::altitudeToQFF(float altitude_meters, float tempC, bool please_return_ * you see what your RPDS_L (0x39) and/or RPDS_H (0x3A) should be. Then you can use the * above to report accurately your local true sea level barometric pressure (QFF). */ -int16_t LPS::opcHelper(float my_local_qff_mbar, float my_local_altitude_meters) { +int32_t LPS::opcHelper(float my_local_qff_mbar, float my_local_altitude_meters) { // real programmers would turn on BDU here, first. int32_t currentRawPressure = LPS::readPressureRaw(); byte rpds_low, rpds_high; diff --git a/LPS.h b/LPS.h index df5f26d..c54812d 100644 --- a/LPS.h +++ b/LPS.h @@ -120,7 +120,7 @@ class LPS float altitudeToQFF(float altitude_meters, float tempC = 15.0, bool please_return_mbars = true); - int16_t opcHelper(float my_local_qff_mbar, float my_local_altitude_meters); + int32_t opcHelper(float my_local_qff_mbar, float my_local_altitude_meters); private: deviceType _device; // chip type (331AP or 25H) diff --git a/README.md b/README.md index 2e7624d..c0ae8f6 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,7 @@ Example output: - `float altitudeToQFF(float altitude_meters, float tempC, bool return_mbars)`
Useful for reporting sea level pressure assuming you know the altitude of your sensor. Once your device is calibrated, you can use this to report local pressure. -- `int16_t opcHelper(float my_local_qff_mbar, float my_local_altitude_meters)`
+- `int32_t opcHelper(float my_local_qff_mbar, float my_local_altitude_meters)`
Useful for calibrating the device so you can assign RPDS registers to correct for changes to pressure value reporting from the device due to soldering. diff --git a/examples/OPCHelper/OPCHelper.ino b/examples/OPCHelper/OPCHelper.ino index 4f7b857..e87c981 100644 --- a/examples/OPCHelper/OPCHelper.ino +++ b/examples/OPCHelper/OPCHelper.ino @@ -55,7 +55,7 @@ void setup() void loop() { - ps.opcHelper(pressure, altitude); + float pressure_diff = ps.opcHelper(pressure, altitude); delay(90000); } From 49d7301881ecdb75a94ef94e1f59b07028067235 Mon Sep 17 00:00:00 2001 From: loraxipam Date: Tue, 14 May 2019 14:01:32 -0400 Subject: [PATCH 5/5] Wrong version year. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c0ae8f6..7186758 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ Example output: ## Version history -* 3.1.0 (2018-05-07): Added helper functions and variables +* 3.1.0 (2019-05-07): Added helper functions and variables * Enums for FIFO modes * Enable FIFO function * Altitude to sea level pressure function