first commit
This commit is contained in:
126
libraries/A4990MotorShield/A4990MotorShield.cpp
Normal file
126
libraries/A4990MotorShield/A4990MotorShield.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#include "A4990MotorShield.h"
|
||||
const unsigned char A4990MotorShield::_M1DIR = 7;
|
||||
const unsigned char A4990MotorShield::_M2DIR = 8;
|
||||
const unsigned char A4990MotorShield::_M1PWM = 9;
|
||||
const unsigned char A4990MotorShield::_M2PWM = 10;
|
||||
const unsigned char A4990MotorShield::_FAULT = 6;
|
||||
boolean A4990MotorShield::_flipM1 = false;
|
||||
boolean A4990MotorShield::_flipM2 = false;
|
||||
|
||||
void A4990MotorShield::initPinsAndMaybeTimer()
|
||||
{
|
||||
// Initialize the pin states used by the motor driver shield
|
||||
// digitalWrite is called before and after setting pinMode.
|
||||
// It called before pinMode to handle the case where the board
|
||||
// is using an ATmega AVR to avoid ever driving the pin high,
|
||||
// even for a short time.
|
||||
// It is called after pinMode to handle the case where the board
|
||||
// is based on the Atmel SAM3X8E ARM Cortex-M3 CPU, like the Arduino
|
||||
// Due. This is necessary because when pinMode is called for the Due
|
||||
// it sets the output to high (or 3.3V) regardless of previous
|
||||
// digitalWrite calls.
|
||||
digitalWrite(_M1PWM, LOW);
|
||||
pinMode(_M1PWM, OUTPUT);
|
||||
digitalWrite(_M1PWM, LOW);
|
||||
digitalWrite(_M2PWM, LOW);
|
||||
pinMode(_M2PWM, OUTPUT);
|
||||
digitalWrite(_M2PWM, LOW);
|
||||
digitalWrite(_M1DIR, LOW);
|
||||
pinMode(_M1DIR, OUTPUT);
|
||||
digitalWrite(_M1DIR, LOW);
|
||||
digitalWrite(_M2DIR, LOW);
|
||||
pinMode(_M2DIR, OUTPUT);
|
||||
digitalWrite(_M2DIR, LOW);
|
||||
pinMode(_FAULT, INPUT_PULLUP);
|
||||
#ifdef A4990MOTORSHIELD_USE_20KHZ_PWM
|
||||
// timer 1 configuration
|
||||
// prescaler: clockI/O / 1
|
||||
// outputs enabled
|
||||
// phase-correct PWM
|
||||
// top of 400
|
||||
//
|
||||
// PWM frequency calculation
|
||||
// 16MHz / 1 (prescaler) / 2 (phase-correct) / 400 (top) = 20kHz
|
||||
TCCR1A = 0b10100000;
|
||||
TCCR1B = 0b00010001;
|
||||
ICR1 = 400;
|
||||
#endif
|
||||
}
|
||||
|
||||
// speed should be a number between -400 and 400
|
||||
void A4990MotorShield::setM1Speed(int speed)
|
||||
{
|
||||
init(); // initialize if necessary
|
||||
|
||||
boolean reverse = 0;
|
||||
|
||||
if (speed < 0)
|
||||
{
|
||||
speed = -speed; // make speed a positive quantity
|
||||
reverse = 1; // preserve the direction
|
||||
}
|
||||
if (speed > 400) // max
|
||||
speed = 400;
|
||||
|
||||
#ifdef A4990MOTORSHIELD_USE_20KHZ_PWM
|
||||
OCR1A = speed;
|
||||
#else
|
||||
analogWrite(_M1PWM, speed * 51 / 80); // default to using analogWrite, mapping 400 to 255
|
||||
#endif
|
||||
|
||||
if (reverse ^ _flipM1) // flip if speed was negative or _flipM1 setting is active, but not both
|
||||
digitalWrite(_M1DIR, HIGH);
|
||||
else
|
||||
digitalWrite(_M1DIR, LOW);
|
||||
}
|
||||
|
||||
// speed should be a number between -400 and 400
|
||||
void A4990MotorShield::setM2Speed(int speed)
|
||||
{
|
||||
init(); // initialize if necessary
|
||||
|
||||
boolean reverse = 0;
|
||||
|
||||
if (speed < 0)
|
||||
{
|
||||
speed = -speed; // make speed a positive quantity
|
||||
reverse = 1; // preserve the direction
|
||||
}
|
||||
if (speed > 400) // max PWM duty cycle
|
||||
speed = 400;
|
||||
|
||||
#ifdef A4990MOTORSHIELD_USE_20KHZ_PWM
|
||||
OCR1B = speed;
|
||||
#else
|
||||
analogWrite(_M2PWM, speed * 51 / 80); // default to using analogWrite, mapping 400 to 255
|
||||
#endif
|
||||
|
||||
if (reverse ^ _flipM2) // flip if speed was negative or _flipM2 setting is active, but not both
|
||||
digitalWrite(_M2DIR, HIGH);
|
||||
else
|
||||
digitalWrite(_M2DIR, LOW);
|
||||
}
|
||||
|
||||
// set speed for both motors
|
||||
// speed should be a number between -400 and 400
|
||||
void A4990MotorShield::setSpeeds(int m1Speed, int m2Speed)
|
||||
{
|
||||
setM1Speed(m1Speed);
|
||||
setM2Speed(m2Speed);
|
||||
}
|
||||
|
||||
void A4990MotorShield::flipM1(boolean flip)
|
||||
{
|
||||
A4990MotorShield::_flipM1 = flip;
|
||||
}
|
||||
|
||||
void A4990MotorShield::flipM2(boolean flip)
|
||||
{
|
||||
A4990MotorShield::_flipM2 = flip;
|
||||
}
|
||||
|
||||
boolean A4990MotorShield::getFault()
|
||||
{
|
||||
init(); // initialize if necessary
|
||||
return digitalRead(_FAULT) == LOW;
|
||||
}
|
||||
40
libraries/A4990MotorShield/A4990MotorShield.h
Normal file
40
libraries/A4990MotorShield/A4990MotorShield.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef A4990MotorShield_h
|
||||
#define A4990MotorShield_h
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined (__AVR_ATmega32U4__)
|
||||
#define A4990MOTORSHIELD_USE_20KHZ_PWM
|
||||
#endif
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class A4990MotorShield
|
||||
{
|
||||
public:
|
||||
static void setM1Speed(int speed);
|
||||
static void setM2Speed(int speed);
|
||||
static void setSpeeds(int m1Speed, int m2Speed);
|
||||
static void flipM1(boolean flip);
|
||||
static void flipM2(boolean flip);
|
||||
static boolean getFault();
|
||||
|
||||
private:
|
||||
static void initPinsAndMaybeTimer();
|
||||
const static unsigned char _M1DIR;
|
||||
const static unsigned char _M2DIR;
|
||||
const static unsigned char _M1PWM;
|
||||
const static unsigned char _M2PWM;
|
||||
const static unsigned char _FAULT;
|
||||
static boolean _flipM1;
|
||||
static boolean _flipM2;
|
||||
|
||||
static inline void init()
|
||||
{
|
||||
static boolean initialized = false;
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
initPinsAndMaybeTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
25
libraries/A4990MotorShield/LICENSE.txt
Normal file
25
libraries/A4990MotorShield/LICENSE.txt
Normal file
@@ -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.
|
||||
110
libraries/A4990MotorShield/README.md
Normal file
110
libraries/A4990MotorShield/README.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Arduino library for the Pololu A4990 Dual Motor Driver Shield
|
||||
|
||||
Version: 2.0.0 <br>
|
||||
Release date: 2016-08-18 <br>
|
||||
[](https://travis-ci.org/pololu/a4990-motor-shield) <br>
|
||||
[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 the
|
||||
[Pololu A4990 Dual Motor Driver Shield for Arduino](https://www.pololu.com/catalog/product/2512).
|
||||
It makes it simple to drive two brushed, DC motors.
|
||||
|
||||
## Getting started
|
||||
|
||||
### Hardware
|
||||
|
||||
The
|
||||
[Pololu A4990 Dual Motor Driver Shield for Arduino](https://www.pololu.com/catalog/product/2512)
|
||||
can be purchased on Pololu's website. Before continuing, careful
|
||||
reading of the product page is recommended.
|
||||
|
||||
#### Compatible Arduino boards
|
||||
|
||||
This shield should work with all Arduino boards and clones that behave
|
||||
like a standard Arduino board. We have specifically tested this shield
|
||||
(using this Arduino library) with:
|
||||
|
||||
* Arduino Uno R3
|
||||
* Arduino Leonardo
|
||||
* Arduino Mega 2560
|
||||
* Arduino Due
|
||||
* Arduino Duemilanove (ATmega328P)
|
||||
|
||||
This library configures Timer 1 on the Uno R3, Leonardo, and
|
||||
Duemilanove to generate a 20 kHz PWM frequency for the motors. The
|
||||
library uses analogWrite on any board that does not use an ATmega168,
|
||||
ATmega328P or ATmega32U4. On the Mega 2560 and Due, analogWrite
|
||||
generates 489 Hz and 1 kHz PWM frequencies, respectively, with the
|
||||
default timer configuration.
|
||||
|
||||
|
||||
### 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 "A4990MotorShield".
|
||||
3. Click the A4990MotorShield 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/a4990-motor-shield/releases)
|
||||
and decompress it.
|
||||
2. Rename the folder "lps-arduino-xxxx" to "A4990MotorShield".
|
||||
3. Drag the "A4990MotorShield" 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.
|
||||
|
||||
## Example program
|
||||
|
||||
An example sketch is available that shows how to use the library. You
|
||||
can access it from the Arduino IDE by opening the "File" menu,
|
||||
selecting "Examples", and then selecting "A4990MotorShield". If
|
||||
you cannot find these examples, the library was probably installed
|
||||
incorrectly and you should retry the installation instructions above.
|
||||
|
||||
### Demo
|
||||
|
||||
The demo ramps motor 1 from stopped to full speed forward, ramps down
|
||||
to full speed reverse, and back to stopped. Then, it does the same
|
||||
with the other motor.
|
||||
|
||||
## Documentatation
|
||||
|
||||
- `void setM1Speed(int speed)` <br> Set speed and direction for
|
||||
motor 1. Speed should be between -400 and 400. The motors brake at 0
|
||||
speed. Positive speeds correspond to motor current flowing from M1A
|
||||
to M1B. Negative speeds correspond to motor current flowing from M1B
|
||||
to M1A.
|
||||
- `void setM2Speed(int speed)` <br> Set speed and direction for
|
||||
motor 2. Speed should be between -400 and 400. The motors brake at 0
|
||||
speed. Positive speeds correspond to motor current flowing from M2A
|
||||
to M2B. Negative speeds correspond to motor current flowing from M2B
|
||||
to M2A.
|
||||
- `void setSpeeds(int m1Speed, int m2Speed)` <br> Set speed and
|
||||
direction for motor 1 and 2.
|
||||
- `void flipM1(bool flip)` <br> Flip the direction meaning of the
|
||||
speed passed to the setSpeeds function for motor 1. The default
|
||||
direction corresponds to flipM1(false) having been called.
|
||||
- `void flipM2(bool flip)` <br> Flip the direction meaning of the
|
||||
speed passed to the setSpeeds function for motor 2. The default
|
||||
direction corresponds to flipM2(false) having been called.
|
||||
- `bool getFault()` <br> Returns true if pin 6 is being driven low by
|
||||
one of the error flag outputs.
|
||||
|
||||
## Version history
|
||||
|
||||
* 2.0.0 (2016-08-18): Updated library to work with the Arduino Library Manager.
|
||||
* 1.0.0 (2014-08-15): Original release.
|
||||
@@ -0,0 +1,115 @@
|
||||
#include <A4990MotorShield.h>
|
||||
|
||||
/*
|
||||
* This example uses the A4990MotorShield library to drive each motor with the
|
||||
* Pololu A4990 Dual Motor Driver Shield for Arduino forward, then backward.
|
||||
* The yellow user LED is on when a motor is set to a positive speed and off when
|
||||
* a motor is set to a negative speed.
|
||||
*/
|
||||
|
||||
#define LED_PIN 13
|
||||
|
||||
A4990MotorShield motors;
|
||||
|
||||
/*
|
||||
* For safety, it is good practice to monitor motor driver faults and handle
|
||||
* them in an appropriate way. If a fault is detected, both motor speeds are set
|
||||
* to zero and it is reported on the serial port.
|
||||
*/
|
||||
void stopIfFault()
|
||||
{
|
||||
if (motors.getFault())
|
||||
{
|
||||
motors.setSpeeds(0,0);
|
||||
Serial.println("Fault");
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
Serial.begin(115200);
|
||||
Serial.println("Pololu A4990 Dual Motor Driver Shield for Arduino");
|
||||
|
||||
// uncomment one or both of the following lines if your motors' directions need to be flipped
|
||||
//motors.flipM1(true);
|
||||
//motors.flipM2(true);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// run M1 motor with positive speed
|
||||
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
|
||||
for (int speed = 0; speed <= 400; speed++)
|
||||
{
|
||||
motors.setM1Speed(speed);
|
||||
stopIfFault();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
for (int speed = 400; speed >= 0; speed--)
|
||||
{
|
||||
motors.setM1Speed(speed);
|
||||
stopIfFault();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
// run M1 motor with negative speed
|
||||
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
for (int speed = 0; speed >= -400; speed--)
|
||||
{
|
||||
motors.setM1Speed(speed);
|
||||
stopIfFault();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
for (int speed = -400; speed <= 0; speed++)
|
||||
{
|
||||
motors.setM1Speed(speed);
|
||||
stopIfFault();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
// run M2 motor with positive speed
|
||||
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
|
||||
for (int speed = 0; speed <= 400; speed++)
|
||||
{
|
||||
motors.setM2Speed(speed);
|
||||
stopIfFault();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
for (int speed = 400; speed >= 0; speed--)
|
||||
{
|
||||
motors.setM2Speed(speed);
|
||||
stopIfFault();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
// run M2 motor with negative speed
|
||||
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
for (int speed = 0; speed >= -400; speed--)
|
||||
{
|
||||
motors.setM2Speed(speed);
|
||||
stopIfFault();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
for (int speed = -400; speed <= 0; speed++)
|
||||
{
|
||||
motors.setM2Speed(speed);
|
||||
stopIfFault();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
delay(500);
|
||||
}
|
||||
8
libraries/A4990MotorShield/keywords.txt
Normal file
8
libraries/A4990MotorShield/keywords.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
A4990MotorShield KEYWORD1
|
||||
|
||||
flipM1 KEYWORD2
|
||||
flipM2 KEYWORD2
|
||||
setM1Speed KEYWORD2
|
||||
setM2Speed KEYWORD2
|
||||
setSpeeds KEYWORD2
|
||||
getFault KEYWORD2
|
||||
9
libraries/A4990MotorShield/library.properties
Normal file
9
libraries/A4990MotorShield/library.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
name=A4990MotorShield
|
||||
version=2.0.0
|
||||
author=Pololu
|
||||
maintainer=Pololu <inbox@pololu.com>
|
||||
sentence=Arduino library for the Pololu A4990 Dual Motor Driver Shield
|
||||
paragraph=This is a library for an Arduino-compatible controller that interfaces with the Pololu A4990 Dual Motor Driver Shield for Arduino.
|
||||
category=Device Control
|
||||
url=https://github.com/pololu/a4990-motor-shield
|
||||
architectures=*
|
||||
454
libraries/ACS712/ACS712.cpp
Normal file
454
libraries/ACS712/ACS712.cpp
Normal file
@@ -0,0 +1,454 @@
|
||||
//
|
||||
// FILE: ACS712.cpp
|
||||
// AUTHOR: Rob Tillaart, Pete Thompson
|
||||
// VERSION: 0.3.8
|
||||
// DATE: 2020-08-02
|
||||
// PURPOSE: ACS712 library - current measurement
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// CONSTRUCTOR
|
||||
ACS712::ACS712(uint8_t analogPin, float volts, uint16_t maxADC, float mVperAmpere)
|
||||
{
|
||||
_pin = analogPin;
|
||||
_mVperAmpere = mVperAmpere;
|
||||
_formFactor = ACS712_FF_SINUS;
|
||||
_noisemV = ACS712_DEFAULT_NOISE; // 21mV according to datasheet
|
||||
|
||||
// set in setADC()
|
||||
// keep it here until after experimental.
|
||||
_maxADC = maxADC;
|
||||
_mVperStep = 1000.0 * volts / maxADC; // 1x 1000 for V -> mV
|
||||
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
|
||||
_midPoint = maxADC / 2;
|
||||
|
||||
// default ADC is internal.
|
||||
setADC(NULL, volts, maxADC);
|
||||
}
|
||||
|
||||
|
||||
// MEASUREMENTS
|
||||
float ACS712::mA_peak2peak(float frequency, uint16_t cycles)
|
||||
{
|
||||
uint16_t period = round(1000000UL / frequency);
|
||||
|
||||
if (cycles == 0) cycles = 1;
|
||||
float sum = 0;
|
||||
|
||||
for (uint16_t i = 0; i < cycles; i++)
|
||||
{
|
||||
int minimum, maximum;
|
||||
// Better than using midPoint
|
||||
minimum = maximum = _analogRead(_pin);
|
||||
|
||||
// find minimum and maximum
|
||||
uint32_t start = micros();
|
||||
while (micros() - start < period) // UNO ~180 samples...
|
||||
{
|
||||
int value = _analogRead(_pin);
|
||||
if (_suppresNoise) // average 2 samples.
|
||||
{
|
||||
value = (value + _analogRead(_pin))/2;
|
||||
}
|
||||
// determine extremes
|
||||
if (value < minimum) minimum = value;
|
||||
else if (value > maximum) maximum = value;
|
||||
}
|
||||
sum += (maximum - minimum);
|
||||
}
|
||||
float peak2peak = sum * _mAPerStep;
|
||||
if (cycles > 1) peak2peak /= cycles;
|
||||
|
||||
return peak2peak;
|
||||
}
|
||||
|
||||
|
||||
float ACS712::mA_AC(float frequency, uint16_t cycles)
|
||||
{
|
||||
uint16_t period = round(1000000UL / frequency);
|
||||
|
||||
if (cycles == 0) cycles = 1;
|
||||
float sum = 0;
|
||||
|
||||
// remove float operation from loop.
|
||||
uint16_t zeroLevel = round(_noisemV/_mVperStep);
|
||||
|
||||
for (uint16_t i = 0; i < cycles; i++)
|
||||
{
|
||||
uint16_t samples = 0;
|
||||
uint16_t zeros = 0;
|
||||
|
||||
int _min, _max;
|
||||
_min = _max = _analogRead(_pin);
|
||||
|
||||
// find minimum and maximum and count the zero-level "percentage"
|
||||
uint32_t start = micros();
|
||||
while (micros() - start < period) // UNO ~180 samples...
|
||||
{
|
||||
samples++;
|
||||
int value = _analogRead(_pin);
|
||||
if (_suppresNoise) // average 2 samples.
|
||||
{
|
||||
value = (value + _analogRead(_pin))/2;
|
||||
}
|
||||
// determine extremes
|
||||
if (value < _min) _min = value;
|
||||
else if (value > _max) _max = value;
|
||||
// count zeros
|
||||
if (abs(value - _midPoint) <= zeroLevel ) zeros++;
|
||||
}
|
||||
int peak2peak = _max - _min;
|
||||
|
||||
// automatic determine _formFactor / crest factor
|
||||
float D = 0;
|
||||
float FF = 0;
|
||||
if (zeros > samples * 0.025) // more than 2% zero's
|
||||
{
|
||||
D = 1.0 - (1.0 * zeros) / samples; // % SAMPLES NONE ZERO
|
||||
FF = sqrt(D) * _formFactor; // ASSUME NON ZERO PART ~ SINUS
|
||||
}
|
||||
else // # zeros is small => D --> 1 --> sqrt(D) --> 1
|
||||
{
|
||||
FF = _formFactor;
|
||||
}
|
||||
|
||||
// value could be partially pre-calculated: C = 1000.0 * 0.5 * _mVperStep / _mVperAmpere;
|
||||
// return 1000.0 * 0.5 * peak2peak * _mVperStep * _formFactor / _mVperAmpere);
|
||||
sum += peak2peak * FF;
|
||||
}
|
||||
float mA = 0.5 * sum * _mAPerStep;
|
||||
if (cycles > 1) mA /= cycles;
|
||||
|
||||
return mA;
|
||||
}
|
||||
|
||||
|
||||
float ACS712::mA_AC_sampling(float frequency, uint16_t cycles)
|
||||
{
|
||||
uint32_t period = round(1000000UL / frequency);
|
||||
|
||||
if (cycles == 0) cycles = 1;
|
||||
float sum = 0;
|
||||
|
||||
// float noiseLevel = _noisemV/_mVperStep;
|
||||
|
||||
for (uint16_t i = 0; i < cycles; i++)
|
||||
{
|
||||
uint16_t samples = 0;
|
||||
float sumSquared = 0;
|
||||
|
||||
uint32_t start = micros();
|
||||
while (micros() - start < period)
|
||||
{
|
||||
samples++;
|
||||
int value = _analogRead(_pin);
|
||||
if (_suppresNoise) // average 2 samples.
|
||||
{
|
||||
value = (value + _analogRead(_pin))/2;
|
||||
}
|
||||
float current = value - _midPoint;
|
||||
sumSquared += (current * current);
|
||||
// not adding noise squared might be more correct for small currents.
|
||||
// if (abs(current) > noiseLevel)
|
||||
// {
|
||||
// sumSquared += (current * current);
|
||||
// }
|
||||
}
|
||||
sum += sqrt(sumSquared / samples);
|
||||
}
|
||||
float mA = sum * _mAPerStep;
|
||||
if (cycles > 1) mA /= cycles;
|
||||
|
||||
return mA;
|
||||
}
|
||||
|
||||
|
||||
float ACS712::mA_DC(uint16_t cycles)
|
||||
{
|
||||
// read at least twice to stabilize the ADC
|
||||
_analogRead(_pin);
|
||||
if (cycles == 0) cycles = 1;
|
||||
float sum = 0;
|
||||
for (uint16_t i = 0; i < cycles; i++)
|
||||
{
|
||||
int value = _analogRead(_pin);
|
||||
if (_suppresNoise) // average 2 samples.
|
||||
{
|
||||
value = (value + _analogRead(_pin))/2;
|
||||
}
|
||||
sum += (value - _midPoint);
|
||||
}
|
||||
float mA = sum * _mAPerStep;
|
||||
if (cycles > 1) mA /= cycles;
|
||||
|
||||
return mA;
|
||||
}
|
||||
|
||||
|
||||
// CALIBRATION MIDPOINT
|
||||
uint16_t ACS712::setMidPoint(uint16_t midPoint)
|
||||
{
|
||||
if (midPoint <= _maxADC) _midPoint = (int) midPoint;
|
||||
return _midPoint;
|
||||
};
|
||||
|
||||
|
||||
uint16_t ACS712::getMidPoint()
|
||||
{
|
||||
return _midPoint;
|
||||
};
|
||||
|
||||
|
||||
uint16_t ACS712::incMidPoint()
|
||||
{
|
||||
if (_midPoint < (int)(_maxADC)) _midPoint += 1;
|
||||
return _midPoint;
|
||||
};
|
||||
|
||||
|
||||
uint16_t ACS712::decMidPoint()
|
||||
{
|
||||
if (_midPoint > 0) _midPoint -= 1;
|
||||
return _midPoint;
|
||||
};
|
||||
|
||||
|
||||
// configure by sampling for 2 cycles of AC
|
||||
// Also works for DC as long as no current flowing
|
||||
// note this is blocking!
|
||||
uint16_t ACS712::autoMidPoint(float frequency, uint16_t cycles)
|
||||
{
|
||||
uint16_t twoPeriods = round(2000000UL / frequency);
|
||||
|
||||
if (cycles == 0) cycles = 1;
|
||||
|
||||
uint32_t total = 0;
|
||||
for (uint16_t i = 0; i < cycles; i++)
|
||||
{
|
||||
uint32_t subTotal = 0;
|
||||
uint32_t samples = 0;
|
||||
uint32_t start = micros();
|
||||
while (micros() - start < twoPeriods)
|
||||
{
|
||||
uint16_t reading = _analogRead(_pin);
|
||||
subTotal += reading;
|
||||
samples++;
|
||||
// Delaying prevents overflow
|
||||
// since we'll perform a maximum of 40,000 reads @ 50 Hz.
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
total += (subTotal / samples);
|
||||
}
|
||||
_midPoint = (total + (cycles/2))/ cycles; // rounding.
|
||||
return _midPoint;
|
||||
}
|
||||
|
||||
|
||||
uint16_t ACS712::autoMidPointDC(uint16_t cycles)
|
||||
{
|
||||
if (cycles == 0) cycles = 1;
|
||||
uint32_t total = 0;
|
||||
for (uint16_t i = 0; i < cycles; i++)
|
||||
{
|
||||
total += analogRead(_pin);
|
||||
}
|
||||
_midPoint = (total + (cycles/2))/ cycles; // rounding.
|
||||
return _midPoint;
|
||||
}
|
||||
|
||||
|
||||
uint16_t ACS712::resetMidPoint()
|
||||
{
|
||||
_midPoint = _maxADC / 2;
|
||||
return _midPoint;
|
||||
};
|
||||
|
||||
|
||||
// CALIBRATION FORM FACTOR
|
||||
void ACS712::setFormFactor(float formFactor)
|
||||
{
|
||||
_formFactor = formFactor;
|
||||
};
|
||||
|
||||
|
||||
float ACS712::getFormFactor()
|
||||
{
|
||||
return _formFactor;
|
||||
};
|
||||
|
||||
|
||||
// CALIBRATION NOISE
|
||||
// noise defaults 21 datasheet
|
||||
void ACS712::setNoisemV(uint8_t noisemV)
|
||||
{
|
||||
_noisemV = noisemV;
|
||||
};
|
||||
|
||||
|
||||
uint8_t ACS712::getNoisemV()
|
||||
{
|
||||
return _noisemV;
|
||||
};
|
||||
|
||||
|
||||
float ACS712::mVNoiseLevel(float frequency, uint16_t cycles)
|
||||
{
|
||||
float mA = mA_peak2peak(frequency, cycles);
|
||||
// divide by 2 as the level is half of the peak to peak range
|
||||
return mA * _mVperAmpere * 0.001 / 2;
|
||||
}
|
||||
|
||||
|
||||
void ACS712::suppressNoise(bool flag)
|
||||
{
|
||||
_suppresNoise = flag;
|
||||
}
|
||||
|
||||
|
||||
// CALIBRATION mV PER AMP
|
||||
// Adjusting resolution AC and DC
|
||||
void ACS712::setmVperAmp(float mVperAmpere)
|
||||
{
|
||||
_mVperAmpere = mVperAmpere;
|
||||
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
|
||||
};
|
||||
|
||||
|
||||
float ACS712::getmVperAmp()
|
||||
{
|
||||
return _mVperAmpere;
|
||||
};
|
||||
|
||||
|
||||
float ACS712::getmAPerStep()
|
||||
{
|
||||
return _mAPerStep;
|
||||
};
|
||||
|
||||
|
||||
float ACS712::getAmperePerStep()
|
||||
{
|
||||
return _mAPerStep * 0.001;
|
||||
};
|
||||
|
||||
|
||||
// FREQUENCY DETECTION
|
||||
// uses oversampling and averaging to minimize variation
|
||||
// blocks for substantial amount of time, depending on minimalFrequency
|
||||
float ACS712::detectFrequency(float minimalFrequency)
|
||||
{
|
||||
int maximum = 0;
|
||||
int minimum = 0;
|
||||
maximum = minimum = _analogRead(_pin);
|
||||
|
||||
// determine maxima
|
||||
uint32_t timeOut = round(1000000.0 / minimalFrequency);
|
||||
uint32_t start = micros();
|
||||
while (micros() - start < timeOut)
|
||||
{
|
||||
int value = _analogRead(_pin);
|
||||
if (value > maximum) maximum = value;
|
||||
if (value < minimum) minimum = value;
|
||||
}
|
||||
|
||||
// calculate quarter points
|
||||
// using quarter points is less noise prone than using one single midpoint
|
||||
int Q1 = (3 * minimum + maximum ) / 4;
|
||||
int Q3 = (minimum + 3 * maximum ) / 4;
|
||||
|
||||
// 10x passing Quantile points
|
||||
// wait for the right moment to start
|
||||
// to prevent endless loop a timeout is checked.
|
||||
timeOut *= 10;
|
||||
start = micros();
|
||||
// casting to int to keep compiler happy.
|
||||
while ((int(_analogRead(_pin)) > Q1) && ((micros() - start) < timeOut));
|
||||
while ((int(_analogRead(_pin)) <= Q3) && ((micros() - start) < timeOut));
|
||||
start = micros();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
while ((int(_analogRead(_pin)) > Q1) && ((micros() - start) < timeOut));
|
||||
while ((int(_analogRead(_pin)) <= Q3) && ((micros() - start) < timeOut));
|
||||
}
|
||||
uint32_t stop = micros();
|
||||
|
||||
// calculate frequency
|
||||
float wavelength = stop - start;
|
||||
float frequency = 1e7 / wavelength;
|
||||
if (_microsAdjust != 1.0) frequency *= _microsAdjust;
|
||||
return frequency;
|
||||
}
|
||||
|
||||
|
||||
// timing for FREQUENCY DETECTION
|
||||
void ACS712::setMicrosAdjust(float factor)
|
||||
{
|
||||
_microsAdjust = factor;
|
||||
};
|
||||
|
||||
|
||||
float ACS712::getMicrosAdjust()
|
||||
{
|
||||
return _microsAdjust;
|
||||
};
|
||||
|
||||
|
||||
// DEBUG
|
||||
uint16_t ACS712::getMinimum(uint16_t milliSeconds)
|
||||
{
|
||||
uint16_t minimum = _analogRead(_pin);
|
||||
|
||||
// find minimum
|
||||
uint32_t start = millis();
|
||||
while (millis() - start < milliSeconds)
|
||||
{
|
||||
uint16_t value = _analogRead(_pin);
|
||||
if (value < minimum) minimum = value;
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
||||
|
||||
uint16_t ACS712::getMaximum(uint16_t milliSeconds)
|
||||
{
|
||||
uint16_t maximum = _analogRead(_pin);
|
||||
|
||||
// find maximum
|
||||
uint32_t start = millis();
|
||||
while (millis() - start < milliSeconds)
|
||||
{
|
||||
uint16_t value = _analogRead(_pin);
|
||||
if (value > maximum) maximum = value;
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
|
||||
void ACS712::setADC(uint16_t (* f)(uint8_t), float volts, uint16_t maxADC)
|
||||
{
|
||||
_readADC = f;
|
||||
|
||||
_maxADC = maxADC;
|
||||
_mVperStep = 1000.0 * volts / maxADC; // 1x 1000 for V -> mV
|
||||
_mAPerStep = 1000.0 * _mVperStep / _mVperAmpere;
|
||||
_midPoint = maxADC / 2;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
uint16_t ACS712::_analogRead(uint8_t pin)
|
||||
{
|
||||
// if external ADC is defined use it.
|
||||
if (_readADC != NULL) return _readADC(pin);
|
||||
return analogRead(pin);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
138
libraries/ACS712/ACS712.h
Normal file
138
libraries/ACS712/ACS712.h
Normal file
@@ -0,0 +1,138 @@
|
||||
#pragma once
|
||||
//
|
||||
// FILE: ACS712.h
|
||||
// AUTHOR: Rob Tillaart, Pete Thompson
|
||||
// VERSION: 0.3.8
|
||||
// DATE: 2020-08-02
|
||||
// PURPOSE: ACS712 library - current measurement
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
//
|
||||
// Tested with a RobotDyn ACS712 20A breakout + UNO.
|
||||
//
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
|
||||
#define ACS712_LIB_VERSION (F("0.3.8"))
|
||||
|
||||
|
||||
// ACS712_FF_SINUS == 1.0/sqrt(2) == 0.5 * sqrt(2)
|
||||
// should be smaller in practice 0.5 ?
|
||||
#define ACS712_FF_SINUS (1.0/sqrt(2))
|
||||
#define ACS712_FF_SQUARE (1.0)
|
||||
#define ACS712_FF_TRIANGLE (1.0/sqrt(3))
|
||||
#define ACS712_FF_SAWTOOTH (1.0/sqrt(3))
|
||||
|
||||
#define ACS712_DEFAULT_FREQ 50
|
||||
#define ACS712_DEFAULT_NOISE 21
|
||||
|
||||
|
||||
class ACS712
|
||||
{
|
||||
public:
|
||||
// NOTE:
|
||||
// One can quite precisely tune the value of the sensor
|
||||
// (1) the milliVolt per Ampere and
|
||||
// (2) the volts parameter.
|
||||
//
|
||||
// TYPE mV per Ampere
|
||||
// 5A 185.0
|
||||
// 20A 100.0
|
||||
// 30A 66.0
|
||||
ACS712(uint8_t analogPin, float volts = 5.0, uint16_t maxADC = 1023, float mVperAmpere = 100);
|
||||
|
||||
// returns mA peak2peak current.
|
||||
float mA_peak2peak(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);
|
||||
|
||||
// returns mA
|
||||
// blocks 20-21 ms to sample a whole 50 or 60 Hz period.
|
||||
// works with peak2peak level and (crest) Form Factor.
|
||||
// lower frequencies block longer.
|
||||
float mA_AC(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);
|
||||
|
||||
// returns mA
|
||||
// blocks 20-21 ms to sample a whole 50 or 60 Hz period.
|
||||
// works with sampling.
|
||||
// lower frequencies block longer.
|
||||
float mA_AC_sampling(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);
|
||||
|
||||
// returns mA
|
||||
// blocks < 1 ms
|
||||
float mA_DC(uint16_t samples = 1);
|
||||
|
||||
|
||||
// midPoint functions
|
||||
// set reference point (raw ADC) for both DC and AC
|
||||
uint16_t setMidPoint(uint16_t midPoint);
|
||||
uint16_t getMidPoint();
|
||||
uint16_t incMidPoint();
|
||||
uint16_t decMidPoint();
|
||||
// Auto midPoint, assuming zero DC current or any AC current
|
||||
// For DC current set the frequency to 1000 or so to reduce blocking.
|
||||
uint16_t autoMidPoint(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1);
|
||||
// Auto midPoint, dedicated for zero DC current (much faster ==> less blocking)
|
||||
uint16_t autoMidPointDC(uint16_t cycles = 1);
|
||||
// resets to half maxADC
|
||||
uint16_t resetMidPoint();
|
||||
|
||||
|
||||
// Form Factor is also known as crest factor;
|
||||
// affects mA_AC() only, default sinus.
|
||||
void setFormFactor(float formFactor = ACS712_FF_SINUS);
|
||||
float getFormFactor();
|
||||
|
||||
|
||||
// noise defaults 21 datasheet
|
||||
void setNoisemV(uint8_t noisemV = ACS712_DEFAULT_NOISE);
|
||||
uint8_t getNoisemV();
|
||||
// enable/disable noiseSuppression for this measurement as needed.
|
||||
float mVNoiseLevel(float frequency = ACS712_DEFAULT_FREQ, uint16_t cycles = 1); // uses mA_peak2peak()
|
||||
void suppressNoise(bool flag);
|
||||
|
||||
|
||||
// Adjusting resolution AC and DC
|
||||
void setmVperAmp(float mVperAmpere);
|
||||
float getmVperAmp();
|
||||
float getmAPerStep();
|
||||
float getAmperePerStep();
|
||||
|
||||
|
||||
// Frequency detection.
|
||||
// the minimal frequency determines the time to sample.
|
||||
float detectFrequency(float minimalFrequency = 40);
|
||||
void setMicrosAdjust(float factor = 1.0);
|
||||
float getMicrosAdjust();
|
||||
|
||||
// DEBUG
|
||||
uint16_t getMinimum(uint16_t milliSeconds = 20);
|
||||
uint16_t getMaximum(uint16_t milliSeconds = 20);
|
||||
|
||||
|
||||
// EXPERIMENTAL 0.3.4
|
||||
// function returning 16 bit max, with pin or channel as parameter
|
||||
void setADC(uint16_t (*)(uint8_t), float volts, uint16_t maxADC);
|
||||
|
||||
|
||||
private:
|
||||
uint8_t _pin;
|
||||
uint16_t _maxADC;
|
||||
float _mVperStep;
|
||||
float _formFactor; // peak2peak -> RMS
|
||||
float _mVperAmpere;
|
||||
float _mAPerStep;
|
||||
int _midPoint;
|
||||
uint8_t _noisemV;
|
||||
float _microsAdjust = 1.0; // 0.9986
|
||||
bool _suppresNoise = false;
|
||||
|
||||
// EXPERIMENTAL 0.3.4
|
||||
// supports up to 16 bits ADC.
|
||||
uint16_t (* _readADC)(uint8_t);
|
||||
uint16_t _analogRead(uint8_t pin);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
121
libraries/ACS712/CHANGELOG.md
Normal file
121
libraries/ACS712/CHANGELOG.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# Change Log ACS712
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.3.8] - 2023-09-19
|
||||
- add badges to readme.md
|
||||
- minor edits
|
||||
|
||||
|
||||
## [0.3.7] - 2023-05-20
|
||||
- add example **estimateMidPointAC.ino** #37
|
||||
- update readme.md (sampling trick #38).
|
||||
- minor edits.
|
||||
|
||||
## [0.3.6] - 2023-04-19
|
||||
- add **autoMidPointDC(cycles)** see issue #35
|
||||
- add rounding to **autoMidPoint()**
|
||||
- update README.md
|
||||
|
||||
## [0.3.5] - 2023-01-18
|
||||
- fix #33 failing build => issue 345 created @ arduino-ci
|
||||
- redo **setADC()**
|
||||
- allows reset to internal **analogRead()** too now.
|
||||
- update README.md
|
||||
|
||||
## [0.3.4] - 2023-01-14
|
||||
- experimental
|
||||
- add **void setADC()** to use an external ADC for measurements.
|
||||
- add **static uint16_t internalAnalog(uint8_t p)** wrapping analogRead() - solves casting.
|
||||
- add example ACS712_20_DC_external_ADC.ino
|
||||
|
||||
## [0.3.3] - 2023-01-03
|
||||
- update GitHub actions
|
||||
- update license
|
||||
- add example
|
||||
- add URL in .h .cpp
|
||||
|
||||
## [0.3.2] - 2022-11-18
|
||||
- fix #26 revert data type \_midPoint to int
|
||||
- Add CHANGELOG.md
|
||||
|
||||
## [0.3.1 2022-09-xx
|
||||
- add float mVNoiseLevel(frequency, cycles)
|
||||
- add void suppressNoise(bool flag) - experimental suppression by averaging two samples.
|
||||
- update readme.md
|
||||
- improve midPoint functions
|
||||
- add resetMidPoint()
|
||||
- add RP2040 pico in build-ci
|
||||
|
||||
## [0.3.0] - 2022-09-01
|
||||
- return midPoint value in MP functions.
|
||||
- float return type for mA() functions
|
||||
- add float mA_peak2peak(freq, cycles)
|
||||
- add debug getMinimum(), getmaximum();
|
||||
- update Readme.md
|
||||
|
||||
----
|
||||
|
||||
## [0.2.8] - 2022-08-19 prepare for 0.3.0
|
||||
- Fix #21 FormFactor
|
||||
- add mA_AC_sampling() as method to determine
|
||||
- current when FormFactor is unknown.
|
||||
- added float _AmperePerStep cached value.
|
||||
- added getAmperePerStep();
|
||||
- moved several functions to .cpp
|
||||
- improve documentation
|
||||
|
||||
## [0.2.7] - 2022-08-10
|
||||
- change mVperAmp to float
|
||||
- add ACS712_FF_SAWTOOTH
|
||||
- update readme.md + unit test + minor edits
|
||||
|
||||
## [0.2.6] - 2021-12-09
|
||||
- update readme.md
|
||||
- update license
|
||||
|
||||
## [0.2.5] - 2021-12-03
|
||||
- add timeout to detectFrequency()
|
||||
|
||||
## [0.2.4] - 2021-11-22
|
||||
- add experimental detectFrequency()
|
||||
|
||||
## [0.2.3] - 2021-10-15
|
||||
- change frequencies to float, for optimal tuning.
|
||||
- update build CI
|
||||
- update readme.md
|
||||
|
||||
## [0.2.2] - 2021-06-23
|
||||
- support for more frequencies
|
||||
|
||||
## [0.2.1] - 2020-12-06
|
||||
- Add Arduino-CI + unit test
|
||||
- update readme
|
||||
- refactor
|
||||
|
||||
## [0.2.0] - 2020-08-02
|
||||
- Add autoMidPoint()
|
||||
|
||||
----
|
||||
|
||||
## [0.1.4] - 2020-08-02
|
||||
- Allow for faster processors
|
||||
|
||||
## [0.1.3] - 2020-05-27
|
||||
- fix library.json
|
||||
|
||||
## [0.1.2] - 2020-03-21
|
||||
- automatic form factor test
|
||||
|
||||
## [0.1.1] - 2020-03-18
|
||||
- first release version
|
||||
|
||||
## [0.1.0] - 2020-03-17
|
||||
- initial version
|
||||
|
||||
|
||||
|
||||
21
libraries/ACS712/LICENSE
Normal file
21
libraries/ACS712/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2023 Rob Tillaart
|
||||
|
||||
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.
|
||||
498
libraries/ACS712/README.md
Normal file
498
libraries/ACS712/README.md
Normal file
@@ -0,0 +1,498 @@
|
||||
|
||||
[](https://github.com/marketplace/actions/arduino_ci)
|
||||
[](https://github.com/RobTillaart/ACS712/actions/workflows/arduino-lint.yml)
|
||||
[](https://github.com/RobTillaart/ACS712/actions/workflows/jsoncheck.yml)
|
||||
[](https://github.com/RobTillaart/ACS712/issues)
|
||||
|
||||
[](https://github.com/RobTillaart/ACS712/blob/master/LICENSE)
|
||||
[](https://github.com/RobTillaart/ACS712/releases)
|
||||
[](https://registry.platformio.org/libraries/robtillaart/ACS712)
|
||||
|
||||
|
||||
# ACS712
|
||||
|
||||
Library for the ACS712 Current Sensor - 5A, 20A, 30A and compatibles.
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
The ACS712 is a chip to measure current, both AC or DC. The chip has an
|
||||
analogue output that provides a voltage that is linear with the current.
|
||||
The ACS712 library supports only a built in ADC by means of **analogRead()**.
|
||||
|
||||
However since 0.3.4 there is an experimental **setADC()**.
|
||||
|
||||
The library has 4 core functions:
|
||||
|
||||
- **float mA_peak2peak(frequency = 50, cycles = 1)**
|
||||
- **float mA_DC(cycles = 1)**
|
||||
- **float mA_AC(frequency = 50, cycles = 1)**
|
||||
- **float mA_AC_sampling(frequency = 50, cycles = 1)**
|
||||
|
||||
The parameter cycles is used to measure multiple cycles and average them.
|
||||
|
||||
To measure DC current a single **analogRead()** with conversion math is
|
||||
sufficient to get a value.
|
||||
To stabilize the signal **analogRead()** is called at least twice.
|
||||
|
||||
To measure AC current **a blocking loop for 20 milliseconds** (50 Hz, 1 cycle)
|
||||
is run to determine the peak to peak value which is converted to the RMS value.
|
||||
To convert the peak2peak value to RMS one need the so called crest or form factor.
|
||||
This factor depends heavily on the signal form, hence its name.
|
||||
For a perfect sinus the value is sqrt(2)/2 == 1/sqrt(2).
|
||||
See **Form factor** below.
|
||||
|
||||
For a 60 Hz environment the blocking is ~16.7 milliseconds, still pretty long.
|
||||
|
||||
The **mA_AC_sampling()** calculates the average of the sumSquared of many measurements.
|
||||
This function should be used when the form factor is not known.
|
||||
|
||||
Note to make precise measurements, the power supply of both the ACS712 and the ADC of
|
||||
the processor should be as stable as possible.
|
||||
That improves the stability of the midpoint and minimizes the noise.
|
||||
|
||||
|
||||
#### Resolution
|
||||
|
||||
| Sensor | mVperA | LSB 10bit | LSB 12bit | LSB 16bit |
|
||||
|:---------|:--------:|:-----------:|:-----------:|:-----------:|
|
||||
| 5 A | 185 | 26.4 mA | 6.6 mA | 0.41 mA |
|
||||
| 20 A | 100 | 48.9 mA | 12.2 mA | 0.76 mA |
|
||||
| 30 A | 66 | 74.1 mA | 18.5 mA | 1.16 mA |
|
||||
|
||||
```cpp
|
||||
getmAPerStep();
|
||||
mA LSB = (5000 mV / maxADC) / mVperA * 1000.0;
|
||||
mA LSB = (1000 * 5000 mV) / (maxADC * mVperA);
|
||||
```
|
||||
|
||||
Although no 16 bit ADC built in are known, it indicates what resolution
|
||||
could be obtained with such an ADC. It triggered the experimental supporting
|
||||
of external ADC's with this library.
|
||||
|
||||
|
||||
#### Tests
|
||||
|
||||
The library is at least confirmed to work with the following boards:
|
||||
|
||||
| Device | Voltage | ADC steps | Notes |
|
||||
|:-------------|:-------:|:---------:|:--------|
|
||||
| Arduino UNO | 5.0V | 1024 | tested with RobotDyn ACS712 20 A breakout.
|
||||
| Arduino UNO | 5.0V | 1024 | tested with Open-Smart ACS712 5 A breakout.
|
||||
| Arduino NANO | 5.0V | 1024 | #18
|
||||
| ESP32 | 3.3V | 4096 | #15
|
||||
| Promicro | 5.0V | 1024 | #15
|
||||
|
||||
Please let me know of other working platforms / processors (and failing ones!).
|
||||
|
||||
|
||||
## Compatibles
|
||||
|
||||
Robodyn has a breakout for the ACS758 - 50 A. - See resolution below.
|
||||
This sensor has versions up to 200 Amps, so use with care!
|
||||
|
||||
Allegromicro offers a lot of different current sensors that might be compatible.
|
||||
These include bidirectional and unidirectional ones.
|
||||
The unidirectional seem to be for DC only.
|
||||
|
||||
https://www.allegromicro.com/en/products/sense/current-sensor-ics/current-sensors-innovations
|
||||
|
||||
If you have tested a compatible sensor, please share your experiences.
|
||||
(can be done by opening an issue to update documentation)
|
||||
|
||||
|
||||
#### Resolution ACS758
|
||||
|
||||
Not tested, but looks compatible - same formula as above
|
||||
|
||||
| Sensor | mVperA | LSB 10bit | LSB 12bit | LSB 16bit | directional |
|
||||
|:---------|:--------:|:-----------:|:-----------:|:-----------:|:-------------:|
|
||||
| 50 A | 40 | 122.2 mA | 30.5 mA | 1.91 mA | bi |
|
||||
| 50 A | 60 | 81.5 mA | 20.3 mA | 1.27 mA | uni |
|
||||
| 100 A | 20 | 244.4 mA | 61.0 mA | 3.81 mA | bi |
|
||||
| 100 A | 40 | 122.2 mA | 30.5 mA | 1.91 mA | uni |
|
||||
| 150 A | 13.3 | 367.5 mA | 91.8 mA | 5.74 mA | bi |
|
||||
| 150 A | 26.7 | 183.1 mA | 45.7 mA | 2.86 mA | uni |
|
||||
| 200 A | 10 | 488.8 mA | 122.1 mA | 7.63 mA | bi |
|
||||
| 200 A | 20 | 244.4 mA | 61.0 mA | 3.81 mA | uni |
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
```cpp
|
||||
#include ACS712.h
|
||||
```
|
||||
|
||||
|
||||
#### Base
|
||||
|
||||
- **ACS712(uint8_t analogPin, float volts = 5.0, uint16_t maxADC = 1023, float mVperAmpere = 100)** constructor.
|
||||
It defaults a 20 A type sensor, which is defined by the default value of mVperAmpere. See table below.
|
||||
Volts is the voltage used by the (Arduino) internal ADC. maxADC is the maximum output of the internal ADC.
|
||||
The defaults are based upon an Arduino UNO, 10 bits ADC.
|
||||
These two ADC parameters are needed to calculate the voltage output of the ACS712 sensor.
|
||||
- **float mA_peak2peak(float frequency = 50, uint16_t cycles = 1)** blocks ~21 ms to sample a whole 50 or 60 Hz period.
|
||||
Returns the peak to peak current, can be used to determine form factor.
|
||||
The **mA_peak2peak()** can also be used to measure on a zero current line
|
||||
to get an indication of the lowest detectable current.
|
||||
Finally this function is used internally to detect the noiseLevel in mV on a zero current line.
|
||||
- **float mA_AC(float frequency = 50, uint16_t cycles = 1)** blocks ~21 ms to sample a whole 50 or 60 Hz period.
|
||||
Note that a lower frequency, or more cycles, will increase the blocking period.
|
||||
The function returns the AC current in mA.
|
||||
Its working is based upon multiplying the peak2peak value by the FormFactor which must be known and set.
|
||||
- 0.2.2 frequencies other integer values than 50 and 60 are supported.
|
||||
- 0.2.3 floating point frequencies are supported to tune even better.
|
||||
- 0.2.8 the parameter cycles allow to average over a number of cycles.
|
||||
- **float mA_AC_sampling(float frequency = 50, uint16_t cycles = 1)** blocks ~21 ms to sample a whole period.
|
||||
The function returns the AC current in mA. (Note it returns a float).
|
||||
Its working is based upon sampling a full period and take the square root of the average sumSquared.
|
||||
This function is intended for signals with unknown Form Factor.
|
||||
- 0.2.8 the parameter cycles allow to average over a number of cycles.
|
||||
- **float mA_DC(uint16_t samples = 1)** blocks < 1 ms (Arduino UNO) as it calls **analogRead()** twice.
|
||||
A negative value indicates the current flows in the opposite direction.
|
||||
- 0.2.8 the parameter samples allow to average over a number of samples.
|
||||
|
||||
|
||||
#### mA_AC_sampling performance trick.
|
||||
|
||||
A trick to sample faster is to set the frequency to 2 times the actual frequency so to 100 or 120 Hz.
|
||||
This results in sampling only half a period and the same current will be measured.
|
||||
Advantage is that the function only blocks for ~10 ms @ 50Hz (8.5 @ 60Hz).
|
||||
The drawback is about 4x as many variation.
|
||||
So only use if the performance (or less blocking) is needed.
|
||||
|
||||
In a similar way one can increase the accuracy (reducing the variation)
|
||||
by setting the frequency a factor 2 lower (25 and 30 Hz).
|
||||
Drawback is a far longer blocking time.
|
||||
|
||||
Use with care!
|
||||
|
||||
See - https://github.com/RobTillaart/ACS712/issues/38
|
||||
|
||||
|
||||
#### Midpoint
|
||||
|
||||
The midpoint is the (raw) zero-reference for all current measurements.
|
||||
It is defined in steps of the ADC and is typical around half the **maxADC** value defined
|
||||
in the constructor. So for a 10 bit ADC a number between 500..525 is most likely.
|
||||
|
||||
Since 0.3.0 all midpoint functions return the actual midPoint.
|
||||
|
||||
- **uint16_t setMidPoint(uint16_t midPoint)** sets midpoint for the ADC conversion.
|
||||
Parameter must be between 0 and maxADC/2, otherwise midpoint is not changed.
|
||||
- **uint16_t getMidPoint()** read the value set / determined.
|
||||
- **uint16_t incMidPoint()** manual increase midpoint, e.g. useful in an interactive application.
|
||||
Will not increase if midpoint equals maxADC.
|
||||
- **uint16_t decMidPoint()** manual decrease midpoint.
|
||||
Will not decrease if midpoint equals 0.
|
||||
- **uint16_t resetMidPoint()** resets the midpoint to the initial value of maxADC / 2 as in the constructor.
|
||||
- **uint16_t autoMidPointDC(uint16_t cycles = 1)** Auto midPoint for DC only.
|
||||
Assuming zero DC current. To reduce the noise cycles must be increased even up to 100.
|
||||
This method is typically much faster for DC than the **autoMidPoint(freq, cycles)**
|
||||
for the same number of cycles. (See issue #35)
|
||||
- **uint16_t autoMidPoint(float frequency = 50, uint16_t cycles = 1)** Auto midPoint, for any AC current or zero DC current.
|
||||
For DC one can use a high frequency e.g. 1000 Hz to reduce the time blocking.
|
||||
The function takes the average of many measurements during one or more full cycles.
|
||||
Note the function therefore blocks for at least 2 periods which is about
|
||||
40 ms for 50 Hz.
|
||||
By increasing the number of cycles the function averages even more measurements,
|
||||
possibly resulting in a better midPoint. Idea is that noise will average out.
|
||||
This function is mandatory for measuring AC.
|
||||
- 0.2.2 frequencies other than 50 and 60 are supported.
|
||||
- 0.2.8 the parameter cycles allow to average over a number of cycles.
|
||||
|
||||
|
||||
Since version 0.3.0 there is another way to determine the midPoint.
|
||||
One can use the two debug functions.
|
||||
(milliseconds > 20 to get at least a full cycle)
|
||||
- **uint16_t getMinimum(uint16_t milliSeconds = 20)**
|
||||
- **uint16_t getMaximum(uint16_t milliSeconds = 20)**
|
||||
|
||||
and take the average of these two values. In code:
|
||||
|
||||
```cpp
|
||||
uint16_t midpoint = ACS.setMidPoint(ACS.getMinimum(20)/2 + ACS.getMaximum(20)/ 2);
|
||||
```
|
||||
See - ACS712_20_AC_midPoint_compare.ino
|
||||
|
||||
The ACS712 has a midPoint level that is specified as 0.5 \* VCC.
|
||||
So **autoMidPoint()** can help to detect voltage deviations for the ACS712.
|
||||
The library does not support this yet.
|
||||
|
||||
|
||||
#### Form factor
|
||||
|
||||
The form factor is also known as the **crest factor**.
|
||||
It is only used for signals measured with **mA_AC()**.
|
||||
|
||||
- **void setFormFactor(float formFactor = ACS712_FF_SINUS)** manually sets the form factor.
|
||||
Must typical be between 0.0 and 1.0, see constants below.
|
||||
- **float getFormFactor()** returns current form factor.
|
||||
|
||||
The library has a number of predefined form factors:
|
||||
|
||||
| definition | value | approx | notes |
|
||||
|:---------------------|:----------------|:--------:|:----------|
|
||||
| ACS712_FF_SQUARE | 1.0 | 1.000 |
|
||||
| ACS712_FF_SINUS | 1.0 / sqrt(2) | 0.707 | default |
|
||||
| ACS712_FF_TRIANGLE | 1.0 / sqrt(3) | 0.577 |
|
||||
| ACS712_FF_SAWTOOTH | 1.0 / sqrt(3) | 0.577 |
|
||||
|
||||
It is important to measure the current with a calibrated multimeter
|
||||
and determine / verify the form factor of the signal.
|
||||
This can help to improve the quality of your measurements.
|
||||
|
||||
Please let me know if other crest factors need to be added.
|
||||
|
||||
Since version 0.3.0 the form factor can be determined by
|
||||
|
||||
```cpp
|
||||
float formFactor = 2.0 * mA_AC_sampling() / ACS.mA_peak2peak();
|
||||
```
|
||||
|
||||
See - ACS712_20_determine_form_factor.ino
|
||||
|
||||
|
||||
#### Noise
|
||||
|
||||
Default = 21 mV (datasheet)
|
||||
|
||||
- **void setNoisemV(uint8_t noisemV = 21)** sets the noise level,
|
||||
is used to determine zero level e.g. in the AC measurements with **mA_AC()**.
|
||||
- **uint8_t getNoisemV()** returns the set value.
|
||||
- **float mVNoiseLevel(float frequency, uint16_t cycles)** determines the mV of noise.
|
||||
Measurement should be taken when there is no AC/DC current or a constant DC current.
|
||||
The level will give a (not quantified yet) indication of the accuracy of the measurements.
|
||||
A first order indication can be made by comparing it to voltage / 2 of the constructor.
|
||||
|
||||
Noise on the signal can be reduced by using a low pass (RC) filter.
|
||||
Version 0.3.1 includes experimental code to take two sample and average them.
|
||||
The idea is that ```((3 + 5)/2)^2 < (3^2 + 5^2)/2```
|
||||
|
||||
In theory this should suppress noise levels however more investigation in
|
||||
software noise detection and suppression is needed.
|
||||
|
||||
- **void suppressNoise(bool flag)** experimental noise suppression.
|
||||
|
||||
|
||||
#### mV per Ampere
|
||||
|
||||
Used for both for AC and DC measurements.
|
||||
Its value is defined in the constructor and depends on type sensor used.
|
||||
These functions allow to adjust this setting run-time.
|
||||
|
||||
- **void setmVperAmp(float mVperAmpere)** sets the milliVolt per Ampere measured.
|
||||
- **float getmVperAmp()** returns the set value.
|
||||
|
||||
Typical values see "Resolution" section above, and the "voltage divider" section below.
|
||||
|
||||
|
||||
#### Frequency detection
|
||||
|
||||
Experimental functionality for AC signal only!
|
||||
|
||||
- **float detectFrequency(float minimalFrequency = 40)** Detect the frequency of the AC signal.
|
||||
- **void setMicrosAdjust(float factor = 1.0)** adjusts the timing of micros in **detectFrequency()**.
|
||||
Values are typical around 1.0 ± 1%
|
||||
- **float getMicrosAdjust()** returns the set factor.
|
||||
|
||||
The minimum frequency of 40 Hz is used to sample for enough time to find the minimum and maximum
|
||||
for 50 and 60 Hz signals.
|
||||
Thereafter the signal is sampled 10 cycles to minimize the variation of the frequency.
|
||||
|
||||
The **microsAdjust()** is to adjust the timing of **micros()**.
|
||||
This function is only useful if one has a good reference source like a calibrated function generator
|
||||
to find the factor to adjust.
|
||||
Testing with my UNO I got a factor 0.9986.
|
||||
|
||||
Current version is experimental and not performance optimized.
|
||||
|
||||
|
||||
#### setADC (experimental 0.3.4)
|
||||
|
||||
- **void setADC(uint16_t (\*)(uint8_t), float volts, uint16_t maxADC)** sets the ADC function and the parameters of the used ADC.
|
||||
The library uses the internal **analogRead()** as default.
|
||||
Be sure to set the parameters of the ADC correctly.
|
||||
|
||||
The easiest way to implement an external ADC is to make a wrapper function as casting for
|
||||
function pointer is a no go area.
|
||||
|
||||
|
||||
```cpp
|
||||
// set to external ADC - 5 volts 12 bits
|
||||
ACS.setADC(myAnalogRead, 5.0, 4096);
|
||||
|
||||
...
|
||||
|
||||
uint16_t myAnalogRead(uint8_t pin)
|
||||
{
|
||||
return MCP.read(pin); // assuming MCP is ADC object.
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
To reset to the internal ADC use **NULL** as function pointer.
|
||||
Be sure to set the parameters of the ADC correctly.
|
||||
|
||||
```cpp
|
||||
// reset to internal ADC - 5 volts 10 bits
|
||||
ACS.setADC(NULL, 5.0, 1023);
|
||||
```
|
||||
|
||||
- example ACS712_20_DC_external_ADC.ino
|
||||
- https://github.com/RobTillaart/ACS712/issues/31
|
||||
|
||||
|
||||
Note that the use of an external ADC should meet certain performance requirements,
|
||||
especially for measuring **ma-AC()**.
|
||||
To 'catch' the peaks well enough one needs at least 2 samples per millisecond
|
||||
for a 60 Hz signal.
|
||||
|
||||
The 16 bit I2C **ADS1115** in continuous mode gives max 0.8 samples per millisecond.
|
||||
This will work perfect for high resolution **mA-DC()** but is not fast enough for
|
||||
doing **mA-AC()**.
|
||||
|
||||
The SPI based **MCP3202** ao can do up to 100 samples per millisecond at 12 bit.
|
||||
These ADC's are perfect both **mA-DC()** and **mA-AC()**.
|
||||
|
||||
- https://github.com/RobTillaart/ADS1X15
|
||||
- https://github.com/RobTillaart/MCP_ADC
|
||||
|
||||
|
||||
## Voltage divider
|
||||
|
||||
As per issue #15 in which an ACS712 was connected via a voltage divider to the ADC of an ESP32.
|
||||
|
||||
Schema
|
||||
```
|
||||
ACS712 ----[ R1 ]----o----[ R2 ]---- GND
|
||||
|
|
||||
|
|
||||
ADC of processor
|
||||
```
|
||||
|
||||
The voltage divider gave an error of about a factor 2 as all voltages were divided,
|
||||
including the "offset" from the **midPoint** zero current level.
|
||||
|
||||
By adjusting the mV per Ampere with **setmVperAmp(float mva)** the readings can be corrected
|
||||
for this "voltage divider effect".
|
||||
|
||||
|
||||
#### Examples:
|
||||
|
||||
For a 20 A type sensor, 100 mV/A would be the normal value.
|
||||
After using a voltage divider one need to adjust the mVperAmp.
|
||||
|
||||
| R1 (ACS) | R2 (GND) | voltage factor | mVperAmp corrected |
|
||||
|:--------:|:---------:|:-------------------------------:|:-----------------------:|
|
||||
| 10200 | 4745 | 4745 / (10200 + 4745) = 0.3175 | 100 \* 0.3175 = 31.75 |
|
||||
| 4745 | 10200 | 10200 / (10200 + 4745) = 0.6825 | 100 \* 0.6825 = 68.25 |
|
||||
| 10200 | 9800 | 9800 / (10200 + 9800) = 0.4900 | 100 \* 0.4900 = 49.00 |
|
||||
|
||||
|
||||
**Note:** setting the midPoint correctly is also needed when using a voltage divider.
|
||||
|
||||
|
||||
## Disconnect detection
|
||||
|
||||
(to be tested)
|
||||
|
||||
To detect that the ACS712 is disconnected from the ADC one could connect the
|
||||
analog pin via a pull-down to GND. A pull-up to VCC is also possible.
|
||||
Choose the solution that fits your project best. (Think safety).
|
||||
|
||||
**mA_DC()** and **mA_AC_sampling()** will report HIGH values (Out of range) when
|
||||
the ACS712 is disconnected.
|
||||
The other - peak2peak based functions - will see this as zero current (min == max).
|
||||
|
||||
Schema with PULL-UP.
|
||||
```
|
||||
ACS712 OUT
|
||||
|
|
||||
|
|
||||
VCC ----[ R1 ]----o R1 = 1 M ohm.
|
||||
|
|
||||
|
|
||||
ADC of processor
|
||||
```
|
||||
|
||||
The library does not support this "extreme values" detection.
|
||||
|
||||
|
||||
## ESPhome
|
||||
|
||||
For people who want to use this library for ESPhome, there exists a wrapper
|
||||
class for this ACS712 library.
|
||||
- https://github.com/marianomd/acs712-esphome
|
||||
|
||||
As I do not have ESPhome know how, please share your experiences.
|
||||
This can be done by an issue.
|
||||
|
||||
|
||||
## Operation
|
||||
|
||||
The examples show the basic working of the functions.
|
||||
|
||||
|
||||
## Future
|
||||
|
||||
#### Must
|
||||
|
||||
- test more
|
||||
- other than the 20A module
|
||||
- 5, 10, 30, 50 ...
|
||||
- need to buy extra hardware
|
||||
|
||||
|
||||
#### Should - 0.3.x
|
||||
|
||||
- investigate **estimateMidPoint(confidence)** See issue #35
|
||||
- is less blocking by spreading the sampling over many calls.
|
||||
returning a confidence level.
|
||||
- investigate noise suppression #21 (0.3.1 and later)
|
||||
- investigate blocking calls:
|
||||
- **mA_AC()** blocks for about 20 ms at 50 Hz.
|
||||
This might affect task scheduling on a ESP32. Needs to be investigated.
|
||||
Probably need a separate thread that wakes up when new analogRead is available?
|
||||
- RTOS specific class?
|
||||
- investigate **detectFrequency(float)** blocks pretty long.
|
||||
|
||||
|
||||
#### Could
|
||||
|
||||
- merge **mA_AC()** and **mA_AC_sampling()** into one. (0.4.0)
|
||||
- or remove - depreciate - the worst one
|
||||
- add range check to (all) set functions?
|
||||
- add unit test for **autoMidPointDC()** (needed?)
|
||||
- **setMidPoint()**
|
||||
- Q: could midpoint be set beyond maxADC? is there any use case?
|
||||
|
||||
|
||||
#### Won't (unless requested)
|
||||
|
||||
- investigate support for micro-Amperes. **ACS.uA_DC()**
|
||||
- need a very stable voltage
|
||||
- needs a 24 bit ADC
|
||||
- default noise is already ~21mV...
|
||||
- => not feasible in normal setup.
|
||||
- Should the FormFactor not be just a parameter of **mA_AC()**
|
||||
it is the only function using it. ==> No unnecessary breaking API
|
||||
- should cycles be an uint8_t ?
|
||||
- No, uint16 allows averaging in minutes range uint8_t just ~5 seconds
|
||||
- midPoint can be a float so it can be set more exact.
|
||||
- extra precision is max half bit = smaller than noise?
|
||||
- math will be slower during sampling (UNO)
|
||||
- split the readme.md in multiple documents?
|
||||
- which?
|
||||
- setADC() to support > 16 bit?
|
||||
- uint32_t performance penalty?
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
If you appreciate my libraries, you can support the development and maintenance.
|
||||
Improve the quality of the libraries by providing issues and Pull Requests, or
|
||||
donate through PayPal or GitHub sponsors.
|
||||
|
||||
Thank you,
|
||||
|
||||
70
libraries/ACS712/examples/ACS712_20_AC/ACS712_20_AC.ino
Normal file
70
libraries/ACS712/examples/ACS712_20_AC/ACS712_20_AC.ino
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo AC measurement with point to point
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
|
||||
// use simulation
|
||||
ACS.setADC(signal, 5, 1024);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
Serial.print("MidPoint: ");
|
||||
Serial.print(ACS.getMidPoint());
|
||||
Serial.print(". Noise mV: ");
|
||||
Serial.println(ACS.getNoisemV());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(100);
|
||||
start = micros();
|
||||
// int mA = ACS.mA_AC();
|
||||
int mA = ACS.mA_AC_sampling();
|
||||
stop = micros();
|
||||
Serial.print("mA: ");
|
||||
Serial.print(mA);
|
||||
Serial.print(". Form factor: ");
|
||||
Serial.print(ACS.getFormFactor());
|
||||
Serial.print(" time: ");
|
||||
Serial.println(stop - start);
|
||||
delay(5000);
|
||||
}
|
||||
|
||||
|
||||
// simulated 50 Hz signal
|
||||
uint16_t signal(uint8_t p)
|
||||
{
|
||||
return 512 + 400 * sin((micros() % 1000000) * (TWO_PI * 50 / 1e6));
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_DEMO.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo to set the mVperAmpere and Form FActor.
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
int mA = ACS.mA_AC();
|
||||
Serial.println(mA);
|
||||
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
char c = Serial.read();
|
||||
|
||||
if (c == '*') ACS.setmVperAmp(ACS.getmVperAmp() + 1);
|
||||
if (c == '/') ACS.setmVperAmp(ACS.getmVperAmp() - 1);
|
||||
Serial.print("mVperAmp:\t");
|
||||
Serial.println(ACS.getmVperAmp());
|
||||
|
||||
if (c == '+') ACS.setFormFactor(ACS.getFormFactor() * 1.05);
|
||||
if (c == '-') ACS.setFormFactor(ACS.getFormFactor() / 1.05);
|
||||
Serial.print("formFactor:\t");
|
||||
Serial.println(ACS.getFormFactor());
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_SAMPLING_DEMO.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo to sample AC current and set mVPerAmpere
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
float mA = ACS.mA_AC_sampling();
|
||||
Serial.println(mA, 1);
|
||||
|
||||
while (Serial.available() > 0)
|
||||
{
|
||||
char c = Serial.read();
|
||||
|
||||
if (c == '*') ACS.setmVperAmp(ACS.getmVperAmp() + 1);
|
||||
if (c == '/') ACS.setmVperAmp(ACS.getmVperAmp() - 1);
|
||||
Serial.print("mVperAmp:\t");
|
||||
Serial.println(ACS.getmVperAmp());
|
||||
}
|
||||
delay(250);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_average.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo AC measurement with point to point + averaging
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
Serial.print("MidPoint: ");
|
||||
Serial.println(ACS.getMidPoint());
|
||||
Serial.print("Noise mV: ");
|
||||
Serial.println(ACS.getNoisemV());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
float average = 0;
|
||||
uint32_t start = millis();
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// select sppropriate function
|
||||
// average += ACS.mA_AC_sampling();
|
||||
average += ACS.mA_AC();
|
||||
}
|
||||
float mA = average / 100.0;
|
||||
uint32_t duration = millis() - start;
|
||||
Serial.print("Time: ");
|
||||
Serial.print(duration);
|
||||
Serial.print(" mA: ");
|
||||
Serial.println(mA);
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_compare.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo AC measurement comparison
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
Serial.print("MidPoint: ");
|
||||
Serial.print(ACS.getMidPoint());
|
||||
Serial.print(". Noise mV: ");
|
||||
Serial.println(ACS.getNoisemV());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
int m1 = ACS.mA_AC();
|
||||
float m2 = ACS.mA_AC_sampling();
|
||||
Serial.print("mA:\t");
|
||||
Serial.print(m1);
|
||||
Serial.print("\t\t");
|
||||
Serial.println(m2);
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_low_pass.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo AC measurement with point to point with low pass filter
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 185);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
float value = 0;
|
||||
float weight = 0.2;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
|
||||
Serial.print("MidPoint: ");
|
||||
Serial.println(ACS.getMidPoint());
|
||||
Serial.print("Noise mV: ");
|
||||
Serial.println(ACS.getNoisemV());
|
||||
Serial.print("Amp/Step: ");
|
||||
Serial.println(ACS.getAmperePerStep(), 4);
|
||||
|
||||
value = ACS.mA_AC(); // get good initial value
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// select sppropriate function
|
||||
float mA = ACS.mA_AC_sampling();
|
||||
// float mA = ACS.mA_AC();
|
||||
value += weight * (mA - value); // low pass filtering
|
||||
|
||||
Serial.print("weight: ");
|
||||
Serial.print(weight);
|
||||
Serial.print(" value: ");
|
||||
Serial.print(value, 0);
|
||||
Serial.print(" mA: ");
|
||||
Serial.print(mA);
|
||||
Serial.println();
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_midPoint_compare.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo to compare different midPoint methods.
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.println();
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
Serial.println("Compare different midPoint methods.\n");
|
||||
|
||||
Serial.print("Default: \t");
|
||||
Serial.println(ACS.getMidPoint());
|
||||
|
||||
Serial.print("AutoMP: \t");
|
||||
Serial.println(ACS.autoMidPoint());
|
||||
|
||||
uint16_t average = (ACS.getMinimum(20) + ACS.getMaximum(20)) / 2;
|
||||
ACS.setMidPoint(average);
|
||||
Serial.print("Average: \t");
|
||||
Serial.println(average);
|
||||
Serial.println();
|
||||
Serial.println("\ndone...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_midPoint_performance.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo to compare different midPoint methods.
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
float mp = 0;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.println();
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
Serial.println("Compare different midPoint methods.\n");
|
||||
|
||||
start = micros();
|
||||
mp = ACS.getMidPoint();
|
||||
stop = micros();
|
||||
Serial.print("Default: \t");
|
||||
Serial.print(mp);
|
||||
Serial.print("\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
|
||||
start = micros();
|
||||
mp = ACS.autoMidPoint();
|
||||
stop = micros();
|
||||
Serial.print("AutoMP: \t");
|
||||
Serial.print(mp);
|
||||
Serial.print("\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
|
||||
start = micros();
|
||||
uint16_t average = (ACS.getMinimum(20) + ACS.getMaximum(20)) / 2;
|
||||
stop = micros();
|
||||
Serial.print("Average: \t");
|
||||
Serial.print(average);
|
||||
Serial.print("\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
|
||||
Serial.println("\ndone...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_simulation.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo AC measurement with point to point
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
// select simulated signal
|
||||
ACS.setADC(signal, 5, 1024);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
Serial.print("MidPoint: ");
|
||||
Serial.print(ACS.getMidPoint());
|
||||
Serial.print(". Noise mV: ");
|
||||
Serial.println(ACS.getNoisemV());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(100);
|
||||
start = micros();
|
||||
// int mA = ACS.mA_AC();
|
||||
int mA = ACS.mA_AC_sampling(50);
|
||||
stop = micros();
|
||||
Serial.print("mA: ");
|
||||
Serial.print(mA);
|
||||
Serial.print(" time: ");
|
||||
Serial.println(stop - start);
|
||||
delay(5000);
|
||||
}
|
||||
|
||||
|
||||
// simulation.
|
||||
uint16_t signal(uint8_t p)
|
||||
{
|
||||
return round(512 + 400 * sin((micros() % 1000000) * (TWO_PI * 50 / 1e6)));
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC_suppress_noise.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo AC measurement with point to point
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
|
||||
Serial.print("MidPoint: ");
|
||||
Serial.print(ACS.getMidPoint());
|
||||
Serial.print(". Noise mV: ");
|
||||
Serial.println(ACS.getNoisemV());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
ACS.suppressNoise(false);
|
||||
Serial.println("\nFALSE");
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Serial.print(ACS.mA_AC());
|
||||
Serial.print("\t");
|
||||
Serial.print(ACS.mA_AC_sampling());
|
||||
Serial.print("\t");
|
||||
Serial.print(ACS.mA_peak2peak());
|
||||
Serial.print("\t");
|
||||
Serial.println();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
ACS.suppressNoise(true);
|
||||
Serial.println("\nTRUE");
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Serial.print(ACS.mA_AC());
|
||||
Serial.print("\t");
|
||||
Serial.print(ACS.mA_AC_sampling());
|
||||
Serial.print("\t");
|
||||
Serial.print(ACS.mA_peak2peak());
|
||||
Serial.print("\t");
|
||||
Serial.println();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
44
libraries/ACS712/examples/ACS712_20_DC/ACS712_20_DC.ino
Normal file
44
libraries/ACS712/examples/ACS712_20_DC/ACS712_20_DC.ino
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// FILE: ACS712_20_DC.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo to measure mA DC
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
// use with Arduino Serial Plotter
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
// Serial.println(ACS.getMidPoint());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
int mA = ACS.mA_DC();
|
||||
Serial.println(mA);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// FILE: ACS712_20_DC_DEMO.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo to set the midPoint and the mVperAmpere.
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
int mA = ACS.mA_DC();
|
||||
Serial.println(mA);
|
||||
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
char c = Serial.read();
|
||||
if (c == '+') ACS.incMidPoint();
|
||||
if (c == '-') ACS.decMidPoint();
|
||||
if (c == '0') ACS.setMidPoint(512);
|
||||
Serial.println(ACS.getMidPoint());
|
||||
|
||||
if (c == '*') ACS.setmVperAmp(ACS.getmVperAmp() * 1.05);
|
||||
if (c == '/') ACS.setmVperAmp(ACS.getmVperAmp() / 1.05);
|
||||
Serial.println(ACS.getmVperAmp());
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// FILE: ACS712_20_DC_external_ADC.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo to measure mA DC with external ADC
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
// use with Arduino Serial Plotter
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.setADC(testADC, 10, 1023);
|
||||
|
||||
// ACS.autoMidPoint();
|
||||
// Serial.println(ACS.getMidPoint());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
int mA = ACS.mA_DC();
|
||||
Serial.println(mA);
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// wrapper needed for external analogRead()
|
||||
// as casting behavior is undefined between different function signatures.
|
||||
uint16_t testADC(uint8_t p)
|
||||
{
|
||||
// simulation
|
||||
return 600 + p;
|
||||
// replace with an external ADC call.
|
||||
// return ADS.readADC(p);
|
||||
// return analogRead(p + 1); // use another internal ADC
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// FILE: ACS712_20_determine_form_factor.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo to determine form factor
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
int i = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
ACS.autoMidPoint();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
Serial.println("\n\nAC \tP2P \tCREST");
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
float mA_1 = ACS.mA_AC_sampling();
|
||||
float mA_2 = ACS.mA_peak2peak();
|
||||
float crest = 2.0 * mA_1 / mA_2;
|
||||
Serial.print(mA_1);
|
||||
Serial.print("\t");
|
||||
Serial.print(mA_2);
|
||||
Serial.print("\t");
|
||||
Serial.println(crest, 4);
|
||||
delay(100);
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// FILE: ACS712_20_mV_noise_level.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo AC measurement with point to point
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
ACS.autoMidPoint();
|
||||
Serial.println();
|
||||
Serial.print(" MidPoint: ");
|
||||
Serial.println(ACS.getMidPoint());
|
||||
Serial.print("Config Noise mV: ");
|
||||
Serial.println(ACS.getNoisemV());
|
||||
Serial.print("Detect Noise mV: ");
|
||||
Serial.println(ACS.mVNoiseLevel(), 1);
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// FILE: ACS712_20_AC.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo AC measurement with point to point
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DISPLAY
|
||||
//
|
||||
#include <Wire.h>
|
||||
#include <LCD.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
#define BACKLIGHT_PIN 3
|
||||
#define En_pin 2
|
||||
#define Rw_pin 1
|
||||
#define Rs_pin 0
|
||||
#define D4_pin 4
|
||||
#define D5_pin 5
|
||||
#define D6_pin 6
|
||||
#define D7_pin 7
|
||||
|
||||
#define BL_OFF 0
|
||||
#define BL_ON 1
|
||||
|
||||
#define DISPLAY_ADDR 0x3F // check
|
||||
|
||||
LiquidCrystal_I2C lcd(DISPLAY_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
|
||||
uint32_t lastDisplay = 0;
|
||||
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
|
||||
|
||||
ACS712 ACS(A0, 5.0, 1023, 185);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
|
||||
lcd.begin(16, 2);
|
||||
lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
|
||||
lcd.setBacklight(BL_ON);
|
||||
|
||||
lcd.clear();
|
||||
|
||||
|
||||
ACS.autoMidPoint();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
lcd.clear();
|
||||
|
||||
float f1 = ACS.mA_AC();
|
||||
float f2 = ACS.mA_AC_sampling();
|
||||
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print("mA: ");
|
||||
lcd.print(f1, 1);
|
||||
|
||||
lcd.setCursor(10, 0);
|
||||
lcd.print(f2, 1);
|
||||
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print("FF: ");
|
||||
lcd.print(f1 / f2);
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// FILE: ACS712_autoMidPointDC.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo detect DC midpoint.
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
uint16_t midPoint = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
delay(10);
|
||||
|
||||
// might be different 1 cycle or 100.
|
||||
start = micros();
|
||||
midPoint = ACS.autoMidPointDC(1);
|
||||
stop = micros();
|
||||
Serial.println("ACS.autoMidPointDC()");
|
||||
Serial.print("us:\t");
|
||||
Serial.println(stop - start);
|
||||
Serial.print("MP 1:\t");
|
||||
Serial.println(midPoint);
|
||||
|
||||
midPoint = ACS.autoMidPointDC(100);
|
||||
Serial.print("MP 100:\t");
|
||||
Serial.println(midPoint);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FILE: ACS712_detectFrequency.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo detect frequency + timing indication.
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
|
||||
// Arduino UNO has 5.0 volt with a max ADC value of 1023 steps
|
||||
// ACS712 5A uses 185 mV per A
|
||||
// ACS712 20A uses 100 mV per A
|
||||
// ACS712 30A uses 66 mV per A
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
// ESP 32 example (might requires resistors to step down the logic voltage)
|
||||
// ACS712 ACS(25, 3.3, 4095, 185);
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ACS712_LIB_VERSION: ");
|
||||
Serial.println(ACS712_LIB_VERSION);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// e.g. detect 50 or 60 Hz sinus signal
|
||||
// blocks on bad signals.
|
||||
start = micros();
|
||||
float frequency = ACS.detectFrequency(45);
|
||||
stop = micros();
|
||||
|
||||
Serial.print(stop - start);
|
||||
Serial.print("\t");
|
||||
Serial.println(frequency, 1);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// FILE: RMS_by_sampling.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2022-08-15
|
||||
// PURPOSE: demo RMS by sampling for AC current
|
||||
// URL: https://github.com/RobTillaart/ACS712
|
||||
//
|
||||
// stand alone sketch to be used with a ACS712
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
// #include "printHelpers.h"
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// 50 Hz, Arduino UNO, 20A ACS
|
||||
float current = mA_AC_sampling(50, 5000.0 / 1023, 100, A0);
|
||||
Serial.println(current);
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
float mA_AC_sampling(float frequency, float mVperStep, float mVperAmpere, uint8_t analogPin)
|
||||
{
|
||||
uint16_t midpoint = 511;
|
||||
uint32_t period = round(1000000UL / frequency);
|
||||
uint16_t samples = 0;
|
||||
float sumSquared = 0;
|
||||
|
||||
uint32_t start = micros();
|
||||
while (micros() - start < period)
|
||||
{
|
||||
samples++;
|
||||
float current = analogRead(analogPin) - midpoint;
|
||||
sumSquared += (current * current);
|
||||
}
|
||||
// Serial.print(scieng(sumSquared, 1, 3));
|
||||
// Serial.print("\t");
|
||||
// Serial.print(samples);
|
||||
// Serial.print("\t");
|
||||
float AmperePerStep = mVperStep / mVperAmpere;
|
||||
float RMS = sqrt(sumSquared / samples) * AmperePerStep;
|
||||
return RMS * 1000.0; // mA
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
@@ -0,0 +1,89 @@
|
||||
// FILE: estimateMidPointAC.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: experimental
|
||||
// URL: https://github.com/RobTillaart/ACS712/issues/37
|
||||
//
|
||||
// Estimates the midpoint by taking many (short-blocking) samples
|
||||
// instead of many samples in a long blocking period.
|
||||
// The function adjusts the confidence (or quality) of the midpoint
|
||||
// depending on the value read.
|
||||
// This code is experimental and meant to investigate a non-blocking
|
||||
// way to find the midPoint for the ACS712 when measuring AC currents.
|
||||
//
|
||||
// It will not be included in the library
|
||||
//
|
||||
// Use with care.
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
|
||||
uint32_t start, stop;
|
||||
int _pin = A0;
|
||||
uint32_t count = 0;
|
||||
volatile uint16_t mp;
|
||||
float conf = 0;
|
||||
|
||||
|
||||
uint16_t estimateMidPointAC(float &confidence, bool reset = false)
|
||||
{
|
||||
static bool _firstCall = true;
|
||||
static float _minimum, _maximum, _confidence;
|
||||
|
||||
int value = analogRead(_pin);
|
||||
if (_firstCall || reset)
|
||||
{
|
||||
_firstCall = false;
|
||||
_minimum = _maximum = value;
|
||||
_confidence = 0;
|
||||
confidence = _confidence;
|
||||
return _minimum;
|
||||
}
|
||||
if (value > _maximum)
|
||||
{
|
||||
_maximum = value;
|
||||
_confidence /= 2;
|
||||
}
|
||||
else if (value < _minimum)
|
||||
{
|
||||
_minimum = value;
|
||||
_confidence /= 2;
|
||||
}
|
||||
else if (_confidence < 100)
|
||||
{
|
||||
_confidence += 1;
|
||||
}
|
||||
confidence = _confidence;
|
||||
return (_minimum + _maximum) / 2;
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
count++;
|
||||
start = micros();
|
||||
mp = estimateMidPointAC(conf, true);
|
||||
stop = micros();
|
||||
Serial.print(millis());
|
||||
Serial.print("\t");
|
||||
Serial.print(count);
|
||||
Serial.print("\t");
|
||||
Serial.print(conf);
|
||||
Serial.print("\t");
|
||||
Serial.print(mp);
|
||||
Serial.print("\t");
|
||||
Serial.print(stop - start);
|
||||
Serial.println();
|
||||
delay(random(100));
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
53
libraries/ACS712/keywords.txt
Normal file
53
libraries/ACS712/keywords.txt
Normal file
@@ -0,0 +1,53 @@
|
||||
# Syntax Colouring Map For ACS712
|
||||
|
||||
# Data types (KEYWORD1)
|
||||
ACS712 KEYWORD1
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
mA_peak2peak KEYWORD2
|
||||
mA_AC KEYWORD2
|
||||
mA_DC KEYWORD2
|
||||
mA_AC_sampling KEYWORD2
|
||||
|
||||
setMidPoint KEYWORD2
|
||||
getMidPoint KEYWORD2
|
||||
incMidPoint KEYWORD2
|
||||
decMidPoint KEYWORD2
|
||||
resetMidPoint KEYWORD2
|
||||
autoMidPoint KEYWORD2
|
||||
autoMidPointDC KEYWORD2
|
||||
|
||||
setFormFactor KEYWORD2
|
||||
getFormFactor KEYWORD2
|
||||
|
||||
setNoisemV KEYWORD2
|
||||
getNoisemV KEYWORD2
|
||||
mVNoiseLevel KEYWORD2
|
||||
suppressNoise KEYWORD2
|
||||
|
||||
setmVperAmp KEYWORD2
|
||||
getmVperAmp KEYWORD2
|
||||
getmAPerStep KEYWORD2
|
||||
getAmperePerStep KEYWORD2
|
||||
|
||||
detectFrequency KEYWORD2
|
||||
setMicrosAdjust KEYWORD2
|
||||
getMicrosAdjust KEYWORD2
|
||||
|
||||
getMinimum KEYWORD2
|
||||
getMaximum KEYWORD2
|
||||
|
||||
setADC KEYWORD2
|
||||
|
||||
|
||||
# Constants (LITERAL1)
|
||||
ACS712_LIB_VERSION LITERAL1
|
||||
|
||||
ACS712_FF_SINUS LITERAL1
|
||||
ACS712_FF_SQUARE LITERAL1
|
||||
ACS712_FF_TRIANGLE LITERAL1
|
||||
ACS712_FF_SAWTOOTH LITERAL1
|
||||
|
||||
ACS712_DEFAULT_FREQ LITERAL1
|
||||
ACS712_DEFAULT_NOISE LITERAL1
|
||||
|
||||
29
libraries/ACS712/library.json
Normal file
29
libraries/ACS712/library.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "ACS712",
|
||||
"keywords": "ACS712, Current, 5A, 20A, 30A",
|
||||
"description": "ACS712 library for Arduino. ",
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
"name": "Rob Tillaart",
|
||||
"email": "Rob.Tillaart@gmail.com",
|
||||
"maintainer": true
|
||||
},
|
||||
{
|
||||
"name": "Pete Thompson",
|
||||
"email": "pete.thompson@yahoo.com",
|
||||
"maintainer": false
|
||||
}
|
||||
|
||||
],
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/ACS712.git"
|
||||
},
|
||||
"version": "0.3.8",
|
||||
"license": "MIT",
|
||||
"frameworks": "*",
|
||||
"platforms": "*",
|
||||
"headers": "ACS712.h"
|
||||
}
|
||||
11
libraries/ACS712/library.properties
Normal file
11
libraries/ACS712/library.properties
Normal file
@@ -0,0 +1,11 @@
|
||||
name=ACS712
|
||||
version=0.3.8
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>, Pete Thompson <pete.thompson@yahoo.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=ACS712 library for Arduino.
|
||||
paragraph=Current measurement, tested with RobotDyn ACDC 20A Module.
|
||||
category=Signal Input/Output
|
||||
url=https://github.com/RobTillaart/ACS712
|
||||
architectures=*
|
||||
includes=ACS712.h
|
||||
depends=
|
||||
215
libraries/ACS712/test/unit_test_001.cpp
Normal file
215
libraries/ACS712/test/unit_test_001.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
//
|
||||
// FILE: unit_test_001.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2020-12-06
|
||||
// PURPOSE: unit tests for the ACS712 current sensor
|
||||
// https://github.com/RobTillaart/ACS712
|
||||
// https://www.adafruit.com/product/2857
|
||||
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
|
||||
//
|
||||
|
||||
// supported assertions
|
||||
// ----------------------------
|
||||
// assertEqual(expected, actual)
|
||||
// assertNotEqual(expected, actual)
|
||||
// assertLess(expected, actual)
|
||||
// assertMore(expected, actual)
|
||||
// assertLessOrEqual(expected, actual)
|
||||
// assertMoreOrEqual(expected, actual)
|
||||
// assertTrue(actual)
|
||||
// assertFalse(actual)
|
||||
// assertNull(actual)
|
||||
|
||||
|
||||
#include <ArduinoUnitTests.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "ACS712.h"
|
||||
|
||||
#define A0 0
|
||||
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
fprintf(stderr, "ACS712_LIB_VERSION: %s\n", (char *) ACS712_LIB_VERSION);
|
||||
}
|
||||
|
||||
unittest_teardown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constants)
|
||||
{
|
||||
assertEqualFloat(1.0/sqrt(2), ACS712_FF_SINUS, 0.001);
|
||||
assertEqualFloat(1.0, ACS712_FF_SQUARE, 0.001);
|
||||
assertEqualFloat(1.0/sqrt(3), ACS712_FF_TRIANGLE, 0.001);
|
||||
assertEqualFloat(1.0/sqrt(3), ACS712_FF_SAWTOOTH, 0.001);
|
||||
|
||||
assertEqual(21, ACS712_DEFAULT_NOISE);
|
||||
assertEqual(50, ACS712_DEFAULT_FREQ);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mA_DC)
|
||||
{
|
||||
GodmodeState* state = GODMODE();
|
||||
state->reset();
|
||||
|
||||
// 0 == A0
|
||||
ACS712 ACS(0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
|
||||
|
||||
// assertEqual(0, ACS.mA_AC(50));
|
||||
// assertEqual(0, ACS.mA_AC(60));
|
||||
int future[12] = {0, 0, 100, 100, 200, 200, 511, 511, 900, 900, 1023, 1023};
|
||||
state->analogPin[0].fromArray(future, 12);
|
||||
|
||||
assertEqualFloat(-24975.6, ACS.mA_DC(), 1);
|
||||
assertEqualFloat(-20088.0, ACS.mA_DC(), 1);
|
||||
assertEqualFloat(-15200.4, ACS.mA_DC(), 1);
|
||||
assertEqualFloat(0.0, ACS.mA_DC(), 1);
|
||||
assertEqualFloat( 19012.7, ACS.mA_DC(), 1);
|
||||
assertEqualFloat( 25024.4, ACS.mA_DC(), 1);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mA_AC)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
|
||||
|
||||
// loop with micros and a lot of analogReads - not possible
|
||||
// assertEqual(0, ACS.mA_AC(50));
|
||||
// assertEqual(0, ACS.mA_AC(60));
|
||||
assertEqual(1, 1);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mA_AC_samples)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
|
||||
|
||||
// loop with micros and a lot (150?) of analogReads - not possible
|
||||
// assertEqual(0, ACS.mA_AC_samples(50));
|
||||
// assertEqual(0, ACS.mA_AC_samples(60));
|
||||
assertEqual(1, 1);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_midPoint)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
|
||||
|
||||
// loop with micros and a lot of analogReads - not possible
|
||||
// ACS.autoMidPoint(50);
|
||||
// uint16_t amp50 = ACS.getMidPoint();
|
||||
// assertEqual(0, amp50);
|
||||
//
|
||||
// ACS.autoMidPoint(60);
|
||||
// uint16_t amp60 = ACS.getMidPoint();
|
||||
// assertEqual(0, amp60);
|
||||
|
||||
uint16_t amp = ACS.getMidPoint();
|
||||
assertEqual(511, amp);
|
||||
|
||||
ACS.setMidPoint(1000);
|
||||
amp = ACS.getMidPoint();
|
||||
assertEqual(1000, amp);
|
||||
|
||||
ACS.incMidPoint();
|
||||
amp = ACS.getMidPoint();
|
||||
assertEqual(1001, amp);
|
||||
|
||||
ACS.decMidPoint();
|
||||
amp = ACS.getMidPoint();
|
||||
assertEqual(1000, amp);
|
||||
|
||||
ACS.decMidPoint();
|
||||
amp = ACS.getMidPoint();
|
||||
assertEqual(999, amp);
|
||||
|
||||
ACS.resetMidPoint();
|
||||
amp = ACS.getMidPoint();
|
||||
assertEqual(511, amp);
|
||||
|
||||
// test range ends
|
||||
ACS.setMidPoint(1023);
|
||||
amp = ACS.incMidPoint();
|
||||
assertEqual(1023, amp);
|
||||
|
||||
ACS.setMidPoint(0);
|
||||
amp = ACS.decMidPoint();
|
||||
assertEqual(0, amp);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_formFactor)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
|
||||
// default 0.5 * sqrt(2)
|
||||
float ff = ACS.getFormFactor();
|
||||
float eff = 0.5 * sqrt(2);
|
||||
float delta = abs(eff - ff);
|
||||
assertMoreOrEqual(0.0001, delta);
|
||||
|
||||
ACS.setFormFactor(0.8);
|
||||
ff = ACS.getFormFactor();
|
||||
eff = 0.8;
|
||||
delta = abs(eff - ff);
|
||||
assertMoreOrEqual(0.0001, delta);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_Noise)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
|
||||
int nmv = ACS.getNoisemV();
|
||||
assertEqual(21, nmv); // default value..
|
||||
|
||||
ACS.setNoisemV(100);
|
||||
nmv = ACS.getNoisemV();
|
||||
assertEqual(100, nmv);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mVperAmp)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
|
||||
float mpa = ACS.getmVperAmp();
|
||||
assertEqualFloat(100, mpa, 0.001); // default value..
|
||||
|
||||
float mva = 25.0;
|
||||
while (mva < 200)
|
||||
{
|
||||
ACS.setmVperAmp(mva);
|
||||
mpa = ACS.getmVperAmp();
|
||||
assertEqualFloat(mva, mpa, 0.001);
|
||||
mva += 24.8; // just a bit random adjustments
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest(test_AmperePerStep)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
|
||||
float aps = ACS.getAmperePerStep();
|
||||
assertEqualFloat(0.047885, aps, 0.001);
|
||||
|
||||
float mva = 25.0;
|
||||
while (mva < 200)
|
||||
{
|
||||
ACS.setmVperAmp(mva);
|
||||
aps = ACS.getAmperePerStep();
|
||||
assertEqualFloat(5000.0/1023/mva, aps, 0.001);
|
||||
mva += 24;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
BIN
libraries/ADS1115_WE/ADS1115_ATtiny_Test_Wiring.png
Normal file
BIN
libraries/ADS1115_WE/ADS1115_ATtiny_Test_Wiring.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 270 KiB |
BIN
libraries/ADS1115_WE/ADS1115_Test_Wiring.png
Normal file
BIN
libraries/ADS1115_WE/ADS1115_Test_Wiring.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 262 KiB |
21
libraries/ADS1115_WE/LICENSE
Normal file
21
libraries/ADS1115_WE/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Wolfgang (Wolle) Ewald
|
||||
|
||||
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.
|
||||
BIN
libraries/ADS1115_WE/List of public functions ADS1115.pdf
Normal file
BIN
libraries/ADS1115_WE/List of public functions ADS1115.pdf
Normal file
Binary file not shown.
37
libraries/ADS1115_WE/README.md
Normal file
37
libraries/ADS1115_WE/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# ADS1115_WE
|
||||
|
||||
An Arduino library for the 16-bit, 4-channel ADS1115 and the 12-Bit, 4-channel ADS1015 ADC with gain and alert functions.
|
||||
|
||||
I have have tried to optimize the library for convenience to use. If you try the examples I recommend to start with `Single_Shot.ino`.
|
||||
|
||||
You can find more details here:
|
||||
|
||||
https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
|
||||
https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
|
||||
All features of the ADS1115 and ADS1015 are implemented, including alert functions.
|
||||
|
||||
The examples are written for the ADS1115 with one exception, which is Continuous_ADS1015.ino. This shows how to "translate" the sketches
|
||||
for the ADS1015. Most enum values like ADS1115_RANGE_6144 and ADS1015_RANGE_6144 are even identical. The exceptions are the enum values for
|
||||
the conversion rate.
|
||||
|
||||
In version 1.4.1 I have implemented the option to use TinyWireM instead of Wire. Therefore the library can be used, for example, on
|
||||
an ATtiny85.
|
||||
|
||||
Since version 1.3.0 I have added a feature to the continuous mode, which ensures that you can change channels safely without risking that the
|
||||
first data read is still from the former channel. If you experienced this issue, you might have solved it with a delay. If this applies to
|
||||
you, you can delete the delays.
|
||||
|
||||
If you like the library it would be cool if you can give it a star. If you find bugs, please inform me.
|
||||
|
||||
<h2>Beware of fake modules</h2>
|
||||
|
||||
There are ADS1115 modules which use ADS1015 ICs and also there are ADS1015 modules which are based on ADS1115 ICs. In theory you should
|
||||
recognize the IC by its label which is "BRPI" for the ADS1015 and "BOGI" for the ADS1115. But I have even found ADS1115 ICs labeled with
|
||||
"BRPI" which is definitely a fake. The difference between the ADS1115 and the ADS1015 is a) the 16-bit vs. 12-bit resolution an b) the speed.
|
||||
|
||||
If you want to find out what you really have on on your module, then try the example sketch "Who_Am_I.ino". Do not change anything apart from
|
||||
the I2C address if necessary.
|
||||
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how you can use the alert pin to compare with limits. I
|
||||
* have chosen the window mode. You can also try the max limit (traditional)
|
||||
* mode. You can change the mode with the function setAlertModeAndLimit_V
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
volatile int interruptPin = 2;
|
||||
int ledPin = 10;
|
||||
volatile bool outOfLimit = false;
|
||||
|
||||
/* There are several ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
|
||||
pinMode(interruptPin, INPUT_PULLUP);
|
||||
pinMode(ledPin, OUTPUT);
|
||||
digitalWrite(ledPin, LOW);
|
||||
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change parameter to change range
|
||||
|
||||
/* Set number of conversions out of limit after which alert pin asserts
|
||||
* - or you can disable the alert (including conversion ready alert)
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); // alternative: ...AFTER_2 or 4. If you disable this sketch does not work
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
//adc.setConvRate(ADS1115_8_SPS); //uncomment if you want to change the default
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
adc.setMeasureMode(ADS1115_CONTINUOUS); //comment or change you want to change to single shot
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in volts - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion is cleared
|
||||
* again (if not latched!)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*
|
||||
*/
|
||||
adc.setAlertModeAndLimit_V(ADS1115_WINDOW, 3.0, 1.5); //you can change modes / limits
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will assert until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion
|
||||
* will be cleared with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
//adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin will assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
//adc.setAlertPinToConversionReady(); //uncomment if you want to change the default
|
||||
|
||||
Serial.println("ADS1115 Example Sketch - uses the Alert Pin / Window Mode");
|
||||
Serial.println();
|
||||
Serial.println("Waiting for Value out of Limit");
|
||||
attachInterrupt(digitalPinToInterrupt(interruptPin), outOfLimitAlert, FALLING);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
if(outOfLimit){
|
||||
voltage = adc.getResult_V();
|
||||
Serial.print("Voltage [V]: ");
|
||||
Serial.println(voltage);
|
||||
digitalWrite(ledPin,HIGH);
|
||||
delay(1000);
|
||||
digitalWrite(ledPin,LOW);
|
||||
outOfLimit = false;
|
||||
attachInterrupt(digitalPinToInterrupt(interruptPin), outOfLimitAlert, FALLING);
|
||||
}
|
||||
}
|
||||
|
||||
void outOfLimitAlert(){
|
||||
detachInterrupt(interruptPin);
|
||||
outOfLimit = true;
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how you can use the alert pin with the latch function. The
|
||||
* only difference to Alert_Window_Mode.ino is that latch is enabled (line 113)
|
||||
* and that the alert needs to be cleared (line 144). Try and see the difference.
|
||||
* As an alternative to the unlatchAlertPin function you can use getResult_V.
|
||||
* Internally clearAlert just performs a read of the conversion register.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
volatile int interruptPin = 2;
|
||||
int ledPin = 10;
|
||||
volatile bool outOfLimit = false;
|
||||
|
||||
/* There are several ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
|
||||
pinMode(interruptPin, INPUT_PULLUP);
|
||||
pinMode(ledPin, OUTPUT);
|
||||
digitalWrite(ledPin, LOW);
|
||||
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND); //uncomment if you want to change the default
|
||||
|
||||
/* Set number of conversions out of limit after which the alert pin will assert
|
||||
* - or you can disable the alert (including conversion ready alert)
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); // you can also choose ...AFTER_2 or 4 for this sketch
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
//adc.setConvRate(ADS1115_8_SPS); //uncomment if you want to change the default
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
adc.setMeasureMode(ADS1115_CONTINUOUS); //comment or change if you want to change single shot
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in volts - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion will be cleared
|
||||
* again (if not latched!)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*
|
||||
*/
|
||||
adc.setAlertModeAndLimit_V(ADS1115_WINDOW, 3.0, 1.5); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will be active until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion
|
||||
* will be cleared with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin will assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
//adc.setAlertPinToConversionReady(); //uncomment if you want to change the default
|
||||
|
||||
Serial.println("ADS1115 Example Sketch - uses the Alert Pin / Window Mode / Latch enabled");
|
||||
Serial.println();
|
||||
Serial.println("Waiting for Value out of Limit");
|
||||
attachInterrupt(digitalPinToInterrupt(interruptPin), outOfLimitAlert, FALLING);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
if(outOfLimit){
|
||||
voltage = adc.getResult_V();
|
||||
Serial.print("Voltage [V]: ");
|
||||
Serial.println(voltage);
|
||||
digitalWrite(ledPin,HIGH);
|
||||
delay(1000);
|
||||
digitalWrite(ledPin,LOW);
|
||||
outOfLimit = false;
|
||||
attachInterrupt(digitalPinToInterrupt(interruptPin), outOfLimitAlert, FALLING);
|
||||
adc.clearAlert(); // unlatches the alert Pin (alternatively use getResult_V)
|
||||
}
|
||||
}
|
||||
|
||||
void outOfLimitAlert(){
|
||||
detachInterrupt(interruptPin);
|
||||
outOfLimit = true;
|
||||
}
|
||||
194
libraries/ADS1115_WE/examples/Auto_Range/Auto_Range.ino
Normal file
194
libraries/ADS1115_WE/examples/Auto_Range/Auto_Range.ino
Normal file
@@ -0,0 +1,194 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how to use the Auto Range function of the AD1115_WE library.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
|
||||
/* There are several ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change parameter to change channel
|
||||
|
||||
/* Set number of conversions after which the alert pin asserts
|
||||
* - or you can disable the alert
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
//adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); //uncomment if you want to change the default
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
adc.setConvRate(ADS1115_64_SPS); //uncomment if you want to change the default
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
adc.setMeasureMode(ADS1115_CONTINUOUS); //comment line/change parameter to change mode
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in Volt - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion will be
|
||||
* cleared (if not latched)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*
|
||||
*/
|
||||
//adc.setAlertModeAndLimit_V(ADS1115_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will assert until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion will be
|
||||
* cleared with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
//adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin will assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
//adc.setAlertPinToConversionReady(); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable permanent automatic range selection mode. If enabled, the range will
|
||||
* change if the measured values are outside of 30-80% of the maximum value of the current
|
||||
* range.
|
||||
* !!! Use EITHER this function once OR setAutoRange() whenever needed (see below) !!!
|
||||
*/
|
||||
adc.setPermanentAutoRangeMode(true);
|
||||
|
||||
Serial.println("ADS1115 Example Sketch - Continuous Mode with Auto Range");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.print("Channel 0 - ");
|
||||
readChannel(ADS1115_COMP_0_GND);
|
||||
|
||||
Serial.print("Channel 1 - ");
|
||||
readChannel(ADS1115_COMP_1_GND);
|
||||
|
||||
Serial.print("Channel 2 - ");
|
||||
readChannel(ADS1115_COMP_2_GND);
|
||||
|
||||
Serial.print("Channel 3 - ");
|
||||
readChannel(ADS1115_COMP_3_GND);
|
||||
|
||||
Serial.println("-------------------------------");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void readChannel(ADS1115_MUX channel) {
|
||||
float voltage = 0.0;
|
||||
adc.setCompareChannels(channel);
|
||||
|
||||
/* setAutoRange() switches to the highest range (+/- 6144 mV), measures the current
|
||||
* voltage and then switches to the lowest range where the current value is still
|
||||
* below 80% of the maximum value of the range. The function is only suitable if you
|
||||
* expect stable or slowly changing voltages. setAutoRange needs roughly the time you
|
||||
* would need for three conversions.
|
||||
* If the ADS115 is in single shot mode, setAutoRange() will switch into continuous
|
||||
* mode to measure a value and switch back again.
|
||||
* !!! Use EITHER this function whenever needed OR setPermanentAutoRangeMode(true) once !!!
|
||||
*/
|
||||
//adc.setAutoRange(); //use either this or setPermanentAutoRangeMode(true)
|
||||
|
||||
voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
|
||||
printVoltageRange(); // this is just to show that the range is changing with changing voltages
|
||||
Serial.println(voltage);
|
||||
}
|
||||
|
||||
void printVoltageRange(){
|
||||
unsigned int voltageRange = adc.getVoltageRange_mV();
|
||||
Serial.print("Range: ");
|
||||
|
||||
switch(voltageRange){
|
||||
case 6144:
|
||||
Serial.print("+/- 6144 mV, Voltage [V]: ");
|
||||
break;
|
||||
case 4096:
|
||||
Serial.print("+/- 4096 mV, Voltage [V]: ");
|
||||
break;
|
||||
case 2048:
|
||||
Serial.print("+/- 2048 mV, Voltage [V]: ");
|
||||
break;
|
||||
case 1024:
|
||||
Serial.print("+/- 1024 mV, Voltage [V]: ");
|
||||
break;
|
||||
case 512:
|
||||
Serial.print("+/- 512 mV, Voltage [V]: ");
|
||||
break;
|
||||
case 256:
|
||||
Serial.print("+/- 256 mV, Voltage [V]: ");
|
||||
break;
|
||||
default:
|
||||
Serial.println("Something went wrong");
|
||||
}
|
||||
}
|
||||
162
libraries/ADS1115_WE/examples/Continuous/Continuous.ino
Normal file
162
libraries/ADS1115_WE/examples/Continuous/Continuous.ino
Normal file
@@ -0,0 +1,162 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how to use the ADS1115 in continuous mode.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
|
||||
/* There are several ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change parameter to change channel
|
||||
|
||||
/* Set number of conversions after which the alert pin asserts
|
||||
* - or you can disable the alert
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
//adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); //uncomment if you want to change the default
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
// adc.setConvRate(ADS1115_8_SPS); //uncomment if you want to change the default
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
adc.setMeasureMode(ADS1115_CONTINUOUS); //comment line/change parameter to change mode
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in Volt - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion will be
|
||||
* cleared (if not latched)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*
|
||||
*/
|
||||
//adc.setAlertModeAndLimit_V(ADS1115_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will assert until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion will be
|
||||
* cleared with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
//adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin will assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
//adc.setAlertPinToConversionReady(); //uncomment if you want to change the default
|
||||
|
||||
Serial.println("ADS1115 Example Sketch - Continuous Mode");
|
||||
Serial.println("All values in volts");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
/* If you change the compare channels you can immediately read values from the conversion
|
||||
* register, although they might belong to the former channel if no precautions are taken.
|
||||
* It takes about the time needed for two conversions to get the correct data. In single
|
||||
* shot mode you can use the isBusy() function to wait for data from the new channel. This
|
||||
* does not work in continuous mode.
|
||||
* To solve this issue the library adds a delay after change of channels if you are in contunuous
|
||||
* mode. The length of the delay is adjusted to the conversion rate. But be aware that the output
|
||||
* rate will be much lower that the conversion rate if you change channels frequently.
|
||||
*/
|
||||
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
|
||||
Serial.print("0: ");
|
||||
voltage = readChannel(ADS1115_COMP_0_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 1: ");
|
||||
voltage = readChannel(ADS1115_COMP_1_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 2: ");
|
||||
voltage = readChannel(ADS1115_COMP_2_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 3: ");
|
||||
voltage = readChannel(ADS1115_COMP_3_GND);
|
||||
Serial.println(voltage);
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
float readChannel(ADS1115_MUX channel) {
|
||||
float voltage = 0.0;
|
||||
adc.setCompareChannels(channel);
|
||||
voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
|
||||
return voltage;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1015_WE library
|
||||
*
|
||||
* This sketch shows how to use the ADS1015 in continuous mode.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1015_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
|
||||
/* There are several ways to create your ADS1015_WE object:
|
||||
* ADS1015_WE adc = ADS1015_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1015_WE adc = ADS1015_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1015_WE adc = ADS1015_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1015_WE adc = ADS1015_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1015_WE adc = ADS1015_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
bool useADS1015 = true;
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
if(!adc.init(useADS1015)){ // passing true will tell the lib that an ADS1015 is used
|
||||
Serial.println("ADS1015 not connected!");
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1015_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1015_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1015_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1015_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1015_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1015_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1015_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1015_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1015_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1015_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1015_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1015_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1015_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1015_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1015_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
adc.setCompareChannels(ADS1015_COMP_0_GND); //comment line/change parameter to change channel
|
||||
|
||||
/* Set number of conversions after which the alert pin asserts
|
||||
* - or you can disable the alert
|
||||
*
|
||||
* ADS1015_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1015_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1015_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1015_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
//adc.setAlertPinMode(ADS1015_ASSERT_AFTER_1); //uncomment if you want to change the default
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1015_128_SPS
|
||||
* ADS1015_250_SPS
|
||||
* ADS1015_490_SPS
|
||||
* ADS1015_920_SPS
|
||||
* ADS1015_1600_SPS (default)
|
||||
* ADS1015_2400_SPS
|
||||
* ADS1015_3300_SPS
|
||||
*/
|
||||
//adc.setConvRate(ADS1015_3300_SPS); //uncomment if you want to change the default
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1015_CONTINUOUS -> continuous mode
|
||||
* ADS1015_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
adc.setMeasureMode(ADS1015_CONTINUOUS); //comment line/change parameter to change mode
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in Volt - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion will be
|
||||
* cleared (if not latched)
|
||||
*
|
||||
* ADS1015_MAX_LIMIT
|
||||
* ADS1015_WINDOW
|
||||
*
|
||||
*/
|
||||
//adc.setAlertModeAndLimit_V(ADS1015_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will assert until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion will be
|
||||
* cleared with next value within limits.
|
||||
*
|
||||
* ADS1015_LATCH_DISABLED (default)
|
||||
* ADS1015_LATCH_ENABLED
|
||||
*/
|
||||
//adc.setAlertLatch(ADS1015_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1015_ACT_LOW -> active low (default)
|
||||
* ADS1015_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1015_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin will assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
//adc.setAlertPinToConversionReady(); //uncomment if you want to change the default
|
||||
|
||||
Serial.println("ADS1015 Example Sketch - Continuous Mode");
|
||||
Serial.println("All values in volts");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
/* If you change the compare channels you can immediately read values from the conversion
|
||||
* register, although they might belong to the former channel if no precautions are taken.
|
||||
* It takes about the time needed for two conversions to get the correct data. In single
|
||||
* shot mode you can use the isBusy() function to wait for data from the new channel. This
|
||||
* does not work in continuous mode.
|
||||
* To solve this issue the library adds a delay after change of channels if you are in contunuous
|
||||
* mode. The length of the delay is adjusted to the conversion rate. But be aware that the output
|
||||
* rate will be much lower that the conversion rate if you change channels frequently.
|
||||
*/
|
||||
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
|
||||
Serial.print("0: ");
|
||||
voltage = readChannel(ADS1015_COMP_0_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 1: ");
|
||||
voltage = readChannel(ADS1015_COMP_1_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 2: ");
|
||||
voltage = readChannel(ADS1015_COMP_2_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 3: ");
|
||||
voltage = readChannel(ADS1015_COMP_3_GND);
|
||||
Serial.println(voltage);
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
float readChannel(ADS1015_MUX channel) {
|
||||
float voltage = 0.0;
|
||||
adc.setCompareChannels(channel);
|
||||
voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
|
||||
return voltage;
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how to use the ADS1115 module with the TinyWireM library:
|
||||
* https://github.com/adafruit/TinyWireM
|
||||
* This allows you to run the ADS1115_WE library on an ATtiny85, for example.
|
||||
*
|
||||
* For this specific sketch you also need library Tiny4KOLED to display the
|
||||
* measured values on a SSD1306 OLED display:
|
||||
* https://github.com/datacute/Tiny4kOLED
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* !!!! IN ORDER TO USE TinyWireM YOU NEED TO UNCOMMENT #define USE_TINY_WIRE_M_ !!!!
|
||||
* !!!! IN ADS1115_config.h WHICH YOU FIND IN THE libraries/ADS1115_WE/src FOLDER !!!! !!!!
|
||||
*/
|
||||
#include <TinyWireM.h>
|
||||
#include <Tiny4kOLED.h>
|
||||
#include<ADS1115_WE.h>
|
||||
#define ADS1115_I2C_ADDR 0x48
|
||||
uint8_t width = 128;
|
||||
uint8_t height = 64;
|
||||
|
||||
/* There are two ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE() -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS) -> uses Wire / I2C_ADDRESS
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(ADS1115_I2C_ADDR);
|
||||
|
||||
void setup() {
|
||||
TinyWireM.begin();
|
||||
oled.begin(width, height, sizeof(tiny4koled_init_128x64br), tiny4koled_init_128x64br);
|
||||
oled.clear();
|
||||
oled.setFont(FONT6X8);
|
||||
oled.on();
|
||||
|
||||
if(!adc.init()){
|
||||
oled.print("ADS1115 not connected");
|
||||
while(1){}
|
||||
}
|
||||
else{
|
||||
oled.print("ADS1115 connected");
|
||||
delay(1000);
|
||||
oled.clear();
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change parameter to change channel
|
||||
|
||||
/* Set number of conversions after which the alert pin asserts
|
||||
* - or you can disable the alert
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
//adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); //uncomment if you want to change the default
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
// adc.setConvRate(ADS1115_8_SPS); //uncomment if you want to change the default
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
adc.setMeasureMode(ADS1115_CONTINUOUS); //comment line/change parameter to change mode
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in Volt - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion will be
|
||||
* cleared (if not latched)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*
|
||||
*/
|
||||
//adc.setAlertModeAndLimit_V(ADS1115_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will assert until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion will be
|
||||
* cleared with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
//adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin will assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
//adc.setAlertPinToConversionReady(); //uncomment if you want to change the default
|
||||
}
|
||||
|
||||
/* If you change the compare channels you can immediately read values from the conversion
|
||||
* register, although they might belong to the former channel if no precautions are taken.
|
||||
* It takes about the time needed for two conversions to get the correct data. In single
|
||||
* shot mode you can use the isBusy() function to wait for data from the new channel. This
|
||||
* does not work in continuous mode.
|
||||
* To solve this issue the library adds a delay after change of channels if you are in contunuous
|
||||
* mode. The length of the delay is adjusted to the conversion rate. But be aware that the output
|
||||
* rate will be much lower that the conversion rate if you change channels frequently.
|
||||
*/
|
||||
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND);
|
||||
voltage = adc.getResult_V();
|
||||
oled.setCursor(0,0);
|
||||
oled.print("Channel 0 [V]: ");
|
||||
oled.print(voltage);
|
||||
oled.clearToEOL();
|
||||
|
||||
adc.setCompareChannels(ADS1115_COMP_1_GND);
|
||||
voltage = adc.getResult_V();
|
||||
oled.setCursor(0,2);
|
||||
oled.print("Channel 1 [V]: ");
|
||||
oled.print(voltage);
|
||||
oled.clearToEOL();
|
||||
|
||||
adc.setCompareChannels(ADS1115_COMP_2_GND);
|
||||
voltage = adc.getResult_V();
|
||||
oled.setCursor(0,4);
|
||||
oled.print("Channel 2 [V]: ");
|
||||
oled.print(voltage);
|
||||
oled.clearToEOL();
|
||||
|
||||
adc.setCompareChannels(ADS1115_COMP_3_GND);
|
||||
voltage = adc.getResult_V();
|
||||
oled.setCursor(0,6);
|
||||
oled.print("Channel 3 [V]: ");
|
||||
oled.print(voltage);
|
||||
oled.clearToEOL();
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how you can use the alert pin as conversion ready alert pin.
|
||||
* It works in continuous mode as well as in single shot mode.
|
||||
* Please note that you need to enable the alert pin with setAlertPinMode. Choose any
|
||||
* parameter except ADS1115_DISABLE_ALERT.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
int interruptPin = 2;
|
||||
volatile bool convReady = false;
|
||||
|
||||
/* There are several ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
pinMode(interruptPin, INPUT_PULLUP);
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change parameter to change channels
|
||||
|
||||
/* Set number of conversions out of limit after which the alert pin will assert
|
||||
* - or you can disable the alert (including conversion ready alert)
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); //needed in this sketch to enable alert pin (doesn't matter if you choose after 1,2 or 4)
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
adc.setConvRate(ADS1115_8_SPS); //comment line/change parameter to change SPS
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
//adc.setMeasureMode(ADS1115_CONTINUOUS); // the conversion ready alert pin also works in continuous mode
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in volts - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion will be cleared
|
||||
* (if not latched)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*
|
||||
*/
|
||||
//adc.setAlertModeAndLimit_V(ADS1115_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will assert until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion
|
||||
* will be cleared with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
//adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
adc.setAlertPinToConversionReady(); //needed for this sketch
|
||||
|
||||
Serial.println("ADS1115 Example Sketch - Single Shot, Conversion Ready Alert Pin controlled");
|
||||
Serial.println();
|
||||
attachInterrupt(digitalPinToInterrupt(interruptPin), convReadyAlert, FALLING);
|
||||
adc.startSingleMeasurement();
|
||||
}
|
||||
|
||||
/* In this example I measure 32 times before the result is output. This is only to slow down
|
||||
* the output rate. I want to show that the output rate is controlled by the conversion ready
|
||||
* signals and not by a delay.
|
||||
*/
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
static int counter = 0;
|
||||
if(convReady){
|
||||
counter++;
|
||||
convReady = false;
|
||||
if(counter==32){ // counter is 32, conversion rate is 8 SPS --> 4s
|
||||
voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
|
||||
Serial.print("Channel 0 vs GND [V]: ");
|
||||
Serial.println(voltage);
|
||||
Serial.println("-------------------------------");
|
||||
counter = 0;
|
||||
}
|
||||
adc.startSingleMeasurement();
|
||||
}
|
||||
}
|
||||
|
||||
void convReadyAlert(){
|
||||
convReady = true;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how to obtain results using different scales / formats.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include <ADS1115_WE.h>
|
||||
#include <Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
|
||||
/* There are several ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
adc.setCompareChannels(ADS1115_COMP_0_1); //comment line/change parameter to change channel
|
||||
adc.setMeasureMode(ADS1115_CONTINUOUS); //comment line/change parameter to change mode
|
||||
|
||||
Serial.println("ADS1115 Example Sketch - Results in different scales / formats");
|
||||
Serial.println("All results are for channel 0 vs. GND");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
/* Output in Volt or in Millivolt */
|
||||
|
||||
float voltageInMillivolt = adc.getResult_mV();
|
||||
Serial.print("Result in Millivolt [mV]: ");
|
||||
Serial.println(voltageInMillivolt);
|
||||
|
||||
float voltageInVolt = adc.getResult_V();
|
||||
Serial.print("Result in Volt [V]: ");
|
||||
Serial.println(voltageInVolt);
|
||||
|
||||
/* Get the raw result from the conversion register. The conversion register
|
||||
* contains the conversion result of the amplified (!) voltage. This means the
|
||||
* value depends on the voltage as well as on the voltage range. E.g. if the
|
||||
* voltage range is 6144 mV (ADS1115_RANGE_6144), +32768 is 6144 mV; if the
|
||||
* range is 4096 mV, +32768 is 4096 mV, and so on. To be exact: +32768 would
|
||||
* the range value, but the register max.value is 32767.
|
||||
*/
|
||||
int rawResult = adc.getRawResult();
|
||||
Serial.print("Raw Result : ");
|
||||
Serial.println(rawResult);
|
||||
|
||||
/* Scaling of the result to a different range:
|
||||
* The results in the conversion register are in a range of -32768 to +32767
|
||||
* You might want to receive the result in a different scale, e.g. -1024 to 1023.
|
||||
* For -1024 to 1023, and if you have chosen e.g. ADS1115_RANGE_4096, 0 Volt would
|
||||
* give 0 as result and 4096 * (32767/32768) mV would give 1023. -4096 mV would
|
||||
* give -1024.
|
||||
*/
|
||||
int scaledResult = adc.getResultWithRange(-1024, 1023);
|
||||
Serial.print("Scaled result : ");
|
||||
Serial.println(scaledResult);
|
||||
|
||||
/* Scaling of the result to a different range plus scaling to a voltage range:
|
||||
* You can use this variant if you also want to scale to a voltage range. E.g. in
|
||||
* in order to get results equivalent to an Arduino UNO (10 bit, 5000 mV range), you
|
||||
* would choose getResultWithRange(-1024, 1023, 5000). A difference to the Arduino
|
||||
* UNO is that you can measure negative voltages.
|
||||
* You have to ensure that the voltage range you scale to is smaller than the
|
||||
* measuring voltage range. For this example only ADS1115_RANGE_6144 would cover the
|
||||
* scale up to 5000 mV.
|
||||
*/
|
||||
int scaledResultWithMaxVoltage = adc.getResultWithRange(-1024, 1023, 5000);
|
||||
Serial.print("Scaled result with voltage scale : ");
|
||||
Serial.println(scaledResultWithMaxVoltage);
|
||||
|
||||
/* This function returns the voltage range ADS1115_RANGE_XXXX in Millivolt */
|
||||
unsigned int voltRange = adc.getVoltageRange_mV();
|
||||
Serial.print("Voltage Range of ADS1115 [mV]: ");
|
||||
Serial.println(voltRange);
|
||||
|
||||
Serial.println("-------------------------------");
|
||||
delay(2000);
|
||||
}
|
||||
154
libraries/ADS1115_WE/examples/Single_Shot/Single_Shot.ino
Normal file
154
libraries/ADS1115_WE/examples/Single_Shot/Single_Shot.ino
Normal file
@@ -0,0 +1,154 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how to use the ADS1115 in single shot mode.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
|
||||
/* There are several ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
//adc.setCompareChannels(ADS1115_COMP_0_GND); //uncomment if you want to change the default
|
||||
|
||||
/* Set number of conversions after which the alert pin will assert
|
||||
* - or you can disable the alert
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
//adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); //uncomment if you want to change the default
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
//adc.setConvRate(ADS1115_128_SPS); //uncomment if you want to change the default
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
//adc.setMeasureMode(ADS1115_CONTINUOUS); //uncomment if you want to change the default
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in volts - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion will be
|
||||
* be cleared (if not latched)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*
|
||||
*/
|
||||
//adc.setAlertModeAndLimit_V(ADS1115_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will assert until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion
|
||||
* will be cleared with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
//adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin will assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
//adc.setAlertPinToConversionReady(); //uncomment if you want to change the default
|
||||
|
||||
Serial.println("ADS1115 Example Sketch - Single Shot Mode");
|
||||
Serial.println("Channel / Voltage [V]: ");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
|
||||
Serial.print("0: ");
|
||||
voltage = readChannel(ADS1115_COMP_0_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 1: ");
|
||||
voltage = readChannel(ADS1115_COMP_1_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 2: ");
|
||||
voltage = readChannel(ADS1115_COMP_2_GND);
|
||||
Serial.print(voltage);
|
||||
|
||||
Serial.print(", 3: ");
|
||||
voltage = readChannel(ADS1115_COMP_3_GND);
|
||||
Serial.println(voltage);
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
float readChannel(ADS1115_MUX channel) {
|
||||
float voltage = 0.0;
|
||||
adc.setCompareChannels(channel);
|
||||
adc.startSingleMeasurement();
|
||||
while(adc.isBusy()){}
|
||||
voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
|
||||
return voltage;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how you can use the conversion ready bit with the isBusy function.
|
||||
* This does not work in the continuous mode.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
|
||||
/* There are several ways to create your ADS1115_WE object:
|
||||
* ADS1115_WE adc = ADS1115_WE(); -> uses Wire / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS); -> uses Wire / I2C_ADDRESS
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire); -> you can pass any TwoWire object / I2C Address = 0x48
|
||||
* ADS1115_WE adc = ADS1115_WE(&Wire, I2C_ADDRESS); -> all together
|
||||
*/
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change parameter to change channels
|
||||
|
||||
/* Set number of conversions after which the alert pin will assert
|
||||
* - or you can disable the alert
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_3 -> after 3 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator / alert pin (default)
|
||||
*/
|
||||
//adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); //uncomment if you want to change the default
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
adc.setConvRate(ADS1115_8_SPS); //comment line/change parameter to change SPS
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*
|
||||
* Continuous mode does not work with conversion ready (isBusy), but it works with the
|
||||
* conversion ready alert pin. Confusing, but that's a property of the ADS1115 and not
|
||||
* a property of the library.
|
||||
*/
|
||||
// adc.setMeasureMode(ADS1115_CONTINUOUS); // continuous mode does not work with conversion ready (isBusy)
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window) in volts - alert pin will
|
||||
* assert when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin assertion will be cleared (if
|
||||
* not latched)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*
|
||||
*/
|
||||
//adc.setAlertModeAndLimit_V(ADS1115_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alert pin will assert until the
|
||||
* conversion register is read (getResult functions). If disabled the alert pin assertion will be
|
||||
* cleared with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
//adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
//adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
|
||||
|
||||
/* With this function the alert pin will assert, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
//adc.setAlertPinToConversionReady(); //uncomment if you want to change the default
|
||||
|
||||
Serial.println("ADS1115 Example Sketch - Single Shot, Conversion Ready (isBusy) controlled");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
for(int i=0; i<32; i++){ // counter is 32, conversion rate is 8 SPS --> 4s
|
||||
adc.startSingleMeasurement();
|
||||
while(adc.isBusy()){}
|
||||
}
|
||||
voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
|
||||
Serial.print("Channel 0 vs GND [V]: ");
|
||||
Serial.println(voltage);
|
||||
Serial.println("-------------------------------");
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch shows how to use two ADS1115 modules. In order to set the address,
|
||||
* connect the address pin to:
|
||||
*
|
||||
* GND -> 0x48 (or leave unconnected)
|
||||
* VCC -> 0x49
|
||||
* SDA -> 0x4A
|
||||
* SCL -> 0x4B
|
||||
*
|
||||
* When you have understood how it works you can easily add two additional ADS1115.
|
||||
* Of course there is potential to shorten the code, e.g. by setting up the ADCs
|
||||
* as array.
|
||||
*
|
||||
* If you need up to eight ADS1115 modules you can use an ESP32 with its two I2C
|
||||
* interfaces:
|
||||
* https://wolles-elektronikkiste.de/en/how-to-use-the-i2c-interfaces-of-the-esp32
|
||||
*
|
||||
* If you need up to 32 ADS1115 modules you can use a multiplexer like the TSCA9548A:
|
||||
* https://wolles-elektronikkiste.de/en/tca9548a-i2c-multiplexer
|
||||
*
|
||||
* Or you combine both and control up to 64 ADS1115 modules.
|
||||
*
|
||||
* Further information about the ADS1115 can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS_1 0x48
|
||||
#define I2C_ADDRESS_2 0x49
|
||||
|
||||
ADS1115_WE adc_1 = ADS1115_WE(I2C_ADDRESS_1);
|
||||
ADS1115_WE adc_2 = ADS1115_WE(I2C_ADDRESS_2);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
|
||||
if(!adc_1.init()){
|
||||
Serial.print("ADS1115 No 1 not connected!");
|
||||
}
|
||||
adc_1.setVoltageRange_mV(ADS1115_RANGE_6144);
|
||||
adc_1.setMeasureMode(ADS1115_CONTINUOUS);
|
||||
adc_1.setCompareChannels(ADS1115_COMP_0_GND);
|
||||
|
||||
if(!adc_2.init()){
|
||||
Serial.print("ADS1115 No 2 not connected!");
|
||||
}
|
||||
adc_2.setVoltageRange_mV(ADS1115_RANGE_6144);
|
||||
adc_2.setMeasureMode(ADS1115_CONTINUOUS);
|
||||
adc_2.setCompareChannels(ADS1115_COMP_0_GND);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float voltage = 0.0;
|
||||
|
||||
voltage = adc_1.getResult_V();
|
||||
Serial.println("Voltage [V], ADS1115 No 1: ");
|
||||
Serial.println(voltage);
|
||||
|
||||
voltage = adc_2.getResult_V();
|
||||
Serial.println("Voltage [V], ADS1115 No 2: ");
|
||||
Serial.println(voltage);
|
||||
|
||||
Serial.println("****************************");
|
||||
delay(1000);
|
||||
}
|
||||
66
libraries/ADS1115_WE/examples/Who_Am_I/Who_Am_I.ino
Normal file
66
libraries/ADS1115_WE/examples/Who_Am_I/Who_Am_I.ino
Normal file
@@ -0,0 +1,66 @@
|
||||
/***************************************************************************
|
||||
* Example sketch for the ADS1115_WE library
|
||||
*
|
||||
* This sketch checks whether you have an ADS1115 or ADS1015 module. The last
|
||||
* four bits of raw values obtained from an ADS1015 should be zero. Connect A0
|
||||
* to a voltage different from GND. The sketch also checks how much time is
|
||||
* needed to perform ten measurements at lowest data rate, which is 128 SPS for
|
||||
* the ADS1015 and 8 SPS for the ADS1115.
|
||||
*
|
||||
* Further information can be found on:
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include<ADS1115_WE.h>
|
||||
#include<Wire.h>
|
||||
#define I2C_ADDRESS 0x48
|
||||
|
||||
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
if(!adc.init()){
|
||||
Serial.println("ADS1115 not connected!");
|
||||
}
|
||||
adc.setVoltageRange_mV(ADS1115_RANGE_6144);
|
||||
adc.setCompareChannels(ADS1115_COMP_0_GND);
|
||||
Serial.println("ADS1115/ADS1015 Example Sketch - Who am I");
|
||||
Serial.println("Performing 10 single ended conversions A0 vs. GND:");
|
||||
uint16_t checkSum = 0;
|
||||
for(int i=0; i<10; i++){
|
||||
adc.startSingleMeasurement();
|
||||
while(adc.isBusy()){}
|
||||
int16_t raw = adc.getRawResult();
|
||||
Serial.println(raw, BIN);
|
||||
checkSum += raw & 0xF;
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("Check Sum (Sum of the last 4 bits): ");
|
||||
Serial.println(checkSum);
|
||||
|
||||
adc.setConvRate(ADS1115_8_SPS); // = ADS1015_128_SPS = 0x0000
|
||||
unsigned long startingTime = millis();
|
||||
for(int i=0; i<10; i++){
|
||||
adc.startSingleMeasurement();
|
||||
while(adc.isBusy()){}
|
||||
}
|
||||
unsigned long duration = millis() - startingTime;
|
||||
Serial.print("Time needed for 10 conversions at slowest sample rate [ms]: ");
|
||||
Serial.println(duration);
|
||||
Serial.println();
|
||||
|
||||
if(checkSum && duration > 1000){
|
||||
Serial.println("I am an ADS1115!");
|
||||
}
|
||||
else if (!checkSum && duration < 1000){
|
||||
Serial.println("I am an ADS1015!");
|
||||
}
|
||||
else {
|
||||
Serial.println("Sorry, don't know who I am!");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
136
libraries/ADS1115_WE/keywords.txt
Normal file
136
libraries/ADS1115_WE/keywords.txt
Normal file
@@ -0,0 +1,136 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For ADS1115_WE
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
ADS1115_WE KEYWORD1
|
||||
ADS1015_WE KEYWORD1
|
||||
|
||||
# ENUM TYPES
|
||||
ADS1115_COMP_QUE KEYWORD1
|
||||
ADS1115_LATCH KEYWORD1
|
||||
ADS1115_ALERT_POL KEYWORD1
|
||||
ADS1115_COMP_MODE KEYWORD1
|
||||
ADS1115_CONV_RATE KEYWORD1
|
||||
ADS1115_MEASURE_MODE KEYWORD1
|
||||
ADS1115_RANGE KEYWORD1
|
||||
ADS1115_MUX KEYWORD1
|
||||
ADS1015_MUX KEYWORD1
|
||||
ADS1115_STATUS_OR_START KEYWORD1
|
||||
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
reset KEYWORD2
|
||||
init KEYWORD2
|
||||
setAlertPinMode KEYWORD2
|
||||
setAlertLatch KEYWORD2
|
||||
setAlertPol KEYWORD2
|
||||
setAlertModeAndLimit_V KEYWORD2
|
||||
setConvRate KEYWORD2
|
||||
getConvRate KEYWORD2
|
||||
setMeasureMode KEYWORD2
|
||||
setVoltageRange_mV KEYWORD2
|
||||
setAutoRange KEYWORD2
|
||||
setCompareChannels KEYWORD2
|
||||
setCompareChannels_nonblock KEYWORD2
|
||||
isBusy KEYWORD2
|
||||
startSingleMeasurement KEYWORD2
|
||||
getResult_V KEYWORD2
|
||||
getResult_mV KEYWORD2
|
||||
getRawResult KEYWORD2
|
||||
getResultWithRange KEYWORD2
|
||||
getVoltageRange_mV KEYWORD2
|
||||
setAlertPinToConversionReady KEYWORD2
|
||||
clearAlert KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
ADS1115_CONV_REG LITERAL1
|
||||
ADS1115_CONFIG_REG LITERAL1
|
||||
ADS1115_LO_THRESH_REG LITERAL1
|
||||
ADS1115_HI_THRESH_REG LITERAL1
|
||||
ADS1115_REG_FACTOR LITERAL1
|
||||
ADS1115_REG_RESET_VAL LITERAL1
|
||||
|
||||
# ENUM VALUES
|
||||
ADS1115_ASSERT_AFTER_1 LITERAL1
|
||||
ADS1115_ASSERT_AFTER_2 LITERAL1
|
||||
ADS1115_ASSERT_AFTER_4 LITERAL1
|
||||
ADS1115_DISABLE_ALERT LITERAL1
|
||||
ADS1115_LATCH_DISABLED LITERAL1
|
||||
ADS1115_LATCH_ENABLED LITERAL1
|
||||
ADS1115_ACT_LOW LITERAL1
|
||||
ADS1115_ACT_HIGH LITERAL1
|
||||
ADS1115_MAX_LIMIT LITERAL1
|
||||
ADS1115_WINDOW LITERAL1
|
||||
ADS1115_8_SPS LITERAL1
|
||||
ADS1115_16_SPS LITERAL1
|
||||
ADS1115_32_SPS LITERAL1
|
||||
ADS1115_64_SPS LITERAL1
|
||||
ADS1115_128_SPS LITERAL1
|
||||
ADS1115_250_SPS LITERAL1
|
||||
ADS1115_475_SPS LITERAL1
|
||||
ADS1115_860_SPS LITERAL1
|
||||
ADS1115_CONTINUOUS LITERAL1
|
||||
ADS1115_CONTINOUS LITERAL1
|
||||
ADS1115_SINGLE LITERAL1
|
||||
ADS1115_RANGE_6144 LITERAL1
|
||||
ADS1115_RANGE_4096 LITERAL1
|
||||
ADS1115_RANGE_2048 LITERAL1
|
||||
ADS1115_RANGE_1024 LITERAL1
|
||||
ADS1115_RANGE_0512 LITERAL1
|
||||
ADS1115_RANGE_0256 LITERAL1
|
||||
ADS1115_COMP_0_1 LITERAL1
|
||||
ADS1115_COMP_0_3 LITERAL1
|
||||
ADS1115_COMP_1_3 LITERAL1
|
||||
ADS1115_COMP_2_3 LITERAL1
|
||||
ADS1115_COMP_0_GND LITERAL1
|
||||
ADS1115_COMP_1_GND LITERAL1
|
||||
ADS1115_COMP_2_GND LITERAL1
|
||||
ADS1115_COMP_3_GND LITERAL1
|
||||
ADS1115_BUSY LITERAL1
|
||||
ADS1015_START_ISREADY LITERAL1
|
||||
ADS1015_ASSERT_AFTER_1 LITERAL1
|
||||
ADS1015_ASSERT_AFTER_2 LITERAL1
|
||||
ADS1015_ASSERT_AFTER_4 LITERAL1
|
||||
ADS1015_DISABLE_ALERT LITERAL1
|
||||
ADS1015_LATCH_DISABLED LITERAL1
|
||||
ADS1015_LATCH_ENABLED LITERAL1
|
||||
ADS1015_ACT_LOW LITERAL1
|
||||
ADS1015_ACT_HIGH LITERAL1
|
||||
ADS1015_MAX_LIMIT LITERAL1
|
||||
ADS1015_WINDOW LITERAL1
|
||||
ADS1015_8_SPS LITERAL1
|
||||
ADS1015_16_SPS LITERAL1
|
||||
ADS1015_32_SPS LITERAL1
|
||||
ADS1015_64_SPS LITERAL1
|
||||
ADS1015_128_SPS LITERAL1
|
||||
ADS1015_250_SPS LITERAL1
|
||||
ADS1015_475_SPS LITERAL1
|
||||
ADS1015_860_SPS LITERAL1
|
||||
ADS1015_CONTINUOUS LITERAL1
|
||||
ADS1015_CONTINOUS LITERAL1
|
||||
ADS1015_SINGLE LITERAL1
|
||||
ADS1015_RANGE_6144 LITERAL1
|
||||
ADS1015_RANGE_4096 LITERAL1
|
||||
ADS1015_RANGE_2048 LITERAL1
|
||||
ADS1015_RANGE_1024 LITERAL1
|
||||
ADS1015_RANGE_0512 LITERAL1
|
||||
ADS1015_RANGE_0256 LITERAL1
|
||||
ADS1015_COMP_0_1 LITERAL1
|
||||
ADS1015_COMP_0_3 LITERAL1
|
||||
ADS1015_COMP_1_3 LITERAL1
|
||||
ADS1015_COMP_2_3 LITERAL1
|
||||
ADS1015_COMP_0_GND LITERAL1
|
||||
ADS1015_COMP_1_GND LITERAL1
|
||||
ADS1015_COMP_2_GND LITERAL1
|
||||
ADS1015_COMP_3_GND LITERAL1
|
||||
ADS1015_BUSY LITERAL1
|
||||
ADS1015_START_ISREADY LITERAL1
|
||||
10
libraries/ADS1115_WE/library.properties
Normal file
10
libraries/ADS1115_WE/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=ADS1115_WE
|
||||
version=1.5.0
|
||||
author=Wolfgang Ewald <wolfgang.ewald@wolles-elektronikkiste.de>
|
||||
maintainer=Wolfgang Ewald <wolfgang.ewald@wolles-elektronikkiste.de>
|
||||
sentence=A library for the ADS1115 and the ADS1015 ADC
|
||||
paragraph=An Arduino library for the 16-bit, 4-channel ADS1115 and the 12-Bit, 4-channel ADS1015 ADC, convenient to use. All features of the ADS1115 are implemented, including alert functions.
|
||||
category=Signal Input/Output
|
||||
url=https://github.com/wollewald/ADS1115_WE
|
||||
architectures=*
|
||||
includes=ADS1115_WE.h
|
||||
34
libraries/ADS1115_WE/src/ADS1015_WE.h
Normal file
34
libraries/ADS1115_WE/src/ADS1015_WE.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* This is a library for the ADS1115 and ADS1015 A/D Converter
|
||||
*
|
||||
* You'll find several example sketches which should enable you to use the library.
|
||||
*
|
||||
* You are free to use it, change it or build on it. In case you like it, it would
|
||||
* be cool if you give it a star.
|
||||
*
|
||||
* If you find bugs, please inform me!
|
||||
*
|
||||
* Written by Wolfgang (Wolle) Ewald
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ADS1015_WE_H
|
||||
#define ADS1015_WE_H
|
||||
#include <ADS1115_WE.h>
|
||||
|
||||
#if ARDUINO < 100
|
||||
#include <WProgram.h>
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
class ADS1015_WE : public ADS1115_WE {
|
||||
public:
|
||||
using ADS1115_WE::ADS1115_WE;
|
||||
};
|
||||
|
||||
#endif
|
||||
405
libraries/ADS1115_WE/src/ADS1115_WE.cpp
Normal file
405
libraries/ADS1115_WE/src/ADS1115_WE.cpp
Normal file
@@ -0,0 +1,405 @@
|
||||
/*****************************************
|
||||
* This is a library for the ADS1115 and ADS1015 A/D Converter
|
||||
*
|
||||
* You'll find an example which should enable you to use the library.
|
||||
*
|
||||
* You are free to use it, change it or build on it. In case you like
|
||||
* it, it would be cool if you give it a star.
|
||||
*
|
||||
* If you find bugs, please inform me!
|
||||
*
|
||||
* Written by Wolfgang (Wolle) Ewald
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
*
|
||||
*******************************************/
|
||||
|
||||
#include "ADS1115_WE.h"
|
||||
|
||||
void ADS1115_WE::reset(){
|
||||
#ifndef USE_TINY_WIRE_M_
|
||||
_wire->beginTransmission(0);
|
||||
_wire->write(0x06);
|
||||
_wire->endTransmission();
|
||||
#else
|
||||
TinyWireM.beginTransmission(0);
|
||||
TinyWireM.send(0x06);
|
||||
TinyWireM.endTransmission();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ADS1115_WE::init(bool ads1015){
|
||||
useADS1015 = ads1015;
|
||||
|
||||
#ifndef USE_TINY_WIRE_M_
|
||||
_wire->beginTransmission(i2cAddress);
|
||||
uint8_t success = _wire->endTransmission();
|
||||
#else
|
||||
TinyWireM.beginTransmission(i2cAddress);
|
||||
uint8_t success = TinyWireM.endTransmission();
|
||||
#endif
|
||||
if(success){
|
||||
return 0;
|
||||
}
|
||||
writeRegister(ADS1115_CONFIG_REG, ADS1115_REG_RESET_VAL);
|
||||
setVoltageRange_mV(ADS1115_RANGE_2048);
|
||||
writeRegister(ADS1115_LO_THRESH_REG, 0x8000);
|
||||
writeRegister(ADS1115_HI_THRESH_REG, 0x7FFF);
|
||||
deviceMeasureMode = ADS1115_SINGLE;
|
||||
autoRangeMode = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ADS1115_WE::setAlertPinMode(ADS1115_COMP_QUE mode){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
currentConfReg &= ~(0x8003);
|
||||
currentConfReg |= mode;
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
}
|
||||
|
||||
void ADS1115_WE::setAlertLatch(ADS1115_LATCH latch){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
currentConfReg &= ~(0x8004);
|
||||
currentConfReg |= latch;
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
}
|
||||
|
||||
void ADS1115_WE::setAlertPol(ADS1115_ALERT_POL polarity){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
currentConfReg &= ~(0x8008);
|
||||
currentConfReg |= polarity;
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
}
|
||||
|
||||
void ADS1115_WE::setAlertModeAndLimit_V(ADS1115_COMP_MODE mode, float hiThres, float loThres){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
currentConfReg &= ~(0x8010);
|
||||
currentConfReg |= mode;
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
int16_t alertLimit = calcLimit(hiThres);
|
||||
writeRegister(ADS1115_HI_THRESH_REG, alertLimit);
|
||||
alertLimit = calcLimit(loThres);
|
||||
writeRegister(ADS1115_LO_THRESH_REG, alertLimit);
|
||||
|
||||
}
|
||||
|
||||
void ADS1115_WE::setConvRate(ADS1115_CONV_RATE rate){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
currentConfReg &= ~(0x80E0);
|
||||
currentConfReg |= rate;
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
}
|
||||
|
||||
convRate ADS1115_WE::getConvRate(){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
return (convRate)(currentConfReg & 0xE0);
|
||||
}
|
||||
|
||||
void ADS1115_WE::setMeasureMode(ADS1115_MEASURE_MODE mode){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
deviceMeasureMode = mode;
|
||||
currentConfReg &= ~(0x8100);
|
||||
currentConfReg |= mode;
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
}
|
||||
|
||||
void ADS1115_WE::setVoltageRange_mV(ADS1115_RANGE range){
|
||||
uint16_t currentVoltageRange = voltageRange;
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
uint16_t currentRange = (currentConfReg >> 9) & 7;
|
||||
uint16_t currentAlertPinMode = currentConfReg & 3;
|
||||
|
||||
setMeasureMode(ADS1115_SINGLE);
|
||||
|
||||
switch(range){
|
||||
case ADS1115_RANGE_6144:
|
||||
voltageRange = 6144;
|
||||
break;
|
||||
case ADS1115_RANGE_4096:
|
||||
voltageRange = 4096;
|
||||
break;
|
||||
case ADS1115_RANGE_2048:
|
||||
voltageRange = 2048;
|
||||
break;
|
||||
case ADS1115_RANGE_1024:
|
||||
voltageRange = 1024;
|
||||
break;
|
||||
case ADS1115_RANGE_0512:
|
||||
voltageRange = 512;
|
||||
break;
|
||||
case ADS1115_RANGE_0256:
|
||||
voltageRange = 256;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((currentRange != range) && (currentAlertPinMode != ADS1115_DISABLE_ALERT)){
|
||||
int16_t alertLimit = readRegister(ADS1115_HI_THRESH_REG);
|
||||
alertLimit = alertLimit * (currentVoltageRange * 1.0 / voltageRange);
|
||||
writeRegister(ADS1115_HI_THRESH_REG, alertLimit);
|
||||
|
||||
alertLimit = readRegister(ADS1115_LO_THRESH_REG);
|
||||
alertLimit = alertLimit * (currentVoltageRange * 1.0 / voltageRange);
|
||||
writeRegister(ADS1115_LO_THRESH_REG, alertLimit);
|
||||
}
|
||||
|
||||
currentConfReg &= ~(0x8E00);
|
||||
currentConfReg |= range;
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
convRate rate = getConvRate();
|
||||
delayAccToRate(rate);
|
||||
}
|
||||
|
||||
void ADS1115_WE::setAutoRange(){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
setVoltageRange_mV(ADS1115_RANGE_6144);
|
||||
|
||||
if(deviceMeasureMode == ADS1115_SINGLE){
|
||||
setMeasureMode(ADS1115_CONTINUOUS);
|
||||
convRate rate = getConvRate();
|
||||
delayAccToRate(rate);
|
||||
}
|
||||
|
||||
int16_t rawResult = abs(readRegister(ADS1115_CONV_REG));
|
||||
int16_t rawResultCopy = rawResult;
|
||||
if(rawResultCopy == -32768){
|
||||
rawResultCopy++;
|
||||
}
|
||||
rawResultCopy = abs(rawResultCopy);
|
||||
|
||||
range optRange = ADS1115_RANGE_6144;
|
||||
|
||||
if(rawResultCopy < 1093){
|
||||
optRange = ADS1115_RANGE_0256;
|
||||
}
|
||||
else if(rawResultCopy < 2185){
|
||||
optRange = ADS1115_RANGE_0512;
|
||||
}
|
||||
else if(rawResultCopy < 4370){
|
||||
optRange = ADS1115_RANGE_1024;
|
||||
}
|
||||
else if(rawResultCopy < 8738){
|
||||
optRange = ADS1115_RANGE_2048;
|
||||
}
|
||||
else if(rawResultCopy < 17476){
|
||||
optRange = ADS1115_RANGE_4096;
|
||||
}
|
||||
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
setVoltageRange_mV(optRange);
|
||||
}
|
||||
|
||||
void ADS1115_WE::setPermanentAutoRangeMode(bool autoMode){
|
||||
if(autoMode){
|
||||
autoRangeMode = true;
|
||||
}
|
||||
else{
|
||||
autoRangeMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ADS1115_WE::delayAccToRate(convRate cr){
|
||||
if(!useADS1015){
|
||||
switch(cr){
|
||||
case ADS1115_8_SPS:
|
||||
delay(130);
|
||||
break;
|
||||
case ADS1115_16_SPS:
|
||||
delay(65);
|
||||
break;
|
||||
case ADS1115_32_SPS:
|
||||
delay(32);
|
||||
break;
|
||||
case ADS1115_64_SPS:
|
||||
delay(16);
|
||||
break;
|
||||
case ADS1115_128_SPS:
|
||||
delay(8);
|
||||
break;
|
||||
case ADS1115_250_SPS:
|
||||
delay(4);
|
||||
break;
|
||||
case ADS1115_475_SPS:
|
||||
delay(3);
|
||||
break;
|
||||
case ADS1115_860_SPS:
|
||||
delay(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
switch(cr){
|
||||
case ADS1015_128_SPS:
|
||||
delay(8);
|
||||
break;
|
||||
case ADS1015_250_SPS:
|
||||
delay(5);
|
||||
break;
|
||||
case ADS1015_490_SPS:
|
||||
delay(2);
|
||||
break;
|
||||
case ADS1015_920_SPS:
|
||||
delay(1);
|
||||
break;
|
||||
case ADS1015_1600_SPS:
|
||||
delayMicroseconds(675);
|
||||
break;
|
||||
case ADS1015_2400_SPS:
|
||||
delayMicroseconds(450);
|
||||
break;
|
||||
case ADS1015_3300_SPS:
|
||||
delayMicroseconds(330);
|
||||
break;
|
||||
case ADS1015_3300_SPS_2:
|
||||
delayMicroseconds(330);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ADS1115_WE::setCompareChannels(ADS1115_MUX mux){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
currentConfReg &= ~(0xF000);
|
||||
currentConfReg |= (mux);
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
|
||||
if(!(currentConfReg & 0x0100)){ // => if not single shot mode
|
||||
convRate rate = getConvRate();
|
||||
delayAccToRate(rate);
|
||||
delayAccToRate(rate);
|
||||
}
|
||||
}
|
||||
|
||||
void ADS1115_WE::setCompareChannels_nonblock(ADS1115_MUX mux){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
currentConfReg &= ~(0xF000);
|
||||
currentConfReg |= (mux);
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
}
|
||||
|
||||
void ADS1115_WE::setSingleChannel(size_t channel) {
|
||||
if (channel >= 4)
|
||||
return;
|
||||
setCompareChannels((ADS1115_MUX)(ADS1115_COMP_0_GND + ADS1115_COMP_INC*channel));
|
||||
}
|
||||
|
||||
bool ADS1115_WE::isBusy(){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
return (!(currentConfReg>>15) & 1);
|
||||
}
|
||||
|
||||
|
||||
void ADS1115_WE::startSingleMeasurement(){
|
||||
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
|
||||
currentConfReg |= (1 << 15);
|
||||
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
|
||||
}
|
||||
|
||||
|
||||
float ADS1115_WE::getResult_V(){
|
||||
float result = getResult_mV();
|
||||
result /= 1000;
|
||||
return result;
|
||||
}
|
||||
|
||||
float ADS1115_WE::getResult_mV(){
|
||||
int16_t rawResult = getRawResult();
|
||||
float result = (rawResult * 1.0 / ADS1115_REG_FACTOR) * voltageRange;
|
||||
return result;
|
||||
}
|
||||
|
||||
int16_t ADS1115_WE::getRawResult(){
|
||||
int16_t rawResult = readRegister(ADS1115_CONV_REG);
|
||||
if(autoRangeMode){
|
||||
int16_t rawResultCopy = rawResult;
|
||||
if(rawResultCopy == -32768){
|
||||
rawResultCopy++;
|
||||
}
|
||||
rawResultCopy = abs(rawResultCopy);
|
||||
if((rawResultCopy > 26214) && (voltageRange != 6144)){ // 80%
|
||||
setAutoRange();
|
||||
rawResult = readRegister(ADS1115_CONV_REG);
|
||||
}
|
||||
else if((rawResultCopy < 9800) && (voltageRange != 256)){ //30%
|
||||
setAutoRange();
|
||||
rawResult = readRegister(ADS1115_CONV_REG);
|
||||
}
|
||||
}
|
||||
return rawResult;
|
||||
}
|
||||
|
||||
int16_t ADS1115_WE::getResultWithRange(int16_t min, int16_t max){
|
||||
int16_t rawResult = getRawResult();
|
||||
int16_t result = map(rawResult, -32768, 32767, min, max);
|
||||
return result;
|
||||
}
|
||||
|
||||
int16_t ADS1115_WE::getResultWithRange(int16_t min, int16_t max, int16_t maxMillivolt){
|
||||
int16_t result = getResultWithRange(min, max);
|
||||
result = static_cast<int16_t>((1.0 * result * voltageRange / maxMillivolt) + 0.5);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t ADS1115_WE::getVoltageRange_mV(){
|
||||
return voltageRange;
|
||||
}
|
||||
|
||||
void ADS1115_WE::setAlertPinToConversionReady(){
|
||||
writeRegister(ADS1115_LO_THRESH_REG, (0<<15));
|
||||
writeRegister(ADS1115_HI_THRESH_REG, (1<<15));
|
||||
}
|
||||
|
||||
void ADS1115_WE::clearAlert(){
|
||||
readRegister(ADS1115_CONV_REG);
|
||||
}
|
||||
|
||||
/************************************************
|
||||
private functions
|
||||
*************************************************/
|
||||
|
||||
int16_t ADS1115_WE::calcLimit(float rawLimit){
|
||||
int16_t limit = static_cast<int16_t>((rawLimit * ADS1115_REG_FACTOR / voltageRange)*1000);
|
||||
return limit;
|
||||
}
|
||||
|
||||
uint8_t ADS1115_WE::writeRegister(uint8_t reg, uint16_t val){
|
||||
uint8_t lVal = val & 255;
|
||||
uint8_t hVal = val >> 8;
|
||||
#ifndef USE_TINY_WIRE_M_
|
||||
_wire->beginTransmission(i2cAddress);
|
||||
_wire->write(reg);
|
||||
_wire->write(hVal);
|
||||
_wire->write(lVal);
|
||||
return _wire->endTransmission();
|
||||
#else
|
||||
TinyWireM.beginTransmission(i2cAddress);
|
||||
TinyWireM.send(reg);
|
||||
TinyWireM.send(hVal);
|
||||
TinyWireM.send(lVal);
|
||||
return TinyWireM.endTransmission();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
uint16_t ADS1115_WE::readRegister(uint8_t reg){
|
||||
uint8_t MSByte = 0, LSByte = 0;
|
||||
uint16_t regValue = 0;
|
||||
#ifndef USE_TINY_WIRE_M_
|
||||
_wire->beginTransmission(i2cAddress);
|
||||
_wire->write(reg);
|
||||
_wire->endTransmission(false);
|
||||
_wire->requestFrom(i2cAddress,static_cast<uint8_t>(2));
|
||||
if(_wire->available()){
|
||||
MSByte = _wire->read();
|
||||
LSByte = _wire->read();
|
||||
}
|
||||
#else
|
||||
TinyWireM.beginTransmission(i2cAddress);
|
||||
TinyWireM.send(reg);
|
||||
TinyWireM.endTransmission();
|
||||
TinyWireM.requestFrom(i2cAddress,static_cast<uint8_t>(2));
|
||||
MSByte = TinyWireM.receive();
|
||||
LSByte = TinyWireM.receive();
|
||||
#endif
|
||||
regValue = (MSByte<<8) + LSByte;
|
||||
return regValue;
|
||||
}
|
||||
334
libraries/ADS1115_WE/src/ADS1115_WE.h
Normal file
334
libraries/ADS1115_WE/src/ADS1115_WE.h
Normal file
@@ -0,0 +1,334 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* This is a library for the ADS1115 and ADS1015 A/D Converter
|
||||
*
|
||||
* You'll find several example sketches which should enable you to use the library.
|
||||
*
|
||||
* You are free to use it, change it or build on it. In case you like it, it would
|
||||
* be cool if you give it a star.
|
||||
*
|
||||
* If you find bugs, please inform me!
|
||||
*
|
||||
* Written by Wolfgang (Wolle) Ewald
|
||||
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
|
||||
* https://wolles-elektronikkiste.de/ads1115 (German)
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ADS1115_WE_H_
|
||||
#define ADS1115_WE_H_
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#include "ADS1115_config.h"
|
||||
|
||||
#ifdef USE_TINY_WIRE_M_
|
||||
#include <TinyWireM.h>
|
||||
#endif
|
||||
#ifndef USE_TINY_WIRE_M_
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
typedef enum ADS1115_COMP_QUE {
|
||||
ADS1115_ASSERT_AFTER_1 = 0x0000,
|
||||
ADS1115_ASSERT_AFTER_2 = 0x0001,
|
||||
ADS1115_ASSERT_AFTER_4 = 0x0002,
|
||||
ADS1115_DISABLE_ALERT = 0x0003,
|
||||
ADS1015_ASSERT_AFTER_1 = ADS1115_ASSERT_AFTER_1,
|
||||
ADS1015_ASSERT_AFTER_2 = ADS1115_ASSERT_AFTER_2,
|
||||
ADS1015_ASSERT_AFTER_4 = ADS1115_ASSERT_AFTER_4,
|
||||
ADS1015_DISABLE_ALERT = ADS1115_DISABLE_ALERT
|
||||
} compQue;
|
||||
|
||||
typedef enum ADS1115_LATCH {
|
||||
ADS1115_LATCH_DISABLED = 0x0000,
|
||||
ADS1115_LATCH_ENABLED = 0x0004,
|
||||
ADS1015_LATCH_DISABLED = ADS1115_LATCH_DISABLED,
|
||||
ADS1015_LATCH_ENABLED = ADS1115_LATCH_ENABLED
|
||||
} latch;
|
||||
|
||||
typedef enum ADS1115_ALERT_POL {
|
||||
ADS1115_ACT_LOW = 0x0000,
|
||||
ADS1115_ACT_HIGH = 0x0008,
|
||||
ADS1015_ACT_LOW = ADS1115_ACT_LOW,
|
||||
ADS1015_ACT_HIGH = ADS1115_ACT_HIGH
|
||||
} alertPol;
|
||||
|
||||
typedef enum ADS1115_COMP_MODE{
|
||||
ADS1115_MAX_LIMIT = 0x0000,
|
||||
ADS1115_WINDOW = 0x0010,
|
||||
ADS1015_MAX_LIMIT = ADS1115_MAX_LIMIT,
|
||||
ADS1015_WINDOW = ADS1115_WINDOW
|
||||
} compMode;
|
||||
|
||||
typedef enum ADS1115_CONV_RATE{
|
||||
ADS1115_8_SPS = 0x0000,
|
||||
ADS1115_16_SPS = 0x0020,
|
||||
ADS1115_32_SPS = 0x0040,
|
||||
ADS1115_64_SPS = 0x0060,
|
||||
ADS1115_128_SPS = 0x0080,
|
||||
ADS1115_250_SPS = 0x00A0,
|
||||
ADS1115_475_SPS = 0x00C0,
|
||||
ADS1115_860_SPS = 0x00E0,
|
||||
ADS1015_128_SPS = ADS1115_8_SPS,
|
||||
ADS1015_250_SPS = ADS1115_16_SPS,
|
||||
ADS1015_490_SPS = ADS1115_32_SPS,
|
||||
ADS1015_920_SPS = ADS1115_64_SPS,
|
||||
ADS1015_1600_SPS = ADS1115_128_SPS,
|
||||
ADS1015_2400_SPS = ADS1115_250_SPS,
|
||||
ADS1015_3300_SPS = ADS1115_475_SPS,
|
||||
ADS1015_3300_SPS_2 = ADS1115_860_SPS
|
||||
} convRate;
|
||||
|
||||
typedef enum ADS1115_MEASURE_MODE{
|
||||
ADS1115_CONTINUOUS = 0x0000,
|
||||
ADS1115_SINGLE = 0x0100,
|
||||
ADS1015_CONTINUOUS = ADS1115_CONTINUOUS,
|
||||
ADS1015_SINGLE = ADS1115_SINGLE
|
||||
} measureMode;
|
||||
|
||||
typedef enum ADS1115_RANGE{
|
||||
ADS1115_RANGE_6144 = 0x0000,
|
||||
ADS1115_RANGE_4096 = 0x0200,
|
||||
ADS1115_RANGE_2048 = 0x0400,
|
||||
ADS1115_RANGE_1024 = 0x0600,
|
||||
ADS1115_RANGE_0512 = 0x0800,
|
||||
ADS1115_RANGE_0256 = 0x0A00,
|
||||
ADS1015_RANGE_6144 = ADS1115_RANGE_6144,
|
||||
ADS1015_RANGE_4096 = ADS1115_RANGE_4096,
|
||||
ADS1015_RANGE_2048 = ADS1115_RANGE_2048,
|
||||
ADS1015_RANGE_1024 = ADS1115_RANGE_1024,
|
||||
ADS1015_RANGE_0512 = ADS1115_RANGE_0512,
|
||||
ADS1015_RANGE_0256 = ADS1115_RANGE_0256
|
||||
} range;
|
||||
|
||||
typedef enum ADS1115_MUX{
|
||||
ADS1115_COMP_0_1 = 0x0000,
|
||||
ADS1115_COMP_0_3 = 0x1000,
|
||||
ADS1115_COMP_1_3 = 0x2000,
|
||||
ADS1115_COMP_2_3 = 0x3000,
|
||||
ADS1115_COMP_0_GND = 0x4000,
|
||||
ADS1115_COMP_1_GND = 0x5000,
|
||||
ADS1115_COMP_2_GND = 0x6000,
|
||||
ADS1115_COMP_3_GND = 0x7000,
|
||||
ADS1015_COMP_0_1 = ADS1115_COMP_0_1,
|
||||
ADS1015_COMP_0_3 = ADS1115_COMP_0_3,
|
||||
ADS1015_COMP_1_3 = ADS1115_COMP_1_3,
|
||||
ADS1015_COMP_2_3 = ADS1115_COMP_2_3,
|
||||
ADS1015_COMP_0_GND = ADS1115_COMP_0_GND,
|
||||
ADS1015_COMP_1_GND = ADS1115_COMP_1_GND,
|
||||
ADS1015_COMP_2_GND = ADS1115_COMP_2_GND,
|
||||
ADS1015_COMP_3_GND = ADS1115_COMP_3_GND
|
||||
} mux;
|
||||
|
||||
#define ADS1115_COMP_INC 0x1000 // increment to next channel
|
||||
#define ADS1015_MUX ADS1115_MUX
|
||||
|
||||
typedef enum ADS1115_STATUS_OR_START{
|
||||
ADS1115_BUSY = 0x0000,
|
||||
ADS1115_START_ISREADY = 0x8000,
|
||||
ADS1015_BUSY = ADS1115_BUSY,
|
||||
ADS1015_START_ISREADY = ADS1115_START_ISREADY
|
||||
} statusOrStart;
|
||||
|
||||
|
||||
class ADS1115_WE
|
||||
{
|
||||
public:
|
||||
/* registers */
|
||||
static constexpr uint8_t ADS1115_CONV_REG {0x00}; // Conversion Register
|
||||
static constexpr uint8_t ADS1115_CONFIG_REG {0x01}; // Configuration Register
|
||||
static constexpr uint8_t ADS1115_LO_THRESH_REG {0x02}; // Low Threshold Register
|
||||
static constexpr uint8_t ADS1115_HI_THRESH_REG {0x03}; // High Threshold Register
|
||||
|
||||
/* other */
|
||||
static constexpr uint16_t ADS1115_REG_FACTOR {32768};
|
||||
static constexpr uint16_t ADS1115_REG_RESET_VAL {0x8583};
|
||||
|
||||
#ifndef USE_TINY_WIRE_M_
|
||||
ADS1115_WE(const uint8_t addr = 0x48) : _wire{&Wire}, i2cAddress{addr} {}
|
||||
ADS1115_WE(TwoWire *w, const uint8_t addr = 0x48) : _wire{w}, i2cAddress{addr} {}
|
||||
#else
|
||||
ADS1115_WE(const uint8_t addr = 0x48) : i2cAddress{addr} {}
|
||||
#endif
|
||||
|
||||
void reset();
|
||||
bool init(bool ads1015 = false);
|
||||
|
||||
/* Set number of conversions after which the alert pin will be active
|
||||
* - or you can disable the alert
|
||||
*
|
||||
* ADS1115_ASSERT_AFTER_1 -> after 1 conversion
|
||||
* ADS1115_ASSERT_AFTER_2 -> after 2 conversions
|
||||
* ADS1115_ASSERT_AFTER_4 -> after 4 conversions
|
||||
* ADS1115_DISABLE_ALERT -> disable comparator // alert pin (default)
|
||||
*/
|
||||
void setAlertPinMode(ADS1115_COMP_QUE mode);
|
||||
|
||||
/* Enable or disable latch. If latch is enabled the alarm pin will be active until the
|
||||
* conversion register is read (getResult functions). If disabled the alarm pin will be
|
||||
* deactivated with next value within limits.
|
||||
*
|
||||
* ADS1115_LATCH_DISABLED (default)
|
||||
* ADS1115_LATCH_ENABLED
|
||||
*/
|
||||
void setAlertLatch(ADS1115_LATCH latch);
|
||||
|
||||
/* Sets the alert pin polarity if active:
|
||||
*
|
||||
* Enable or disable latch. If latch is enabled the alarm pin will be active until the
|
||||
* conversion register is read (getResult functions). If disabled the alarm pin will be
|
||||
* deactivated with next value within limits.
|
||||
*
|
||||
* ADS1115_ACT_LOW -> active low (default)
|
||||
* ADS1115_ACT_HIGH -> active high
|
||||
*/
|
||||
void setAlertPol(ADS1115_ALERT_POL polarity);
|
||||
|
||||
/* Choose maximum limit or maximum and minimum alert limit (window)in Volt - alert pin will
|
||||
* be active when measured values are beyond the maximum limit or outside the window
|
||||
* Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
|
||||
* In max limit mode the minimum value is the limit where the alert pin will be deactivated (if
|
||||
* not latched)
|
||||
*
|
||||
* ADS1115_MAX_LIMIT
|
||||
* ADS1115_WINDOW
|
||||
*/
|
||||
void setAlertModeAndLimit_V(ADS1115_COMP_MODE mode, float hithres, float lothres);
|
||||
|
||||
/* Set the conversion rate in SPS (samples per second)
|
||||
* Options should be self-explaining:
|
||||
*
|
||||
* ADS1115_8_SPS
|
||||
* ADS1115_16_SPS
|
||||
* ADS1115_32_SPS
|
||||
* ADS1115_64_SPS
|
||||
* ADS1115_128_SPS (default)
|
||||
* ADS1115_250_SPS
|
||||
* ADS1115_475_SPS
|
||||
* ADS1115_860_SPS
|
||||
*/
|
||||
void setConvRate(ADS1115_CONV_RATE rate);
|
||||
|
||||
/* returns the conversion rate */
|
||||
convRate getConvRate();
|
||||
|
||||
/* Set continuous or single shot mode:
|
||||
*
|
||||
* ADS1115_CONTINUOUS -> continuous mode
|
||||
* ADS1115_SINGLE -> single shot mode (default)
|
||||
*/
|
||||
void setMeasureMode(ADS1115_MEASURE_MODE mode);
|
||||
|
||||
/* Set the voltage range of the ADC to adjust the gain:
|
||||
* Please note that you must not apply more than VDD + 0.3V to the input pins!
|
||||
*
|
||||
* ADS1115_RANGE_6144 -> +/- 6144 mV
|
||||
* ADS1115_RANGE_4096 -> +/- 4096 mV
|
||||
* ADS1115_RANGE_2048 -> +/- 2048 mV (default)
|
||||
* ADS1115_RANGE_1024 -> +/- 1024 mV
|
||||
* ADS1115_RANGE_0512 -> +/- 512 mV
|
||||
* ADS1115_RANGE_0256 -> +/- 256 mV
|
||||
*/
|
||||
void setVoltageRange_mV(ADS1115_RANGE range);
|
||||
|
||||
/* Set the voltage range automatically
|
||||
* 1) changes into maximum range and continuous mode
|
||||
* 2) measures the voltage
|
||||
* 3) chooses the smallest range in which the measured voltage is <80%
|
||||
* of the range's maximum
|
||||
* 4) switches back to single shot mode if it was in this mode before
|
||||
*
|
||||
* Please be aware that the procedure takes the the time needed for several conversions.
|
||||
* You should ony use it in case you expect stable or slowly changing voltages.
|
||||
*/
|
||||
void setAutoRange();
|
||||
|
||||
/* Set the automatic voltage range permanantly, but the range will only be changed if the
|
||||
* measured value is outside 30 - 80% of the maximum value of the current range.
|
||||
* Therefore this method is faster than setAutoRange().
|
||||
*/
|
||||
void setPermanentAutoRangeMode(bool autoMode);
|
||||
|
||||
/* Set the inputs to be compared
|
||||
*
|
||||
* ADS1115_COMP_0_1 -> compares 0 with 1 (default)
|
||||
* ADS1115_COMP_0_3 -> compares 0 with 3
|
||||
* ADS1115_COMP_1_3 -> compares 1 with 3
|
||||
* ADS1115_COMP_2_3 -> compares 2 with 3
|
||||
* ADS1115_COMP_0_GND -> compares 0 with GND
|
||||
* ADS1115_COMP_1_GND -> compares 1 with GND
|
||||
* ADS1115_COMP_2_GND -> compares 2 with GND
|
||||
* ADS1115_COMP_3_GND -> compares 3 with GND
|
||||
*/
|
||||
void setCompareChannels(ADS1115_MUX mux);
|
||||
|
||||
/* Set to channel (0-3) in single ended mode in a non blocking way without delay
|
||||
*/
|
||||
void setCompareChannels_nonblock(ADS1115_MUX mux);
|
||||
|
||||
/* Set to channel (0-3) in single ended mode
|
||||
*/
|
||||
void setSingleChannel(size_t channel);
|
||||
|
||||
bool isBusy();
|
||||
void startSingleMeasurement();
|
||||
float getResult_V();
|
||||
float getResult_mV();
|
||||
|
||||
/* Get the raw result from the conversion register:
|
||||
* The conversion register contains the conversion result of the amplified (!)
|
||||
* voltage. This means the value depends on the voltage as well as on the
|
||||
* voltage range. E.g. if the voltage range is 6144 mV (ADS1115_RANGE_6144),
|
||||
* +32767 is 6144 mV; if the range is 4096 mV, +32767 is 4096 mV, and so on.
|
||||
*/
|
||||
int16_t getRawResult();
|
||||
|
||||
/* Scaling of the result to a different range:
|
||||
* The results in the conversion register are in a range of -32767 to +32767
|
||||
* You might want to receive the result in a different scale, e.g. -1023 to 1023.
|
||||
* For -1023 to 1023, and if you have chosen e.g. ADS1115_RANGE_4096, 0 Volt would
|
||||
* give 0 as result and 4096 mV would give 1023. -4096 mV would give -1023.
|
||||
*/
|
||||
int16_t getResultWithRange(int16_t min, int16_t max);
|
||||
|
||||
/* Scaling of the result to a different range plus scaling to a voltage range:
|
||||
* You can use this variant if you also want to scale to a voltage range. E.g. in
|
||||
* in order to get results equivalent to an Arduino UNO (10 bit, 5000 mV range), you
|
||||
* would choose getResultWithRange(-1023, 1023, 5000). A difference to the Arduino
|
||||
* UNO is that you can measure negative voltages.
|
||||
* You have to ensure that the voltage range you scale to is smaller than the
|
||||
* measuring voltage range.
|
||||
*/
|
||||
int16_t getResultWithRange(int16_t min, int16_t max, int16_t maxVoltage);
|
||||
|
||||
/* This function returns the voltage range ADS1115_RANGE_XXXX in Millivolt */
|
||||
uint16_t getVoltageRange_mV();
|
||||
|
||||
/* With this function the alert pin will be active, when a conversion is ready.
|
||||
* In order to deactivate, use the setAlertLimit_V function
|
||||
*/
|
||||
void setAlertPinToConversionReady();
|
||||
void clearAlert();
|
||||
|
||||
|
||||
protected:
|
||||
#ifndef USE_TINY_WIRE_M_
|
||||
TwoWire *_wire;
|
||||
#endif
|
||||
bool useADS1015;
|
||||
uint16_t voltageRange;
|
||||
ADS1115_MEASURE_MODE deviceMeasureMode;
|
||||
uint8_t i2cAddress;
|
||||
bool autoRangeMode;
|
||||
void delayAccToRate(convRate cr);
|
||||
int16_t calcLimit(float rawLimit);
|
||||
uint8_t writeRegister(uint8_t reg, uint16_t val);
|
||||
uint16_t readRegister(uint8_t reg);
|
||||
};
|
||||
#endif
|
||||
|
||||
5
libraries/ADS1115_WE/src/ADS1115_config.h
Normal file
5
libraries/ADS1115_WE/src/ADS1115_config.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#ifndef ADS1115_CONFIG_H_
|
||||
#define ADS1115_CONFIG_H_
|
||||
/* Uncomment the following line to use TinyWireM instead of Wire */
|
||||
//#define USE_TINY_WIRE_M_
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
#include <AVR_RTC.h>
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
|
||||
setup_RTC_interrupt();
|
||||
Serial.begin(38400); // open the serial port at 9600 bps:
|
||||
|
||||
tm CurrTimeDate; // set up an array for the RTC info.
|
||||
// <year yyyy> <month mm Jan=0> <date dd> <day d Sun=0> <hour hh> <minute mm> <second ss>
|
||||
|
||||
CurrTimeDate.tm_year = (uint8_t)( 2016 - 1900 );
|
||||
CurrTimeDate.tm_mon = (uint8_t) 0;
|
||||
CurrTimeDate.tm_mday = (uint8_t) 12;
|
||||
CurrTimeDate.tm_wday = (uint8_t) 2;
|
||||
CurrTimeDate.tm_hour = (uint8_t) 17;
|
||||
CurrTimeDate.tm_min = (uint8_t) 16;
|
||||
CurrTimeDate.tm_sec = (uint8_t) 0;
|
||||
|
||||
set_system_time( mktime( (tm*)&CurrTimeDate));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
|
||||
time_t currentTick; // set up a location for the current time stamp since the
|
||||
|
||||
time((time_t *)¤tTick);
|
||||
|
||||
Serial.println(ctime( (time_t *)¤tTick));
|
||||
|
||||
delay(2000);
|
||||
|
||||
}
|
||||
9
libraries/AVR_Standard_C_Time_Library/library.properties
Normal file
9
libraries/AVR_Standard_C_Time_Library/library.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
name=AVR Standard C Time Library
|
||||
version=2.0.0-1
|
||||
author=Phillip Stevens <phillip.stevens@gmail.com>
|
||||
maintainer=Phillip Stevens <phillip.stevens@gmail.com>
|
||||
sentence=<h3>Real Time functions for Goldilocks ATmega1284p & ATmega2560</h3>
|
||||
paragraph=This library implements a RTC on an ATmega with a 32kHz clock crystal on Timer 2, supporting the avr-libc time.h functions.
|
||||
category=Timing
|
||||
url=https://github.com/feilipu/Arduino_RTC_Library
|
||||
architectures=avr
|
||||
77
libraries/AVR_Standard_C_Time_Library/readme.md
Normal file
77
libraries/AVR_Standard_C_Time_Library/readme.md
Normal file
@@ -0,0 +1,77 @@
|
||||
This library has been created to provide RTC capabilities on AVR devices with the ability to connect a 32kHz watch crystal on Timer 2, such as the Goldilocks ATMega1284p, and the Arduino Mega ATmega2560.
|
||||
|
||||
It is not compatible with the Arduino tones.h functions, as the tones library has not been fully implemented to use another timer other than Timer 2.
|
||||
|
||||
## General
|
||||
|
||||
The AVR standard time implementation aspires to conform with ISO/IEC 9899 (C90). However, due to limitations of the target processor and the nature of its development environment, a practical implementation must of necessity deviate from the standard.
|
||||
|
||||
## Reference Manual
|
||||
|
||||
http://www.nongnu.org/avr-libc/user-manual/group__avr__time.html
|
||||
|
||||
The tm structure contains a representation of time 'broken down' into components of the Gregorian calendar.
|
||||
|
||||
The normal ranges of the elements of tm are...
|
||||
```
|
||||
tm_sec seconds after the minute - [ 0 to 59 ]
|
||||
tm_min minutes after the hour - [ 0 to 59 ]
|
||||
tm_hour hours since midnight - [ 0 to 23 ]
|
||||
tm_mday day of the month - [ 1 to 31 ]
|
||||
tm_wday days since Sunday - [ 0 to 6 ]
|
||||
tm_mon months since January - [ 0 to 11 ]
|
||||
tm_year years since 2000
|
||||
tm_yday days since January 1 - [ 0 to 365 ]
|
||||
tm_isdst Daylight Saving Time flag
|
||||
```
|
||||
|
||||
## Compatibility
|
||||
|
||||
* ATmega1284p @ 24.576MHz : Seeed Studio Goldilocks, Seeed Studio Goldilocks Analogue
|
||||
* ATmega2560 @ 16MHz : Arduino Mega, Arduino ADK
|
||||
* ATmega2560 @ 16MHz : Seeed Studio ADK
|
||||
|
||||
## Files & Configuration
|
||||
|
||||
* AVR_RTC.h : contains the definitions for all functions.
|
||||
* setup_RTC_interrupt() : this initialises Timer2, and the "once per second" RTC interrupt.
|
||||
|
||||
Example code for basic functions below.
|
||||
|
||||
```
|
||||
#include <AVR_RTC.h>
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
|
||||
setup_RTC_interrupt(); // initialise the RTC.
|
||||
|
||||
Serial.begin(38400); // open the serial port at 38400 bps.
|
||||
|
||||
tm CurrTimeDate; // set up an array for the RTC info.
|
||||
// <year yyyy> <month mm Jan=0> <date dd> <day d Sun=0> <hour hh> <minute mm> <second ss>
|
||||
|
||||
CurrTimeDate.tm_year = (uint8_t)( 2016 - 1900 );
|
||||
CurrTimeDate.tm_mon = (uint8_t) 0;
|
||||
CurrTimeDate.tm_mday = (uint8_t) 12;
|
||||
CurrTimeDate.tm_wday = (uint8_t) 2;
|
||||
CurrTimeDate.tm_hour = (uint8_t) 17;
|
||||
CurrTimeDate.tm_min = (uint8_t) 16;
|
||||
CurrTimeDate.tm_sec = (uint8_t) 0;
|
||||
|
||||
set_system_time( mktime( (tm*)&CurrTimeDate ) );
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
|
||||
time_t currentTick; // set up a location for the current time stamp.
|
||||
|
||||
time((time_t *)¤tTick); // get the current time stamp.
|
||||
|
||||
Serial.println(ctime( (time_t *)¤tTick));
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
```
|
||||
|
||||
85
libraries/AVR_Standard_C_Time_Library/src/AVR_RTC.h
Normal file
85
libraries/AVR_Standard_C_Time_Library/src/AVR_RTC.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* (C)2020 Phillip Stevens All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer. Redistributions in binary
|
||||
* form must reproduce the above copyright notice, this list of conditions
|
||||
* and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution. Neither the name of the copyright holders
|
||||
* nor the names of contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef AVR_RTC_H
|
||||
#define AVR_RTC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
The tm structure contains a representation of time 'broken down' into components of the
|
||||
Gregorian calendar.
|
||||
|
||||
The normal ranges of the elements are..
|
||||
|
||||
\code
|
||||
tm_sec seconds after the minute - [ 0 to 59 ]
|
||||
tm_min minutes after the hour - [ 0 to 59 ]
|
||||
tm_hour hours since midnight - [ 0 to 23 ]
|
||||
tm_mday day of the month - [ 1 to 31 ]
|
||||
tm_wday days since Sunday - [ 0 to 6 ]
|
||||
tm_mon months since January - [ 0 to 11 ]
|
||||
tm_year years since 2000
|
||||
tm_yday days since January 1 - [ 0 to 365 ]
|
||||
tm_isdst Daylight Saving Time flag *
|
||||
|
||||
\endcode
|
||||
|
||||
*The value of tm_isdst is zero if Daylight Saving Time is not in effect, and is negative if
|
||||
the information is not available.
|
||||
|
||||
When Daylight Saving Time is in effect, the value represents the number of
|
||||
seconds the clock is advanced.
|
||||
*/
|
||||
|
||||
typedef struct tm tm;
|
||||
|
||||
/**
|
||||
Convert a Y2K time stamp into a FAT file system time stamp.
|
||||
*/
|
||||
uint32_t system_fatfs(const struct tm * timeptr);
|
||||
|
||||
/**
|
||||
Convert a FAT file system time stamp into a Y2K time stamp.
|
||||
*/
|
||||
uint32_t fatfs_system( uint16_t fsdate, uint16_t fstime, struct tm * timeptr);
|
||||
|
||||
/**
|
||||
* Perform hardware setup to enable 1 second sys_tick() from RTC on Timer 2.
|
||||
*/
|
||||
void setup_RTC_interrupt( void );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AVR_RTC_H */
|
||||
99
libraries/AVR_Standard_C_Time_Library/src/fatfs_time.c
Normal file
99
libraries/AVR_Standard_C_Time_Library/src/fatfs_time.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* (C)2012 Michael Duane Rice All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer. Redistributions in binary
|
||||
* form must reproduce the above copyright notice, this list of conditions
|
||||
* and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution. Neither the name of the copyright holders
|
||||
* nor the names of contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
Return a value suitable for use as a FAT file system time stamp.
|
||||
*/
|
||||
|
||||
#include "AVR_RTC.h"
|
||||
|
||||
uint32_t
|
||||
system_fatfs(const struct tm * timeptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint32_t n;
|
||||
|
||||
n = timeptr->tm_year - 80;
|
||||
n <<= 25;
|
||||
ret = n;
|
||||
|
||||
n = timeptr->tm_mon + 1;
|
||||
n <<= 21;
|
||||
ret |= n;
|
||||
|
||||
n = timeptr->tm_mday;
|
||||
n <<= 16;
|
||||
ret |= n;
|
||||
|
||||
n = timeptr->tm_hour;
|
||||
n <<= 11;
|
||||
ret |= n;
|
||||
|
||||
n = timeptr->tm_min;
|
||||
n <<= 5;
|
||||
ret |= n;
|
||||
|
||||
ret |= timeptr->tm_sec >> 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert a FAT file system time stamp into a Y2K time stamp.
|
||||
|
||||
wFatDate [in]
|
||||
The MS-DOS date. The date is a packed value with the following format.
|
||||
Bits Description
|
||||
0-4 Day of the month (1–31)
|
||||
5-8 Month (1 = January, 2 = February, and so on)
|
||||
9-15 Year offset from 1980, subtract 20 to get Y2K year, add 2000 for Gregorian year.
|
||||
|
||||
wFatTime [in]
|
||||
The MS-DOS time. The time is a packed value with the following format.
|
||||
Bits Description
|
||||
0-4 Second divided by 2
|
||||
5-10 Minute (0–59)
|
||||
11-15 Hour (0–23 on a 24-hour clock)
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
fatfs_system( uint16_t fsdate, uint16_t fstime, struct tm * timeptr)
|
||||
{
|
||||
timeptr->tm_year = ((fsdate >> 9) & 0x007F) + 80;
|
||||
timeptr->tm_mon = ((uint8_t)(fsdate >> 5 ) & 0x0F) - 1;
|
||||
timeptr->tm_mday = (uint8_t) fsdate & 0x1F;
|
||||
|
||||
timeptr->tm_hour = (uint8_t)(fstime >> 11) & 0x1F;
|
||||
timeptr->tm_min = (uint8_t)(fstime >> 5) & 0x3F;
|
||||
timeptr->tm_sec = ((uint8_t) fstime & 0x001F) << 1;
|
||||
return mktime( timeptr );
|
||||
}
|
||||
|
||||
50
libraries/AVR_Standard_C_Time_Library/src/timer2.c
Normal file
50
libraries/AVR_Standard_C_Time_Library/src/timer2.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Set up the RTC based on using the AVR Timer 2 attached Clock Crystal.
|
||||
Developed for the Goldilocks Analogue, but also relevant for the Arduino Mega
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <util/atomic.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "AVR_RTC.h"
|
||||
|
||||
void
|
||||
setup_RTC_interrupt( void )
|
||||
{
|
||||
|
||||
/* Using 8bit Timer2 to generate the tick.
|
||||
* A 32.768 KHz crystal must be attached to the appropriate pins.
|
||||
* We then adjust the scale factor and counter to roll over at the top
|
||||
* so we can get EXACT seconds for the Real Time clock.
|
||||
*
|
||||
* This code is correct for an ATmega328p (Arduino Uno) but will fail to function
|
||||
* because the pins are used for an external crystal.
|
||||
*/
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
TIMSK2 &= ~( _BV(OCIE2B)|_BV(OCIE2A)|_BV(TOIE2) ); // disable all Timer2 interrupts
|
||||
TIFR2 |= _BV(OCF2B)|_BV(OCF2A)|_BV(TOV2); // clear all pending interrupts
|
||||
ASSR = _BV(AS2); // set Timer/Counter2 to be asynchronous from the CPU clock
|
||||
// with a second external clock (32,768kHz) driving it.
|
||||
TCNT2 = 0x00; // zero out the counter
|
||||
TCCR2A = 0x00; // Normal mode
|
||||
TCCR2B = _BV(CS22) | _BV(CS20); // divide timer clock by 128 so counter will roll over at MAX
|
||||
|
||||
while( ASSR & (_BV(TCN2UB)|_BV(OCR2AUB)|_BV(TCR2AUB))); // Wait until Timer2 update complete
|
||||
|
||||
/* Enable the interrupt - this is okay as interrupts are currently globally disabled. */
|
||||
TIMSK2 |= _BV(TOIE2); // When the TOIE2 bit is written to one, the interrupt is enabled
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tick ISR for the RTC. All this does is increment the RTC tick count, once per second.
|
||||
* Use ISR_NOBLOCK where there is an important timer running, that should preempt the RTC.
|
||||
* As long as it completes within one second, then there is no issue.
|
||||
*/
|
||||
ISR(TIMER2_OVF_vect, ISR_NAKED ISR_NOBLOCK ) __attribute__ ((hot, flatten));
|
||||
ISR(TIMER2_OVF_vect)
|
||||
{
|
||||
system_tick();
|
||||
reti();
|
||||
}
|
||||
508
libraries/Adafruit_ADXL343/Adafruit_ADXL343.cpp
Normal file
508
libraries/Adafruit_ADXL343/Adafruit_ADXL343.cpp
Normal file
@@ -0,0 +1,508 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file Adafruit_ADXL343.cpp
|
||||
@author Bryan Siepert and K.Townsend (Adafruit Industries)
|
||||
|
||||
BSD License (see license.txt)
|
||||
|
||||
The ADXL343 is a digital accelerometer with 13-bit resolution, capable
|
||||
of measuring up to +/-16g. This driver communicates using I2C.
|
||||
|
||||
This is a library for the Adafruit ADXL343 breakout
|
||||
----> https://www.adafruit.com/product/4097
|
||||
or the Adafruit ADXL343 + ADT7410 FeatherWing
|
||||
----> https://www.adafruit.com/product/4147
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
v1.0 - First release
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "Adafruit_ADXL343.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes 8-bits to the specified destination register
|
||||
|
||||
@param reg The register to write to
|
||||
@param value The value to write to the register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
void Adafruit_ADXL343::writeRegister(uint8_t reg, uint8_t value) {
|
||||
Adafruit_BusIO_Register reg_obj = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, reg, 1);
|
||||
reg_obj.write(value);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads 8-bits from the specified register
|
||||
|
||||
@param reg register to read
|
||||
|
||||
@return The results of the register read request
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t Adafruit_ADXL343::readRegister(uint8_t reg) {
|
||||
Adafruit_BusIO_Register reg_obj = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, reg, 1);
|
||||
return ((uint8_t)reg_obj.read());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads 16-bits from the specified register
|
||||
|
||||
@param reg The register to read two bytes from
|
||||
|
||||
@return The 16-bit value read from the reg starting address
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
int16_t Adafruit_ADXL343::read16(uint8_t reg) {
|
||||
Adafruit_BusIO_Register reg_obj = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, reg, 2);
|
||||
return ((uint16_t)reg_obj.read());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the device ID (can be used to check connection)
|
||||
|
||||
@return The 8-bit device ID
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t Adafruit_ADXL343::getDeviceID(void) {
|
||||
// Check device ID register
|
||||
return readRegister(ADXL3XX_REG_DEVID);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enables (1) or disables (0) the interrupts on the specified
|
||||
interrupt pin.
|
||||
|
||||
@param cfg The bitfield of the interrupts to enable or disable.
|
||||
|
||||
@return True if the operation was successful, otherwise false.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_ADXL343::enableInterrupts(int_config cfg) {
|
||||
/* Update the INT_ENABLE register with 'config'. */
|
||||
writeRegister(ADXL3XX_REG_INT_ENABLE, cfg.value);
|
||||
|
||||
/* ToDo: Add proper error checking! */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief 'Maps' the specific interrupt to either pin INT1 (bit=0),
|
||||
of pin INT2 (bit=1).
|
||||
|
||||
@param cfg The bitfield of the interrupts to enable or disable.
|
||||
|
||||
@return True if the operation was successful, otherwise false.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_ADXL343::mapInterrupts(int_config cfg) {
|
||||
/* Update the INT_MAP register with 'config'. */
|
||||
writeRegister(ADXL3XX_REG_INT_MAP, cfg.value);
|
||||
|
||||
/* ToDo: Add proper error checking! */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the status of the interrupt pins. Reading this register
|
||||
also clears or deasserts any currently active interrupt.
|
||||
|
||||
@return The 8-bit content of the INT_SOURCE register.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t Adafruit_ADXL343::checkInterrupts(void) {
|
||||
return readRegister(ADXL3XX_REG_INT_SOURCE);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent X axis value
|
||||
|
||||
@return The 16-bit signed value for the X axis
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int16_t Adafruit_ADXL343::getX(void) { return read16(ADXL3XX_REG_DATAX0); }
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent Y axis value
|
||||
|
||||
@return The 16-bit signed value for the Y axis
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int16_t Adafruit_ADXL343::getY(void) { return read16(ADXL3XX_REG_DATAY0); }
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent Z axis value
|
||||
|
||||
@return The 16-bit signed value for the Z axis
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int16_t Adafruit_ADXL343::getZ(void) { return read16(ADXL3XX_REG_DATAZ0); }
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads 3x16-bits from the x, y, and z data register
|
||||
@param x reference to return x acceleration data
|
||||
@param y reference to return y acceleration data
|
||||
@param z reference to return z acceleration data
|
||||
@return True if the operation was successful, otherwise false.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_ADXL343::getXYZ(int16_t &x, int16_t &y, int16_t &z) {
|
||||
int16_t buffer[] = {0, 0, 0};
|
||||
Adafruit_BusIO_Register reg_obj = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_DATAX0, 6);
|
||||
if (!reg_obj.read((uint8_t *)&buffer, 6))
|
||||
return false;
|
||||
x = buffer[0];
|
||||
y = buffer[1];
|
||||
z = buffer[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
* @brief Instantiates a new ADXL343 class
|
||||
*
|
||||
* @param sensorID An optional ID # so you can track this sensor, it will
|
||||
* tag sensorEvents you create.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_ADXL343::Adafruit_ADXL343(int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
_wire = &Wire;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
* @brief Instantiates a new ADXL343 class
|
||||
*
|
||||
* @param sensorID An optional ID # so you can track this sensor, it will
|
||||
* tag sensorEvents you create.
|
||||
* @param wireBus TwoWire instance to use for I2C communication.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_ADXL343::Adafruit_ADXL343(int32_t sensorID, TwoWire *wireBus) {
|
||||
_sensorID = sensorID;
|
||||
_wire = wireBus;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new ADXL343 class in software SPI mode
|
||||
|
||||
@param clock The SCK pin
|
||||
@param miso The MISO pin
|
||||
@param mosi The MOSI pin
|
||||
@param cs The CS/SSEL pin
|
||||
@param sensorID An optional ID # so you can track this sensor, it will tag
|
||||
sensorEvents you create.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_ADXL343::Adafruit_ADXL343(uint8_t clock, uint8_t miso, uint8_t mosi,
|
||||
uint8_t cs, int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
_cs = cs;
|
||||
_clk = clock;
|
||||
_do = mosi;
|
||||
_di = miso;
|
||||
_wire = NULL;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new ADXL343 class in hardware SPI mode
|
||||
|
||||
@param cs The CS/SSEL pin
|
||||
@param theSPI SPIClass instance to use for SPI communication.
|
||||
@param sensorID An optional ID # so you can track this sensor, it will tag
|
||||
sensorEvents you create.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_ADXL343::Adafruit_ADXL343(uint8_t cs, SPIClass *theSPI,
|
||||
int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
_cs = cs;
|
||||
_spi = theSPI;
|
||||
_wire = NULL;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW (reads coefficients values, etc.)
|
||||
@param i2caddr The 7-bit I2C address to find the ADXL on
|
||||
@return True if the sensor was successfully initialised.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_ADXL343::begin(uint8_t i2caddr) {
|
||||
|
||||
if (_wire) {
|
||||
//-- I2C --------------
|
||||
if (i2c_dev) {
|
||||
delete i2c_dev; // remove old interface
|
||||
}
|
||||
i2c_dev = new Adafruit_I2CDevice(i2caddr, _wire);
|
||||
|
||||
if (!i2c_dev->begin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
//-- SPI --------------
|
||||
i2c_dev = NULL;
|
||||
|
||||
if (spi_dev) {
|
||||
delete spi_dev; // remove old interface
|
||||
}
|
||||
if (_spi) {
|
||||
// hardware spi
|
||||
spi_dev = new Adafruit_SPIDevice(_cs,
|
||||
1000000, // frequency
|
||||
SPI_BITORDER_MSBFIRST, // bit order
|
||||
SPI_MODE3, // data mode
|
||||
_spi); // hardware SPI
|
||||
} else {
|
||||
// software spi
|
||||
spi_dev = new Adafruit_SPIDevice(_cs, _clk, _di, _do,
|
||||
1000000, // frequency
|
||||
SPI_BITORDER_MSBFIRST, // bit order
|
||||
SPI_MODE3); // data mode
|
||||
}
|
||||
|
||||
if (!spi_dev->begin()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check connection */
|
||||
uint8_t deviceid = getDeviceID();
|
||||
if (deviceid != 0xE5) {
|
||||
/* No ADXL343 detected ... return false */
|
||||
return false;
|
||||
}
|
||||
|
||||
_range = ADXL343_RANGE_2_G;
|
||||
// Default tap detection level (2G, 31.25ms duration, single tap only)
|
||||
// If only the single tap function is in use, the single tap interrupt
|
||||
// is triggered when the acceleration goes below the threshold, as
|
||||
// long as DUR has not been exceeded.
|
||||
writeRegister(ADXL3XX_REG_INT_ENABLE, 0); // Disable interrupts to start
|
||||
writeRegister(ADXL3XX_REG_THRESH_TAP, 20); // 62.5 mg/LSB (so 0xFF = 16 g)
|
||||
writeRegister(ADXL3XX_REG_DUR, 50); // Max tap duration, 625 µs/LSB
|
||||
writeRegister(ADXL3XX_REG_LATENT,
|
||||
0); // Tap latency, 1.25 ms/LSB, 0=no double tap
|
||||
writeRegister(ADXL3XX_REG_WINDOW,
|
||||
0); // Waiting period, 1.25 ms/LSB, 0=no double tap
|
||||
writeRegister(ADXL3XX_REG_TAP_AXES, 0x7); // Enable the XYZ axis for tap
|
||||
|
||||
// Enable measurements
|
||||
writeRegister(ADXL3XX_REG_POWER_CTL, 0x08);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the g range for the accelerometer
|
||||
|
||||
@param range The range to set, based on adxl34x_range_t
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_ADXL343::setRange(adxl34x_range_t range) {
|
||||
Adafruit_BusIO_Register data_format_reg =
|
||||
Adafruit_BusIO_Register(i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC,
|
||||
ADXL3XX_REG_DATA_FORMAT, 1);
|
||||
|
||||
Adafruit_BusIO_RegisterBits range_bits =
|
||||
Adafruit_BusIO_RegisterBits(&data_format_reg, 2, 0);
|
||||
|
||||
Adafruit_BusIO_RegisterBits full_range_bit =
|
||||
Adafruit_BusIO_RegisterBits(&data_format_reg, 1, 3);
|
||||
|
||||
/* Update the data rate */
|
||||
range_bits.write(range);
|
||||
/* Make sure that the FULL-RES bit is enabled for range scaling */
|
||||
full_range_bit.write(true);
|
||||
|
||||
/* Keep track of the current range (to avoid readbacks) */
|
||||
_range = range;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the g range for the accelerometer
|
||||
|
||||
@return The adxl34x_range_t value corresponding to the sensors range
|
||||
*/
|
||||
/**************************************************************************/
|
||||
adxl34x_range_t Adafruit_ADXL343::getRange(void) {
|
||||
Adafruit_BusIO_Register data_format_reg =
|
||||
Adafruit_BusIO_Register(i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC,
|
||||
ADXL3XX_REG_DATA_FORMAT, 1);
|
||||
|
||||
Adafruit_BusIO_RegisterBits range_bits =
|
||||
Adafruit_BusIO_RegisterBits(&data_format_reg, 2, 0);
|
||||
return (adxl34x_range_t)range_bits.read();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the data rate for the ADXL343 (controls power consumption)
|
||||
|
||||
@param dataRate The data rate to set, based on adxl3xx_dataRate_t
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_ADXL343::setDataRate(adxl3xx_dataRate_t dataRate) {
|
||||
/* Note: The LOW_POWER bits are currently ignored and we always keep
|
||||
the device in 'normal' mode */
|
||||
writeRegister(ADXL3XX_REG_BW_RATE, dataRate);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the data rate for the ADXL343 (controls power consumption)
|
||||
|
||||
@return The current data rate, based on adxl3xx_dataRate_t
|
||||
*/
|
||||
/**************************************************************************/
|
||||
adxl3xx_dataRate_t Adafruit_ADXL343::getDataRate(void) {
|
||||
Adafruit_BusIO_Register bw_rate_reg = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_BW_RATE, 1);
|
||||
|
||||
Adafruit_BusIO_RegisterBits rate_bits =
|
||||
Adafruit_BusIO_RegisterBits(&bw_rate_reg, 4, 0);
|
||||
|
||||
return (adxl3xx_dataRate_t)rate_bits.read();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Retrieves the X Y Z trim offsets, note that they are 4 bits signed
|
||||
but we use int8_t to store and 'extend' the sign bit!
|
||||
@param x Pointer to the x offset, from -5 to 4 (internally multiplied by 8
|
||||
lsb)
|
||||
@param y Pointer to the y offset, from -5 to 4 (internally multiplied by 8
|
||||
lsb)
|
||||
@param z Pointer to the z offset, from -5 to 4 (internally multiplied by 8
|
||||
lsb)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_ADXL343::getTrimOffsets(int8_t *x, int8_t *y, int8_t *z) {
|
||||
Adafruit_BusIO_Register x_off = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSX, 1);
|
||||
if (x != NULL)
|
||||
*x = x_off.read();
|
||||
Adafruit_BusIO_Register y_off = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSY, 1);
|
||||
if (y != NULL)
|
||||
*y = y_off.read();
|
||||
Adafruit_BusIO_Register z_off = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSZ, 1);
|
||||
if (z != NULL)
|
||||
*z = z_off.read();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the X Y Z trim offsets, note that they are 4 bits signed
|
||||
but we use int8_t to store and 'extend' the sign bit!
|
||||
@param x The x offset, from -5 to 4 (internally multiplied by 8 lsb)
|
||||
@param y The y offset, from -5 to 4 (internally multiplied by 8 lsb)
|
||||
@param z The z offset, from -5 to 4 (internally multiplied by 8 lsb)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_ADXL343::setTrimOffsets(int8_t x, int8_t y, int8_t z) {
|
||||
Adafruit_BusIO_Register x_off = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSX, 1);
|
||||
x_off.write(x);
|
||||
|
||||
Adafruit_BusIO_Register y_off = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSY, 1);
|
||||
y_off.write(y);
|
||||
|
||||
Adafruit_BusIO_Register z_off = Adafruit_BusIO_Register(
|
||||
i2c_dev, spi_dev, AD8_HIGH_TOREAD_AD7_HIGH_TOINC, ADXL3XX_REG_OFSZ, 1);
|
||||
z_off.write(z);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent sensor event
|
||||
|
||||
@param event Pointer to the sensors_event_t placeholder
|
||||
|
||||
@return True of the read request was successful.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_ADXL343::getEvent(sensors_event_t *event) {
|
||||
int16_t x, y, z;
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_ACCELEROMETER;
|
||||
event->timestamp = millis();
|
||||
if (!getXYZ(x, y, z))
|
||||
return false;
|
||||
event->acceleration.x =
|
||||
x * ADXL343_MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
|
||||
event->acceleration.y =
|
||||
y * ADXL343_MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
|
||||
event->acceleration.z =
|
||||
z * ADXL343_MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data
|
||||
|
||||
@param sensor Pointer to the sensor_t placeholder.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_ADXL343::getSensor(sensor_t *sensor) {
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy(sensor->name, "ADXL343", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name) - 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_ACCELEROMETER;
|
||||
sensor->min_delay = 0;
|
||||
sensor->min_value = -156.9064F; /* -16g = 156.9064 m/s^2 */
|
||||
sensor->max_value = 156.9064F; /* 16g = 156.9064 m/s^2 */
|
||||
sensor->resolution = 0.03923F; /* 4mg = 0.0392266 m/s^2 */
|
||||
}
|
||||
204
libraries/Adafruit_ADXL343/Adafruit_ADXL343.h
Normal file
204
libraries/Adafruit_ADXL343/Adafruit_ADXL343.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file Adafruit_ADXL343.h
|
||||
@author Bryan Siepert and K. Townsend (Adafruit Industries)
|
||||
|
||||
BSD license (see license.txt)
|
||||
|
||||
This is a library for the Adafruit ADS1015 breakout board
|
||||
----> https://www.adafruit.com/products/???
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
v1.0 - First release
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#ifndef _ADAFRUIT_SENSOR_ADXL343_H
|
||||
#define _ADAFRUIT_SENSOR_ADXL343_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Adafruit_BusIO_Register.h>
|
||||
#include <Adafruit_I2CDevice.h>
|
||||
#include <Adafruit_SPIDevice.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Wire.h>
|
||||
|
||||
/*=========================================================================
|
||||
I2C ADDRESS/BITS
|
||||
-----------------------------------------------------------------------*/
|
||||
#define ADXL343_ADDRESS (0x53) /**< Assumes ALT address pin low */
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
REGISTERS
|
||||
-----------------------------------------------------------------------*/
|
||||
#define ADXL3XX_REG_DEVID (0x00) /**< Device ID */
|
||||
#define ADXL3XX_REG_THRESH_TAP (0x1D) /**< Tap threshold */
|
||||
#define ADXL3XX_REG_OFSX (0x1E) /**< X-axis offset */
|
||||
#define ADXL3XX_REG_OFSY (0x1F) /**< Y-axis offset */
|
||||
#define ADXL3XX_REG_OFSZ (0x20) /**< Z-axis offset */
|
||||
#define ADXL3XX_REG_DUR (0x21) /**< Tap duration */
|
||||
#define ADXL3XX_REG_LATENT (0x22) /**< Tap latency */
|
||||
#define ADXL3XX_REG_WINDOW (0x23) /**< Tap window */
|
||||
#define ADXL3XX_REG_THRESH_ACT (0x24) /**< Activity threshold */
|
||||
#define ADXL3XX_REG_THRESH_INACT (0x25) /**< Inactivity threshold */
|
||||
#define ADXL3XX_REG_TIME_INACT (0x26) /**< Inactivity time */
|
||||
#define ADXL3XX_REG_ACT_INACT_CTL \
|
||||
(0x27) /**< Axis enable control for activity and inactivity detection */
|
||||
#define ADXL3XX_REG_THRESH_FF (0x28) /**< Free-fall threshold */
|
||||
#define ADXL3XX_REG_TIME_FF (0x29) /**< Free-fall time */
|
||||
#define ADXL3XX_REG_TAP_AXES (0x2A) /**< Axis control for single/double tap */
|
||||
#define ADXL3XX_REG_ACT_TAP_STATUS (0x2B) /**< Source for single/double tap */
|
||||
#define ADXL3XX_REG_BW_RATE (0x2C) /**< Data rate and power mode control */
|
||||
#define ADXL3XX_REG_POWER_CTL (0x2D) /**< Power-saving features control */
|
||||
#define ADXL3XX_REG_INT_ENABLE (0x2E) /**< Interrupt enable control */
|
||||
#define ADXL3XX_REG_INT_MAP (0x2F) /**< Interrupt mapping control */
|
||||
#define ADXL3XX_REG_INT_SOURCE (0x30) /**< Source of interrupts */
|
||||
#define ADXL3XX_REG_DATA_FORMAT (0x31) /**< Data format control */
|
||||
#define ADXL3XX_REG_DATAX0 (0x32) /**< X-axis data 0 */
|
||||
#define ADXL3XX_REG_DATAX1 (0x33) /**< X-axis data 1 */
|
||||
#define ADXL3XX_REG_DATAY0 (0x34) /**< Y-axis data 0 */
|
||||
#define ADXL3XX_REG_DATAY1 (0x35) /**< Y-axis data 1 */
|
||||
#define ADXL3XX_REG_DATAZ0 (0x36) /**< Z-axis data 0 */
|
||||
#define ADXL3XX_REG_DATAZ1 (0x37) /**< Z-axis data 1 */
|
||||
#define ADXL3XX_REG_FIFO_CTL (0x38) /**< FIFO control */
|
||||
#define ADXL3XX_REG_FIFO_STATUS (0x39) /**< FIFO status */
|
||||
/*=========================================================================*/
|
||||
|
||||
/*=========================================================================
|
||||
REGISTERS
|
||||
-----------------------------------------------------------------------*/
|
||||
#define ADXL343_MG2G_MULTIPLIER (0.004) /**< 4mg per lsb */
|
||||
/*=========================================================================*/
|
||||
|
||||
/** Used with register 0x2C (ADXL3XX_REG_BW_RATE) to set bandwidth */
|
||||
typedef enum {
|
||||
ADXL343_DATARATE_3200_HZ = 0b1111, /**< 3200Hz Bandwidth */
|
||||
ADXL343_DATARATE_1600_HZ = 0b1110, /**< 1600Hz Bandwidth */
|
||||
ADXL343_DATARATE_800_HZ = 0b1101, /**< 800Hz Bandwidth */
|
||||
ADXL343_DATARATE_400_HZ = 0b1100, /**< 400Hz Bandwidth */
|
||||
ADXL343_DATARATE_200_HZ = 0b1011, /**< 200Hz Bandwidth */
|
||||
ADXL343_DATARATE_100_HZ = 0b1010, /**< 100Hz Bandwidth */
|
||||
ADXL343_DATARATE_50_HZ = 0b1001, /**< 50Hz Bandwidth */
|
||||
ADXL343_DATARATE_25_HZ = 0b1000, /**< 25Hz Bandwidth */
|
||||
ADXL343_DATARATE_12_5_HZ = 0b0111, /**< 12.5Hz Bandwidth */
|
||||
ADXL343_DATARATE_6_25HZ = 0b0110, /**< 6.25Hz Bandwidth */
|
||||
ADXL343_DATARATE_3_13_HZ = 0b0101, /**< 3.13Hz Bandwidth */
|
||||
ADXL343_DATARATE_1_56_HZ = 0b0100, /**< 1.56Hz Bandwidth */
|
||||
ADXL343_DATARATE_0_78_HZ = 0b0011, /**< 0.78Hz Bandwidth */
|
||||
ADXL343_DATARATE_0_39_HZ = 0b0010, /**< 0.39Hz Bandwidth */
|
||||
ADXL343_DATARATE_0_20_HZ = 0b0001, /**< 0.20Hz Bandwidth */
|
||||
ADXL343_DATARATE_0_10_HZ = 0b0000, /**< 0.10Hz Bandwidth (default value) */
|
||||
|
||||
ADXL3XX_DATARATE_3200_HZ = 0b1111, /**< 3200Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_1600_HZ = 0b1110, /**< 1600Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_800_HZ = 0b1101, /**< 800Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_400_HZ = 0b1100, /**< 400Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_200_HZ = 0b1011, /**< 200Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_100_HZ = 0b1010, /**< 100Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_50_HZ = 0b1001, /**< 50Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_25_HZ = 0b1000, /**< 25Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_12_5_HZ = 0b0111, /**< 12.5Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_6_25HZ = 0b0110, /**< 6.25Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_3_13_HZ = 0b0101, /**< 3.13Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_1_56_HZ = 0b0100, /**< 1.56Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_0_78_HZ = 0b0011, /**< 0.78Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_0_39_HZ = 0b0010, /**< 0.39Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_0_20_HZ = 0b0001, /**< 0.20Hz Bandwidth */
|
||||
ADXL3XX_DATARATE_0_10_HZ = 0b0000 /**< 0.10Hz Bandwidth (default value) */
|
||||
} adxl3xx_dataRate_t;
|
||||
|
||||
/** Used with register 0x31 (ADXL3XX_REG_DATA_FORMAT) to set g range */
|
||||
typedef enum {
|
||||
ADXL343_RANGE_16_G = 0b11, /**< +/- 16g */
|
||||
ADXL343_RANGE_8_G = 0b10, /**< +/- 8g */
|
||||
ADXL343_RANGE_4_G = 0b01, /**< +/- 4g */
|
||||
ADXL343_RANGE_2_G = 0b00, /**< +/- 2g (default value) */
|
||||
|
||||
ADXL34X_RANGE_16_G = 0b11, /**< +/- 16g */
|
||||
ADXL34X_RANGE_8_G = 0b10, /**< +/- 8g */
|
||||
ADXL34X_RANGE_4_G = 0b01, /**< +/- 4g */
|
||||
ADXL34X_RANGE_2_G = 0b00 /**< +/- 2g (default value) */
|
||||
} adxl34x_range_t;
|
||||
|
||||
/** Possible interrupts sources on the ADXL343. */
|
||||
union int_config {
|
||||
uint8_t value; /**< Composite 8-bit value of the bitfield.*/
|
||||
struct {
|
||||
uint8_t overrun : 1; /**< Bit 0 */
|
||||
uint8_t watermark : 1; /**< Bit 1 */
|
||||
uint8_t freefall : 1; /**< Bit 2 */
|
||||
uint8_t inactivity : 1; /**< Bit 3 */
|
||||
uint8_t activity : 1; /**< Bit 4 */
|
||||
uint8_t double_tap : 1; /**< Bit 5 */
|
||||
uint8_t single_tap : 1; /**< Bit 6 */
|
||||
uint8_t data_ready : 1; /**< Bit 7 */
|
||||
} bits; /**< Individual bits in the bitfield. */
|
||||
};
|
||||
|
||||
/** Possible interrupt pin outputs on the ADXL343. */
|
||||
typedef enum {
|
||||
ADXL343_INT1 = 0,
|
||||
ADXL343_INT2 = 1,
|
||||
ADXL3XX_INT1 = 0,
|
||||
ADXL3XX_INT2 = 1,
|
||||
} adxl3xx_int_pin;
|
||||
|
||||
/**
|
||||
* Driver for the Adafruit ADXL343 breakout.
|
||||
*/
|
||||
class Adafruit_ADXL343 : public Adafruit_Sensor {
|
||||
public:
|
||||
Adafruit_ADXL343(int32_t sensorID);
|
||||
Adafruit_ADXL343(int32_t sensorID, TwoWire *wireBus);
|
||||
Adafruit_ADXL343(uint8_t clock, uint8_t miso, uint8_t mosi, uint8_t cs,
|
||||
int32_t sensorID = -1);
|
||||
Adafruit_ADXL343(uint8_t cs, SPIClass *theSPI, int32_t sensorID = -1);
|
||||
|
||||
bool begin(uint8_t i2caddr = ADXL343_ADDRESS);
|
||||
void setRange(adxl34x_range_t range);
|
||||
adxl34x_range_t getRange(void);
|
||||
void setDataRate(adxl3xx_dataRate_t dataRate);
|
||||
adxl3xx_dataRate_t getDataRate(void);
|
||||
bool getEvent(sensors_event_t *);
|
||||
void getSensor(sensor_t *);
|
||||
|
||||
uint8_t getDeviceID(void);
|
||||
void writeRegister(uint8_t reg, uint8_t value);
|
||||
uint8_t readRegister(uint8_t reg);
|
||||
int16_t read16(uint8_t reg);
|
||||
|
||||
bool enableInterrupts(int_config cfg);
|
||||
bool mapInterrupts(int_config cfg);
|
||||
uint8_t checkInterrupts(void);
|
||||
|
||||
void getTrimOffsets(int8_t *x, int8_t *y, int8_t *z);
|
||||
void setTrimOffsets(int8_t x, int8_t y, int8_t z);
|
||||
|
||||
int16_t getX(void);
|
||||
int16_t getY(void);
|
||||
int16_t getZ(void);
|
||||
bool getXYZ(int16_t &x, int16_t &y, int16_t &z);
|
||||
|
||||
protected:
|
||||
Adafruit_SPIDevice *spi_dev = NULL; ///< BusIO SPI device
|
||||
Adafruit_I2CDevice *i2c_dev = NULL; ///< BusIO I2C device
|
||||
|
||||
TwoWire *_wire = NULL; ///< I2C hardware interface
|
||||
SPIClass *_spi = NULL; ///< SPI hardware interface
|
||||
int32_t _sensorID; ///< User-set sensor identifier
|
||||
adxl34x_range_t _range; ///< cache of range
|
||||
uint8_t _clk, ///< SPI software clock
|
||||
_do, ///< SPI software data out
|
||||
_di, ///< SPI software data in
|
||||
_cs; ///< SPI software chip select
|
||||
};
|
||||
|
||||
#endif
|
||||
29
libraries/Adafruit_ADXL343/README.md
Normal file
29
libraries/Adafruit_ADXL343/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Adafruit ADXL343 Accelerometer Driver 
|
||||
|
||||
This driver is for the Adafruit ADXL343 Breakout (https://www.adafruit.com/product/4097), and is based on Adafruit's Unified Sensor Library (Adafruit_Sensor).
|
||||
|
||||
## About the ADXL343 ##
|
||||
|
||||
The ADXL343 is a digital accelerometer that supports both SPI and I2C mode, with adjustable data rata and 'range' (+/-2/4/8/16g). The Adafruit_ADXL343 driver takes advantage of I2C mode to reduce the total pin count required to use the sensor.
|
||||
|
||||
More information on the ADXL345 can be found in the datasheet: http://www.analog.com/static/imported-files/data_sheets/ADXL343.pdf
|
||||
|
||||
## What is the Adafruit Unified Sensor Library? ##
|
||||
|
||||
The Adafruit Unified Sensor Library (https://github.com/adafruit/Adafruit_Sensor) provides a common interface and data type for any supported sensor. It defines some basic information about the sensor (sensor limits, etc.), and returns standard SI units of a specific type and scale for each supported sensor type.
|
||||
|
||||
It provides a simple abstraction layer between your application and the actual sensor HW, allowing you to drop in any comparable sensor with only one or two lines of code to change in your project (essentially the constructor since the functions to read sensor data and get information about the sensor are defined in the base Adafruit_Sensor class).
|
||||
|
||||
This is imporant useful for two reasons:
|
||||
|
||||
1.) You can use the data right away because it's already converted to SI units that you understand and can compare, rather than meaningless values like 0..1023.
|
||||
|
||||
2.) Because SI units are standardised in the sensor library, you can also do quick sanity checks working with new sensors, or drop in any comparable sensor if you need better sensitivity or if a lower cost unit becomes available, etc.
|
||||
|
||||
Light sensors will always report units in lux, gyroscopes will always report units in rad/s, etc. ... freeing you up to focus on the data, rather than digging through the datasheet to understand what the sensor's raw numbers really mean.
|
||||
|
||||
## About this Driver ##
|
||||
|
||||
Adafruit invests time and resources providing this open source code. Please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
Written by Kevin (KTOWN) Townsend for Adafruit Industries.
|
||||
149
libraries/Adafruit_ADXL343/examples/interrupts/interrupts.ino
Normal file
149
libraries/Adafruit_ADXL343/examples/interrupts/interrupts.ino
Normal file
@@ -0,0 +1,149 @@
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_ADXL343.h>
|
||||
|
||||
/* Assign a unique ID to this sensor at the same time */
|
||||
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);
|
||||
|
||||
/** The input pins to enable the interrupt on, connected to INT1 and INT2 on the ADXL. */
|
||||
#define INPUT_PIN_INT1 (5) // Uno = (2)
|
||||
#define INPUT_PIN_INT2 (6) // Uno = (3)
|
||||
|
||||
/**
|
||||
* This struct is used to count the number of times that specific interrutps
|
||||
* have been fired by the ADXL and detected on the MCU. They will increment
|
||||
* by one for each event associated with the specified interrupt 'bit'.
|
||||
*/
|
||||
struct adxl_int_stats {
|
||||
uint32_t data_ready;
|
||||
uint32_t single_tap;
|
||||
uint32_t double_tap;
|
||||
uint32_t activity;
|
||||
uint32_t inactivity;
|
||||
uint32_t freefall;
|
||||
uint32_t watermark;
|
||||
uint32_t overrun;
|
||||
uint32_t total;
|
||||
};
|
||||
|
||||
/** Global stats block, incremented inside the interrupt handler(s). */
|
||||
struct adxl_int_stats g_int_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
/** Global counter to track the numbers of unused interrupts fired. */
|
||||
uint32_t g_ints_fired = 0;
|
||||
|
||||
/** Global variable to determine which interrupt(s) are enabled on the ADXL343. */
|
||||
int_config g_int_config_enabled = { 0 };
|
||||
|
||||
/** Global variables to determine which INT pin interrupt(s) are mapped to on the ADXL343. */
|
||||
int_config g_int_config_map = { 0 };
|
||||
|
||||
/** Interrupt service routine for INT1 events. */
|
||||
void int1_isr(void)
|
||||
{
|
||||
/* By default, this sketch routes the OVERRUN interrupt to INT1. */
|
||||
g_int_stats.overrun++;
|
||||
g_int_stats.total++;
|
||||
g_ints_fired++;
|
||||
|
||||
/* TODO: Toggle an LED! */
|
||||
}
|
||||
|
||||
/** Interrupt service routine for INT2 events. */
|
||||
void int2_isr(void)
|
||||
{
|
||||
/* By default, this sketch routes the DATA_READY interrupt to INT2. */
|
||||
g_int_stats.data_ready++;
|
||||
g_int_stats.total++;
|
||||
g_ints_fired++;
|
||||
|
||||
/* TODO: Toggle an LED! */
|
||||
}
|
||||
|
||||
/** Configures the HW interrupts on the ADXL343 and the target MCU. */
|
||||
void config_interrupts(void)
|
||||
{
|
||||
/* NOTE: Once an interrupt fires on the ADXL you can read a register
|
||||
* to know the source of the interrupt, but since this would likely
|
||||
* happen in the 'interrupt context' performing an I2C read is a bad
|
||||
* idea since it will block the device from handling other interrupts
|
||||
* in a timely manner.
|
||||
*
|
||||
* The best approach is to try to make use of only two interrupts on
|
||||
* two different interrupt pins, so that when an interrupt fires, based
|
||||
* on the 'isr' function that is called, you already know the int source.
|
||||
*/
|
||||
|
||||
/* Attach interrupt inputs on the MCU. */
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
pinMode(INPUT_PIN_INT1, INPUT);
|
||||
pinMode(INPUT_PIN_INT2, INPUT);
|
||||
attachInterrupt(digitalPinToInterrupt(INPUT_PIN_INT1), int1_isr, RISING);
|
||||
attachInterrupt(digitalPinToInterrupt(INPUT_PIN_INT2), int2_isr, RISING);
|
||||
|
||||
/* Enable interrupts on the accelerometer. */
|
||||
g_int_config_enabled.bits.overrun = true; /* Set the INT1 */
|
||||
g_int_config_enabled.bits.watermark = false;
|
||||
g_int_config_enabled.bits.freefall = false;
|
||||
g_int_config_enabled.bits.inactivity = false;
|
||||
g_int_config_enabled.bits.activity = false;
|
||||
g_int_config_enabled.bits.double_tap = false;
|
||||
g_int_config_enabled.bits.single_tap = false;
|
||||
g_int_config_enabled.bits.data_ready = true; /* Set to INT2 */
|
||||
accel.enableInterrupts(g_int_config_enabled);
|
||||
|
||||
/* Map specific interrupts to one of the two INT pins. */
|
||||
g_int_config_map.bits.overrun = ADXL343_INT1;
|
||||
g_int_config_map.bits.watermark = ADXL343_INT1;
|
||||
g_int_config_map.bits.freefall = ADXL343_INT1;
|
||||
g_int_config_map.bits.inactivity = ADXL343_INT1;
|
||||
g_int_config_map.bits.activity = ADXL343_INT1;
|
||||
g_int_config_map.bits.double_tap = ADXL343_INT1;
|
||||
g_int_config_map.bits.single_tap = ADXL343_INT1;
|
||||
g_int_config_map.bits.data_ready = ADXL343_INT2;
|
||||
accel.mapInterrupts(g_int_config_map);
|
||||
}
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
while (!Serial);
|
||||
Serial.println("ADXL343 Interrupt Tester"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!accel.begin())
|
||||
{
|
||||
/* There was a problem detecting the ADXL343 ... check your connections */
|
||||
Serial.println("Ooops, no ADXL343 detected ... Check your wiring!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Set the range to whatever is appropriate for your project */
|
||||
accel.setRange(ADXL343_RANGE_16_G);
|
||||
// displaySetRange(ADXL343_RANGE_8_G);
|
||||
// displaySetRange(ADXL343_RANGE_4_G);
|
||||
// displaySetRange(ADXL343_RANGE_2_G);
|
||||
|
||||
|
||||
/* Configure the HW interrupts. */
|
||||
config_interrupts();
|
||||
|
||||
Serial.println("ADXL343 init complete. Waiting for INT activity.");
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
accel.getEvent(&event);
|
||||
delay(10);
|
||||
|
||||
while (g_ints_fired) {
|
||||
Serial.println("INT detected!");
|
||||
Serial.print("\tOVERRUN Count: "); Serial.println(g_int_stats.overrun, DEC);
|
||||
Serial.print("\tDATA_READY Count: "); Serial.println(g_int_stats.data_ready, DEC);
|
||||
|
||||
/* Decrement the unhandled int counter. */
|
||||
g_ints_fired--;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Connect two identical ADXL_343 sensor breakout boards
|
||||
* to a single Arduino. By connecting SDO on one of the
|
||||
* sensors to Vcc the I2C address of this sensor changes
|
||||
* from the default (0x53) to the alternative address (0x1D).
|
||||
* The address is passed during begin().
|
||||
*
|
||||
* This example returns raw sensor output of x, y and z acceleration
|
||||
* for both sensors over serial at 115200 baud.
|
||||
*
|
||||
* Example by Rolf Hut based on sensorTest example
|
||||
*/
|
||||
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_ADXL343.h>
|
||||
|
||||
/* Create two sensor objects and assign unique IDs */
|
||||
Adafruit_ADXL343 accel1 = Adafruit_ADXL343(12345);
|
||||
Adafruit_ADXL343 accel2 = Adafruit_ADXL343(12346);
|
||||
|
||||
|
||||
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
|
||||
Serial.println("Two Accelerometers on one Arduino"); Serial.println("");
|
||||
|
||||
/* Initialise the first sensors, this uses the default address */
|
||||
if(!accel1.begin())
|
||||
{
|
||||
/* There was a problem detecting the ADXL343 ... check your connections */
|
||||
Serial.println("Ooops, no ADXL343 nr1 detected ... Check your wiring!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Initialise the second sensors, this uses the alternative address */
|
||||
/* of 0x1D. On this sensor SDO must be connected to VCC */
|
||||
if(!accel2.begin(0x1D))
|
||||
{
|
||||
/* There was a problem detecting the ADXL343 ... check your connections */
|
||||
Serial.println("Ooops, no ADXL343 nr2 detected ... Check your wiring!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Set the range and data rate to whatever is appropriate for your project */
|
||||
/* See the sensortest example for more details */
|
||||
accel1.setRange(ADXL343_RANGE_2_G);
|
||||
accel2.setRange(ADXL343_RANGE_2_G);
|
||||
|
||||
accel1.setDataRate(ADXL343_DATARATE_1600_HZ);
|
||||
accel2.setDataRate(ADXL343_DATARATE_1600_HZ);
|
||||
|
||||
/* Display some basic information on these sensors */
|
||||
accel1.printSensorDetails();
|
||||
accel2.printSensorDetails();
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
/* Get new sensor events */
|
||||
sensors_event_t event1;
|
||||
sensors_event_t event2;
|
||||
accel1.getEvent(&event1);
|
||||
accel2.getEvent(&event2);
|
||||
|
||||
/* Display the results (acceleration is measured in m/s^2) */
|
||||
Serial.print(event1.acceleration.x); Serial.print(",");
|
||||
Serial.print(event1.acceleration.y); Serial.print(",");
|
||||
Serial.print(event1.acceleration.z); Serial.print(",");
|
||||
Serial.print(event2.acceleration.x); Serial.print(",");
|
||||
Serial.print(event2.acceleration.y); Serial.print(",");
|
||||
Serial.println(event2.acceleration.z);
|
||||
}
|
||||
93
libraries/Adafruit_ADXL343/examples/offsets/offsets.ino
Normal file
93
libraries/Adafruit_ADXL343/examples/offsets/offsets.ino
Normal file
@@ -0,0 +1,93 @@
|
||||
/* This example shows how to use the trimmer offset registers to account for any error in the sensor
|
||||
and 'zero' out the flat reading to be 0, 0, 1g. note this is unique to each sensor so it'll have
|
||||
to be repeated and 'saved' for each ADXL you use!
|
||||
*/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_ADXL343.h>
|
||||
|
||||
#define ADXL343_SCK 13
|
||||
#define ADXL343_MISO 12
|
||||
#define ADXL343_MOSI 11
|
||||
#define ADXL343_CS 10
|
||||
|
||||
/* Assign a unique ID to this sensor at the same time */
|
||||
/* Uncomment following line for default Wire bus */
|
||||
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);
|
||||
|
||||
/* NeoTrellis M4, etc. */
|
||||
/* Uncomment following line for Wire1 bus */
|
||||
//Adafruit_ADXL343 accel = Adafruit_ADXL343(12345, &Wire1);
|
||||
|
||||
/* Uncomment for SPI */
|
||||
//Adafruit_ADXL343 accel = Adafruit_ADXL343(ADXL343_SCK, ADXL343_MISO, ADXL343_MOSI, ADXL343_CS, 12345);
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println("Offsets Test"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!accel.begin())
|
||||
{
|
||||
/* There was a problem detecting the ADXL343 ... check your connections */
|
||||
Serial.println("Ooops, no ADXL343 detected ... Check your wiring!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Set the range to whatever is appropriate for your project */
|
||||
accel.setRange(ADXL343_RANGE_16_G);
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
accel.printSensorDetails();
|
||||
Serial.println("");
|
||||
|
||||
// init offsets to zero
|
||||
accel.setTrimOffsets(0, 0, 0);
|
||||
|
||||
Serial.println("Hold accelerometer flat to set offsets to 0, 0, and -1g...");
|
||||
delay(1000);
|
||||
int16_t x, y, z;
|
||||
x = accel.getX();
|
||||
y = accel.getY();
|
||||
z = accel.getZ();
|
||||
Serial.print("Raw X: "); Serial.print(x); Serial.print(" ");
|
||||
Serial.print("Y: "); Serial.print(y); Serial.print(" ");
|
||||
Serial.print("Z: "); Serial.print(z); Serial.print(" ");Serial.println(" counts");
|
||||
|
||||
// the trim offsets are in 'multiples' of 8, we want to round, so we add 4
|
||||
accel.setTrimOffsets(-(x+4)/8,
|
||||
-(y+4)/8,
|
||||
-(z-250+4)/8); // Z should be '250' at 1g (4mg per bit)
|
||||
|
||||
int8_t x_offset, y_offset, z_offset;
|
||||
accel.getTrimOffsets(&x_offset, &y_offset, &z_offset);
|
||||
Serial.print("Current trim offsets: ");
|
||||
Serial.print(x_offset); Serial.print(", ");
|
||||
Serial.print(y_offset); Serial.print(", ");
|
||||
Serial.println(z_offset);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
accel.getEvent(&event);
|
||||
|
||||
/* Display the results (acceleration is measured in m/s^2) */
|
||||
Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print(" ");
|
||||
Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print(" ");
|
||||
Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print(" ");
|
||||
Serial.println("m/s^2 ");
|
||||
|
||||
Serial.print("Raw X: "); Serial.print(accel.getX()); Serial.print(" ");
|
||||
Serial.print("Y: "); Serial.print(accel.getY()); Serial.print(" ");
|
||||
Serial.print("Z: "); Serial.print(accel.getZ()); Serial.print(" ");
|
||||
Serial.println(" counts");
|
||||
Serial.println();
|
||||
delay(500);
|
||||
}
|
||||
148
libraries/Adafruit_ADXL343/examples/sensortest/sensortest.ino
Normal file
148
libraries/Adafruit_ADXL343/examples/sensortest/sensortest.ino
Normal file
@@ -0,0 +1,148 @@
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_ADXL343.h>
|
||||
|
||||
#define ADXL343_SCK 13
|
||||
#define ADXL343_MISO 12
|
||||
#define ADXL343_MOSI 11
|
||||
#define ADXL343_CS 10
|
||||
|
||||
/* Assign a unique ID to this sensor at the same time */
|
||||
/* Uncomment following line for default Wire bus */
|
||||
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);
|
||||
|
||||
/* NeoTrellis M4, etc. */
|
||||
/* Uncomment following line for Wire1 bus */
|
||||
//Adafruit_ADXL343 accel = Adafruit_ADXL343(12345, &Wire1);
|
||||
|
||||
/* Uncomment for software SPI */
|
||||
//Adafruit_ADXL343 accel = Adafruit_ADXL343(ADXL343_SCK, ADXL343_MISO, ADXL343_MOSI, ADXL343_CS, 12345);
|
||||
|
||||
/* Uncomment for hardware SPI */
|
||||
//Adafruit_ADXL343 accel = Adafruit_ADXL343(ADXL343_CS, &SPI, 12345);
|
||||
|
||||
void displayDataRate(void)
|
||||
{
|
||||
Serial.print ("Data Rate: ");
|
||||
|
||||
switch(accel.getDataRate())
|
||||
{
|
||||
case ADXL343_DATARATE_3200_HZ:
|
||||
Serial.print ("3200 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_1600_HZ:
|
||||
Serial.print ("1600 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_800_HZ:
|
||||
Serial.print ("800 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_400_HZ:
|
||||
Serial.print ("400 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_200_HZ:
|
||||
Serial.print ("200 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_100_HZ:
|
||||
Serial.print ("100 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_50_HZ:
|
||||
Serial.print ("50 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_25_HZ:
|
||||
Serial.print ("25 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_12_5_HZ:
|
||||
Serial.print ("12.5 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_6_25HZ:
|
||||
Serial.print ("6.25 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_3_13_HZ:
|
||||
Serial.print ("3.13 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_1_56_HZ:
|
||||
Serial.print ("1.56 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_0_78_HZ:
|
||||
Serial.print ("0.78 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_0_39_HZ:
|
||||
Serial.print ("0.39 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_0_20_HZ:
|
||||
Serial.print ("0.20 ");
|
||||
break;
|
||||
case ADXL343_DATARATE_0_10_HZ:
|
||||
Serial.print ("0.10 ");
|
||||
break;
|
||||
default:
|
||||
Serial.print ("???? ");
|
||||
break;
|
||||
}
|
||||
Serial.println(" Hz");
|
||||
}
|
||||
|
||||
void displayRange(void)
|
||||
{
|
||||
Serial.print ("Range: +/- ");
|
||||
|
||||
switch(accel.getRange())
|
||||
{
|
||||
case ADXL343_RANGE_16_G:
|
||||
Serial.print ("16 ");
|
||||
break;
|
||||
case ADXL343_RANGE_8_G:
|
||||
Serial.print ("8 ");
|
||||
break;
|
||||
case ADXL343_RANGE_4_G:
|
||||
Serial.print ("4 ");
|
||||
break;
|
||||
case ADXL343_RANGE_2_G:
|
||||
Serial.print ("2 ");
|
||||
break;
|
||||
default:
|
||||
Serial.print ("?? ");
|
||||
break;
|
||||
}
|
||||
Serial.println(" g");
|
||||
}
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println("Accelerometer Test"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!accel.begin())
|
||||
{
|
||||
/* There was a problem detecting the ADXL343 ... check your connections */
|
||||
Serial.println("Ooops, no ADXL343 detected ... Check your wiring!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Set the range to whatever is appropriate for your project */
|
||||
accel.setRange(ADXL343_RANGE_16_G);
|
||||
// accel.setRange(ADXL343_RANGE_8_G);
|
||||
// accel.setRange(ADXL343_RANGE_4_G);
|
||||
// accel.setRange(ADXL343_RANGE_2_G);
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
accel.printSensorDetails();
|
||||
displayDataRate();
|
||||
displayRange();
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
accel.getEvent(&event);
|
||||
|
||||
/* Display the results (acceleration is measured in m/s^2) */
|
||||
Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print(" ");
|
||||
Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print(" ");
|
||||
Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print(" ");Serial.println("m/s^2 ");
|
||||
delay(500);
|
||||
}
|
||||
71
libraries/Adafruit_ADXL343/examples/singletap/singletap.ino
Normal file
71
libraries/Adafruit_ADXL343/examples/singletap/singletap.ino
Normal file
@@ -0,0 +1,71 @@
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_ADXL343.h>
|
||||
|
||||
/* Assign a unique ID to this sensor at the same time */
|
||||
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);
|
||||
|
||||
/** The input pin to enable the interrupt on, connected to INT1 on the ADXL. */
|
||||
#define INPUT_PIN_INT1 (5) // SAMD21/SAMD51 = 5 for interrupt pin
|
||||
|
||||
uint32_t g_tap_count = 0;
|
||||
int_config g_int_config_enabled = { 0 };
|
||||
int_config g_int_config_map = { 0 };
|
||||
|
||||
/** Interrupt service routine for INT1 events. This will be called when a single tap is detected. */
|
||||
void int1_isr(void)
|
||||
{
|
||||
g_tap_count++;
|
||||
}
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
while (!Serial);
|
||||
Serial.println("ADXL343 Single Tap INT Tester"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!accel.begin())
|
||||
{
|
||||
/* There was a problem detecting the ADXL343 ... check your connections */
|
||||
Serial.println("Ooops, no ADXL343 detected ... Check your wiring!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Set the range to whatever is appropriate for your project */
|
||||
accel.setRange(ADXL343_RANGE_16_G);
|
||||
|
||||
/* Configure the HW interrupts. */
|
||||
pinMode(INPUT_PIN_INT1, INPUT);
|
||||
attachInterrupt(digitalPinToInterrupt(INPUT_PIN_INT1), int1_isr, RISING);
|
||||
|
||||
/* Enable single tap interrupts on the accelerometer. */
|
||||
g_int_config_enabled.bits.single_tap = true;
|
||||
accel.enableInterrupts(g_int_config_enabled);
|
||||
|
||||
/* Map single tap interrupts to INT1 pin. */
|
||||
g_int_config_map.bits.single_tap = ADXL343_INT1;
|
||||
accel.mapInterrupts(g_int_config_map);
|
||||
|
||||
/* Reset tap counter. */
|
||||
g_tap_count = 0;
|
||||
|
||||
Serial.println("ADXL343 init complete. Waiting for single tap INT activity.");
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
/* Reading data clears the interrupts. */
|
||||
sensors_event_t event;
|
||||
accel.getEvent(&event);
|
||||
delay(10);
|
||||
|
||||
while (g_tap_count) {
|
||||
Serial.println("Single tap detected!");
|
||||
/* Clear the interrupt as a side-effect of reading the interrupt source register.. */
|
||||
accel.checkInterrupts();
|
||||
/* Decrement the local interrupt counter. */
|
||||
g_tap_count--;
|
||||
}
|
||||
}
|
||||
10
libraries/Adafruit_ADXL343/library.properties
Normal file
10
libraries/Adafruit_ADXL343/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=Adafruit ADXL343
|
||||
version=1.6.4
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Unified driver for the ADXL343 Accelerometer
|
||||
paragraph=Unified driver for the ADXL343 Accelerometer
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_ADXL343
|
||||
architectures=*
|
||||
depends=Adafruit Unified Sensor, Adafruit BusIO
|
||||
26
libraries/Adafruit_ADXL343/license.txt
Normal file
26
libraries/Adafruit_ADXL343/license.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2019, Adafruit Industries
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
646
libraries/Adafruit_BME280_Library/Adafruit_BME280.cpp
Normal file
646
libraries/Adafruit_BME280_Library/Adafruit_BME280.cpp
Normal file
@@ -0,0 +1,646 @@
|
||||
/*!
|
||||
* @file Adafruit_BME280.cpp
|
||||
*
|
||||
* @mainpage Adafruit BME280 humidity, temperature & pressure sensor
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
* Driver for the BME280 humidity, temperature & pressure sensor
|
||||
*
|
||||
* These sensors use I2C or SPI to communicate, 2 or 4 pins are required
|
||||
* to interface.
|
||||
*
|
||||
* Designed specifically to work with the Adafruit BME280 Breakout
|
||||
* ----> http://www.adafruit.com/products/2652
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Kevin "KTOWN" Townsend for Adafruit Industries.
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* BSD license, all text here must be included in any redistribution.
|
||||
* See the LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Adafruit_BME280.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
/*!
|
||||
* @brief class constructor
|
||||
*/
|
||||
Adafruit_BME280::Adafruit_BME280() {}
|
||||
|
||||
/*!
|
||||
* @brief class constructor if using hardware SPI
|
||||
* @param cspin the chip select pin to use
|
||||
* @param *theSPI
|
||||
* optional SPI object
|
||||
*/
|
||||
Adafruit_BME280::Adafruit_BME280(int8_t cspin, SPIClass *theSPI) {
|
||||
spi_dev = new Adafruit_SPIDevice(cspin, 1000000, SPI_BITORDER_MSBFIRST,
|
||||
SPI_MODE0, theSPI);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief class constructor if using software SPI
|
||||
* @param cspin the chip select pin to use
|
||||
* @param mosipin the MOSI pin to use
|
||||
* @param misopin the MISO pin to use
|
||||
* @param sckpin the SCK pin to use
|
||||
*/
|
||||
Adafruit_BME280::Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin,
|
||||
int8_t sckpin) {
|
||||
spi_dev = new Adafruit_SPIDevice(cspin, sckpin, misopin, mosipin);
|
||||
}
|
||||
|
||||
Adafruit_BME280::~Adafruit_BME280(void) {
|
||||
if (spi_dev) {
|
||||
delete spi_dev;
|
||||
}
|
||||
if (i2c_dev) {
|
||||
delete i2c_dev;
|
||||
}
|
||||
if (temp_sensor) {
|
||||
delete temp_sensor;
|
||||
}
|
||||
if (pressure_sensor) {
|
||||
delete pressure_sensor;
|
||||
}
|
||||
if (humidity_sensor) {
|
||||
delete humidity_sensor;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Initialise sensor with given parameters / settings
|
||||
* @param addr the I2C address the device can be found on
|
||||
* @param theWire the I2C object to use, defaults to &Wire
|
||||
* @returns true on success, false otherwise
|
||||
*/
|
||||
bool Adafruit_BME280::begin(uint8_t addr, TwoWire *theWire) {
|
||||
if (spi_dev == NULL) {
|
||||
// I2C mode
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(addr, theWire);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
} else {
|
||||
// SPI mode
|
||||
if (!spi_dev->begin())
|
||||
return false;
|
||||
}
|
||||
return init();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Initialise sensor with given parameters / settings
|
||||
* @returns true on success, false otherwise
|
||||
*/
|
||||
bool Adafruit_BME280::init() {
|
||||
// check if sensor, i.e. the chip ID is correct
|
||||
_sensorID = read8(BME280_REGISTER_CHIPID);
|
||||
if (_sensorID != 0x60)
|
||||
return false;
|
||||
|
||||
// reset the device using soft-reset
|
||||
// this makes sure the IIR is off, etc.
|
||||
write8(BME280_REGISTER_SOFTRESET, 0xB6);
|
||||
|
||||
// wait for chip to wake up.
|
||||
delay(10);
|
||||
|
||||
// if chip is still reading calibration, delay
|
||||
while (isReadingCalibration())
|
||||
delay(10);
|
||||
|
||||
readCoefficients(); // read trimming parameters, see DS 4.2.2
|
||||
|
||||
setSampling(); // use defaults
|
||||
|
||||
delay(100);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief setup sensor with given parameters / settings
|
||||
*
|
||||
* This is simply a overload to the normal begin()-function, so SPI users
|
||||
* don't get confused about the library requiring an address.
|
||||
* @param mode the power mode to use for the sensor
|
||||
* @param tempSampling the temp samping rate to use
|
||||
* @param pressSampling the pressure sampling rate to use
|
||||
* @param humSampling the humidity sampling rate to use
|
||||
* @param filter the filter mode to use
|
||||
* @param duration the standby duration to use
|
||||
*/
|
||||
void Adafruit_BME280::setSampling(sensor_mode mode,
|
||||
sensor_sampling tempSampling,
|
||||
sensor_sampling pressSampling,
|
||||
sensor_sampling humSampling,
|
||||
sensor_filter filter,
|
||||
standby_duration duration) {
|
||||
_measReg.mode = mode;
|
||||
_measReg.osrs_t = tempSampling;
|
||||
_measReg.osrs_p = pressSampling;
|
||||
|
||||
_humReg.osrs_h = humSampling;
|
||||
_configReg.filter = filter;
|
||||
_configReg.t_sb = duration;
|
||||
_configReg.spi3w_en = 0;
|
||||
|
||||
// making sure sensor is in sleep mode before setting configuration
|
||||
// as it otherwise may be ignored
|
||||
write8(BME280_REGISTER_CONTROL, MODE_SLEEP);
|
||||
|
||||
// you must make sure to also set REGISTER_CONTROL after setting the
|
||||
// CONTROLHUMID register, otherwise the values won't be applied (see
|
||||
// DS 5.4.3)
|
||||
write8(BME280_REGISTER_CONTROLHUMID, _humReg.get());
|
||||
write8(BME280_REGISTER_CONFIG, _configReg.get());
|
||||
write8(BME280_REGISTER_CONTROL, _measReg.get());
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Writes an 8 bit value over I2C or SPI
|
||||
* @param reg the register address to write to
|
||||
* @param value the value to write to the register
|
||||
*/
|
||||
void Adafruit_BME280::write8(byte reg, byte value) {
|
||||
byte buffer[2];
|
||||
buffer[1] = value;
|
||||
if (i2c_dev) {
|
||||
buffer[0] = reg;
|
||||
i2c_dev->write(buffer, 2);
|
||||
} else {
|
||||
buffer[0] = reg & ~0x80;
|
||||
spi_dev->write(buffer, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads an 8 bit value over I2C or SPI
|
||||
* @param reg the register address to read from
|
||||
* @returns the data byte read from the device
|
||||
*/
|
||||
uint8_t Adafruit_BME280::read8(byte reg) {
|
||||
uint8_t buffer[1];
|
||||
if (i2c_dev) {
|
||||
buffer[0] = uint8_t(reg);
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 1);
|
||||
} else {
|
||||
buffer[0] = uint8_t(reg | 0x80);
|
||||
spi_dev->write_then_read(buffer, 1, buffer, 1);
|
||||
}
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads a 16 bit value over I2C or SPI
|
||||
* @param reg the register address to read from
|
||||
* @returns the 16 bit data value read from the device
|
||||
*/
|
||||
uint16_t Adafruit_BME280::read16(byte reg) {
|
||||
uint8_t buffer[2];
|
||||
|
||||
if (i2c_dev) {
|
||||
buffer[0] = uint8_t(reg);
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 2);
|
||||
} else {
|
||||
buffer[0] = uint8_t(reg | 0x80);
|
||||
spi_dev->write_then_read(buffer, 1, buffer, 2);
|
||||
}
|
||||
return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads a signed 16 bit little endian value over I2C or SPI
|
||||
* @param reg the register address to read from
|
||||
* @returns the 16 bit data value read from the device
|
||||
*/
|
||||
uint16_t Adafruit_BME280::read16_LE(byte reg) {
|
||||
uint16_t temp = read16(reg);
|
||||
return (temp >> 8) | (temp << 8);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads a signed 16 bit value over I2C or SPI
|
||||
* @param reg the register address to read from
|
||||
* @returns the 16 bit data value read from the device
|
||||
*/
|
||||
int16_t Adafruit_BME280::readS16(byte reg) { return (int16_t)read16(reg); }
|
||||
|
||||
/*!
|
||||
* @brief Reads a signed little endian 16 bit value over I2C or SPI
|
||||
* @param reg the register address to read from
|
||||
* @returns the 16 bit data value read from the device
|
||||
*/
|
||||
int16_t Adafruit_BME280::readS16_LE(byte reg) {
|
||||
return (int16_t)read16_LE(reg);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads a 24 bit value over I2C
|
||||
* @param reg the register address to read from
|
||||
* @returns the 24 bit data value read from the device
|
||||
*/
|
||||
uint32_t Adafruit_BME280::read24(byte reg) {
|
||||
uint8_t buffer[3];
|
||||
|
||||
if (i2c_dev) {
|
||||
buffer[0] = uint8_t(reg);
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 3);
|
||||
} else {
|
||||
buffer[0] = uint8_t(reg | 0x80);
|
||||
spi_dev->write_then_read(buffer, 1, buffer, 3);
|
||||
}
|
||||
|
||||
return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8 |
|
||||
uint32_t(buffer[2]);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Take a new measurement (only possible in forced mode)
|
||||
@returns true in case of success else false
|
||||
*/
|
||||
bool Adafruit_BME280::takeForcedMeasurement(void) {
|
||||
bool return_value = false;
|
||||
// If we are in forced mode, the BME sensor goes back to sleep after each
|
||||
// measurement and we need to set it to forced mode once at this point, so
|
||||
// it will take the next measurement and then return to sleep again.
|
||||
// In normal mode simply does new measurements periodically.
|
||||
if (_measReg.mode == MODE_FORCED) {
|
||||
return_value = true;
|
||||
// set to forced mode, i.e. "take next measurement"
|
||||
write8(BME280_REGISTER_CONTROL, _measReg.get());
|
||||
// Store current time to measure the timeout
|
||||
uint32_t timeout_start = millis();
|
||||
// wait until measurement has been completed, otherwise we would read the
|
||||
// the values from the last measurement or the timeout occurred after 2 sec.
|
||||
while (read8(BME280_REGISTER_STATUS) & 0x08) {
|
||||
// In case of a timeout, stop the while loop
|
||||
if ((millis() - timeout_start) > 2000) {
|
||||
return_value = false;
|
||||
break;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads the factory-set coefficients
|
||||
*/
|
||||
void Adafruit_BME280::readCoefficients(void) {
|
||||
_bme280_calib.dig_T1 = read16_LE(BME280_REGISTER_DIG_T1);
|
||||
_bme280_calib.dig_T2 = readS16_LE(BME280_REGISTER_DIG_T2);
|
||||
_bme280_calib.dig_T3 = readS16_LE(BME280_REGISTER_DIG_T3);
|
||||
|
||||
_bme280_calib.dig_P1 = read16_LE(BME280_REGISTER_DIG_P1);
|
||||
_bme280_calib.dig_P2 = readS16_LE(BME280_REGISTER_DIG_P2);
|
||||
_bme280_calib.dig_P3 = readS16_LE(BME280_REGISTER_DIG_P3);
|
||||
_bme280_calib.dig_P4 = readS16_LE(BME280_REGISTER_DIG_P4);
|
||||
_bme280_calib.dig_P5 = readS16_LE(BME280_REGISTER_DIG_P5);
|
||||
_bme280_calib.dig_P6 = readS16_LE(BME280_REGISTER_DIG_P6);
|
||||
_bme280_calib.dig_P7 = readS16_LE(BME280_REGISTER_DIG_P7);
|
||||
_bme280_calib.dig_P8 = readS16_LE(BME280_REGISTER_DIG_P8);
|
||||
_bme280_calib.dig_P9 = readS16_LE(BME280_REGISTER_DIG_P9);
|
||||
|
||||
_bme280_calib.dig_H1 = read8(BME280_REGISTER_DIG_H1);
|
||||
_bme280_calib.dig_H2 = readS16_LE(BME280_REGISTER_DIG_H2);
|
||||
_bme280_calib.dig_H3 = read8(BME280_REGISTER_DIG_H3);
|
||||
_bme280_calib.dig_H4 = ((int8_t)read8(BME280_REGISTER_DIG_H4) << 4) |
|
||||
(read8(BME280_REGISTER_DIG_H4 + 1) & 0xF);
|
||||
_bme280_calib.dig_H5 = ((int8_t)read8(BME280_REGISTER_DIG_H5 + 1) << 4) |
|
||||
(read8(BME280_REGISTER_DIG_H5) >> 4);
|
||||
_bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief return true if chip is busy reading cal data
|
||||
* @returns true if reading calibration, false otherwise
|
||||
*/
|
||||
bool Adafruit_BME280::isReadingCalibration(void) {
|
||||
uint8_t const rStatus = read8(BME280_REGISTER_STATUS);
|
||||
|
||||
return (rStatus & (1 << 0)) != 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Returns the temperature from the sensor
|
||||
* @returns the temperature read from the device
|
||||
*/
|
||||
float Adafruit_BME280::readTemperature(void) {
|
||||
int32_t var1, var2;
|
||||
|
||||
int32_t adc_T = read24(BME280_REGISTER_TEMPDATA);
|
||||
if (adc_T == 0x800000) // value in case temp measurement was disabled
|
||||
return NAN;
|
||||
adc_T >>= 4;
|
||||
|
||||
var1 = (int32_t)((adc_T / 8) - ((int32_t)_bme280_calib.dig_T1 * 2));
|
||||
var1 = (var1 * ((int32_t)_bme280_calib.dig_T2)) / 2048;
|
||||
var2 = (int32_t)((adc_T / 16) - ((int32_t)_bme280_calib.dig_T1));
|
||||
var2 = (((var2 * var2) / 4096) * ((int32_t)_bme280_calib.dig_T3)) / 16384;
|
||||
|
||||
t_fine = var1 + var2 + t_fine_adjust;
|
||||
|
||||
int32_t T = (t_fine * 5 + 128) / 256;
|
||||
|
||||
return (float)T / 100;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Returns the pressure from the sensor
|
||||
* @returns the pressure value (in Pascal) read from the device
|
||||
*/
|
||||
float Adafruit_BME280::readPressure(void) {
|
||||
int64_t var1, var2, var3, var4;
|
||||
|
||||
readTemperature(); // must be done first to get t_fine
|
||||
|
||||
int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA);
|
||||
if (adc_P == 0x800000) // value in case pressure measurement was disabled
|
||||
return NAN;
|
||||
adc_P >>= 4;
|
||||
|
||||
var1 = ((int64_t)t_fine) - 128000;
|
||||
var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6;
|
||||
var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) * 131072);
|
||||
var2 = var2 + (((int64_t)_bme280_calib.dig_P4) * 34359738368);
|
||||
var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) / 256) +
|
||||
((var1 * ((int64_t)_bme280_calib.dig_P2) * 4096));
|
||||
var3 = ((int64_t)1) * 140737488355328;
|
||||
var1 = (var3 + var1) * ((int64_t)_bme280_calib.dig_P1) / 8589934592;
|
||||
|
||||
if (var1 == 0) {
|
||||
return 0; // avoid exception caused by division by zero
|
||||
}
|
||||
|
||||
var4 = 1048576 - adc_P;
|
||||
var4 = (((var4 * 2147483648) - var2) * 3125) / var1;
|
||||
var1 = (((int64_t)_bme280_calib.dig_P9) * (var4 / 8192) * (var4 / 8192)) /
|
||||
33554432;
|
||||
var2 = (((int64_t)_bme280_calib.dig_P8) * var4) / 524288;
|
||||
var4 = ((var4 + var1 + var2) / 256) + (((int64_t)_bme280_calib.dig_P7) * 16);
|
||||
|
||||
float P = var4 / 256.0;
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Returns the humidity from the sensor
|
||||
* @returns the humidity value read from the device
|
||||
*/
|
||||
float Adafruit_BME280::readHumidity(void) {
|
||||
int32_t var1, var2, var3, var4, var5;
|
||||
|
||||
readTemperature(); // must be done first to get t_fine
|
||||
|
||||
int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA);
|
||||
if (adc_H == 0x8000) // value in case humidity measurement was disabled
|
||||
return NAN;
|
||||
|
||||
var1 = t_fine - ((int32_t)76800);
|
||||
var2 = (int32_t)(adc_H * 16384);
|
||||
var3 = (int32_t)(((int32_t)_bme280_calib.dig_H4) * 1048576);
|
||||
var4 = ((int32_t)_bme280_calib.dig_H5) * var1;
|
||||
var5 = (((var2 - var3) - var4) + (int32_t)16384) / 32768;
|
||||
var2 = (var1 * ((int32_t)_bme280_calib.dig_H6)) / 1024;
|
||||
var3 = (var1 * ((int32_t)_bme280_calib.dig_H3)) / 2048;
|
||||
var4 = ((var2 * (var3 + (int32_t)32768)) / 1024) + (int32_t)2097152;
|
||||
var2 = ((var4 * ((int32_t)_bme280_calib.dig_H2)) + 8192) / 16384;
|
||||
var3 = var5 * var2;
|
||||
var4 = ((var3 / 32768) * (var3 / 32768)) / 128;
|
||||
var5 = var3 - ((var4 * ((int32_t)_bme280_calib.dig_H1)) / 16);
|
||||
var5 = (var5 < 0 ? 0 : var5);
|
||||
var5 = (var5 > 419430400 ? 419430400 : var5);
|
||||
uint32_t H = (uint32_t)(var5 / 4096);
|
||||
|
||||
return (float)H / 1024.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Calculates the altitude (in meters) from the specified atmospheric
|
||||
* pressure (in hPa), and sea-level pressure (in hPa).
|
||||
* @param seaLevel Sea-level pressure in hPa
|
||||
* @returns the altitude value read from the device
|
||||
*/
|
||||
float Adafruit_BME280::readAltitude(float seaLevel) {
|
||||
// Equation taken from BMP180 datasheet (page 16):
|
||||
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||
|
||||
// Note that using the equation from wikipedia can give bad results
|
||||
// at high altitude. See this thread for more information:
|
||||
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
|
||||
|
||||
float atmospheric = readPressure() / 100.0F;
|
||||
return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Calculates the pressure at sea level (in hPa) from the specified
|
||||
* altitude (in meters), and atmospheric pressure (in hPa).
|
||||
* @param altitude Altitude in meters
|
||||
* @param atmospheric Atmospheric pressure in hPa
|
||||
* @returns the pressure at sea level (in hPa) from the specified altitude
|
||||
*/
|
||||
float Adafruit_BME280::seaLevelForAltitude(float altitude, float atmospheric) {
|
||||
// Equation taken from BMP180 datasheet (page 17):
|
||||
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||
|
||||
// Note that using the equation from wikipedia can give bad results
|
||||
// at high altitude. See this thread for more information:
|
||||
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
|
||||
|
||||
return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns Sensor ID found by init() for diagnostics
|
||||
* @returns Sensor ID 0x60 for BME280, 0x56, 0x57, 0x58 BMP280
|
||||
*/
|
||||
uint32_t Adafruit_BME280::sensorID(void) { return _sensorID; }
|
||||
|
||||
/*!
|
||||
* Returns the current temperature compensation value in degrees Celsius
|
||||
* @returns the current temperature compensation value in degrees Celsius
|
||||
*/
|
||||
float Adafruit_BME280::getTemperatureCompensation(void) {
|
||||
return float((t_fine_adjust * 5) >> 8) / 100.0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Sets a value to be added to each temperature reading. This adjusted
|
||||
* temperature is used in pressure and humidity readings.
|
||||
* @param adjustment Value to be added to each temperature reading in Celsius
|
||||
*/
|
||||
void Adafruit_BME280::setTemperatureCompensation(float adjustment) {
|
||||
// convert the value in C into and adjustment to t_fine
|
||||
t_fine_adjust = ((int32_t(adjustment * 100) << 8)) / 5;
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief Gets an Adafruit Unified Sensor object for the temp sensor component
|
||||
@return Adafruit_Sensor pointer to temperature sensor
|
||||
*/
|
||||
Adafruit_Sensor *Adafruit_BME280::getTemperatureSensor(void) {
|
||||
if (!temp_sensor) {
|
||||
temp_sensor = new Adafruit_BME280_Temp(this);
|
||||
}
|
||||
|
||||
return temp_sensor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Gets an Adafruit Unified Sensor object for the pressure sensor
|
||||
component
|
||||
@return Adafruit_Sensor pointer to pressure sensor
|
||||
*/
|
||||
Adafruit_Sensor *Adafruit_BME280::getPressureSensor(void) {
|
||||
if (!pressure_sensor) {
|
||||
pressure_sensor = new Adafruit_BME280_Pressure(this);
|
||||
}
|
||||
return pressure_sensor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Gets an Adafruit Unified Sensor object for the humidity sensor
|
||||
component
|
||||
@return Adafruit_Sensor pointer to humidity sensor
|
||||
*/
|
||||
Adafruit_Sensor *Adafruit_BME280::getHumiditySensor(void) {
|
||||
if (!humidity_sensor) {
|
||||
humidity_sensor = new Adafruit_BME280_Humidity(this);
|
||||
}
|
||||
return humidity_sensor;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data for the BME280's temperature sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BME280_Temp::getSensor(sensor_t *sensor) {
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name) - 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
|
||||
sensor->min_delay = 0;
|
||||
sensor->min_value = -40.0; /* Temperature range -40 ~ +85 C */
|
||||
sensor->max_value = +85.0;
|
||||
sensor->resolution = 0.01; /* 0.01 C */
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the temperature as a standard sensor event
|
||||
@param event Sensor event object that will be populated
|
||||
@returns True
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BME280_Temp::getEvent(sensors_event_t *event) {
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
|
||||
event->timestamp = millis();
|
||||
event->temperature = _theBME280->readTemperature();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data for the BME280's pressure sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BME280_Pressure::getSensor(sensor_t *sensor) {
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name) - 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_PRESSURE;
|
||||
sensor->min_delay = 0;
|
||||
sensor->min_value = 300.0; /* 300 ~ 1100 hPa */
|
||||
sensor->max_value = 1100.0;
|
||||
sensor->resolution = 0.012; /* 0.12 hPa relative */
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the pressure as a standard sensor event
|
||||
@param event Sensor event object that will be populated
|
||||
@returns True
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BME280_Pressure::getEvent(sensors_event_t *event) {
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_PRESSURE;
|
||||
event->timestamp = millis();
|
||||
event->pressure = _theBME280->readPressure() / 100; // convert Pa to hPa
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data for the BME280's humidity sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BME280_Humidity::getSensor(sensor_t *sensor) {
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name) - 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
|
||||
sensor->min_delay = 0;
|
||||
sensor->min_value = 0;
|
||||
sensor->max_value = 100; /* 0 - 100 % */
|
||||
sensor->resolution = 3; /* 3% accuracy */
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the humidity as a standard sensor event
|
||||
@param event Sensor event object that will be populated
|
||||
@returns True
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BME280_Humidity::getEvent(sensors_event_t *event) {
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
|
||||
event->timestamp = millis();
|
||||
event->relative_humidity = _theBME280->readHumidity();
|
||||
return true;
|
||||
}
|
||||
372
libraries/Adafruit_BME280_Library/Adafruit_BME280.h
Normal file
372
libraries/Adafruit_BME280_Library/Adafruit_BME280.h
Normal file
@@ -0,0 +1,372 @@
|
||||
/*!
|
||||
* @file Adafruit_BME280.h
|
||||
*
|
||||
* Designed specifically to work with the Adafruit BME280 Breakout
|
||||
* ----> http://www.adafruit.com/products/2650
|
||||
*
|
||||
* These sensors use I2C or SPI to communicate, 2 or 4 pins are required
|
||||
* to interface.
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* Written by Kevin "KTOWN" Townsend for Adafruit Industries.
|
||||
*
|
||||
* BSD license, all text here must be included in any redistribution.
|
||||
* See the LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BME280_H__
|
||||
#define __BME280_H__
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include <Adafruit_I2CDevice.h>
|
||||
#include <Adafruit_SPIDevice.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
|
||||
/*!
|
||||
* @brief default I2C address
|
||||
*/
|
||||
#define BME280_ADDRESS (0x77) // Primary I2C Address
|
||||
/*!
|
||||
* @brief alternate I2C address
|
||||
*/
|
||||
#define BME280_ADDRESS_ALTERNATE (0x76) // Alternate Address
|
||||
|
||||
/*!
|
||||
* @brief Register addresses
|
||||
*/
|
||||
enum {
|
||||
BME280_REGISTER_DIG_T1 = 0x88,
|
||||
BME280_REGISTER_DIG_T2 = 0x8A,
|
||||
BME280_REGISTER_DIG_T3 = 0x8C,
|
||||
|
||||
BME280_REGISTER_DIG_P1 = 0x8E,
|
||||
BME280_REGISTER_DIG_P2 = 0x90,
|
||||
BME280_REGISTER_DIG_P3 = 0x92,
|
||||
BME280_REGISTER_DIG_P4 = 0x94,
|
||||
BME280_REGISTER_DIG_P5 = 0x96,
|
||||
BME280_REGISTER_DIG_P6 = 0x98,
|
||||
BME280_REGISTER_DIG_P7 = 0x9A,
|
||||
BME280_REGISTER_DIG_P8 = 0x9C,
|
||||
BME280_REGISTER_DIG_P9 = 0x9E,
|
||||
|
||||
BME280_REGISTER_DIG_H1 = 0xA1,
|
||||
BME280_REGISTER_DIG_H2 = 0xE1,
|
||||
BME280_REGISTER_DIG_H3 = 0xE3,
|
||||
BME280_REGISTER_DIG_H4 = 0xE4,
|
||||
BME280_REGISTER_DIG_H5 = 0xE5,
|
||||
BME280_REGISTER_DIG_H6 = 0xE7,
|
||||
|
||||
BME280_REGISTER_CHIPID = 0xD0,
|
||||
BME280_REGISTER_VERSION = 0xD1,
|
||||
BME280_REGISTER_SOFTRESET = 0xE0,
|
||||
|
||||
BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0
|
||||
|
||||
BME280_REGISTER_CONTROLHUMID = 0xF2,
|
||||
BME280_REGISTER_STATUS = 0XF3,
|
||||
BME280_REGISTER_CONTROL = 0xF4,
|
||||
BME280_REGISTER_CONFIG = 0xF5,
|
||||
BME280_REGISTER_PRESSUREDATA = 0xF7,
|
||||
BME280_REGISTER_TEMPDATA = 0xFA,
|
||||
BME280_REGISTER_HUMIDDATA = 0xFD
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief calibration data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
typedef struct {
|
||||
uint16_t dig_T1; ///< temperature compensation value
|
||||
int16_t dig_T2; ///< temperature compensation value
|
||||
int16_t dig_T3; ///< temperature compensation value
|
||||
|
||||
uint16_t dig_P1; ///< pressure compensation value
|
||||
int16_t dig_P2; ///< pressure compensation value
|
||||
int16_t dig_P3; ///< pressure compensation value
|
||||
int16_t dig_P4; ///< pressure compensation value
|
||||
int16_t dig_P5; ///< pressure compensation value
|
||||
int16_t dig_P6; ///< pressure compensation value
|
||||
int16_t dig_P7; ///< pressure compensation value
|
||||
int16_t dig_P8; ///< pressure compensation value
|
||||
int16_t dig_P9; ///< pressure compensation value
|
||||
|
||||
uint8_t dig_H1; ///< humidity compensation value
|
||||
int16_t dig_H2; ///< humidity compensation value
|
||||
uint8_t dig_H3; ///< humidity compensation value
|
||||
int16_t dig_H4; ///< humidity compensation value
|
||||
int16_t dig_H5; ///< humidity compensation value
|
||||
int8_t dig_H6; ///< humidity compensation value
|
||||
} bme280_calib_data;
|
||||
/*=========================================================================*/
|
||||
|
||||
class Adafruit_BME280;
|
||||
|
||||
/** Adafruit Unified Sensor interface for temperature component of BME280 */
|
||||
class Adafruit_BME280_Temp : public Adafruit_Sensor {
|
||||
public:
|
||||
/** @brief Create an Adafruit_Sensor compatible object for the temp sensor
|
||||
@param parent A pointer to the BME280 class */
|
||||
Adafruit_BME280_Temp(Adafruit_BME280 *parent) { _theBME280 = parent; }
|
||||
bool getEvent(sensors_event_t *);
|
||||
void getSensor(sensor_t *);
|
||||
|
||||
private:
|
||||
int _sensorID = 280;
|
||||
Adafruit_BME280 *_theBME280 = NULL;
|
||||
};
|
||||
|
||||
/** Adafruit Unified Sensor interface for pressure component of BME280 */
|
||||
class Adafruit_BME280_Pressure : public Adafruit_Sensor {
|
||||
public:
|
||||
/** @brief Create an Adafruit_Sensor compatible object for the pressure sensor
|
||||
@param parent A pointer to the BME280 class */
|
||||
Adafruit_BME280_Pressure(Adafruit_BME280 *parent) { _theBME280 = parent; }
|
||||
bool getEvent(sensors_event_t *);
|
||||
void getSensor(sensor_t *);
|
||||
|
||||
private:
|
||||
int _sensorID = 280;
|
||||
Adafruit_BME280 *_theBME280 = NULL;
|
||||
};
|
||||
|
||||
/** Adafruit Unified Sensor interface for humidity component of BME280 */
|
||||
class Adafruit_BME280_Humidity : public Adafruit_Sensor {
|
||||
public:
|
||||
/** @brief Create an Adafruit_Sensor compatible object for the humidity sensor
|
||||
@param parent A pointer to the BME280 class */
|
||||
Adafruit_BME280_Humidity(Adafruit_BME280 *parent) { _theBME280 = parent; }
|
||||
bool getEvent(sensors_event_t *);
|
||||
void getSensor(sensor_t *);
|
||||
|
||||
private:
|
||||
int _sensorID = 280;
|
||||
Adafruit_BME280 *_theBME280 = NULL;
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Class that stores state and functions for interacting with BME280 IC
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class Adafruit_BME280 {
|
||||
public:
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief sampling rates
|
||||
*/
|
||||
/**************************************************************************/
|
||||
enum sensor_sampling {
|
||||
SAMPLING_NONE = 0b000,
|
||||
SAMPLING_X1 = 0b001,
|
||||
SAMPLING_X2 = 0b010,
|
||||
SAMPLING_X4 = 0b011,
|
||||
SAMPLING_X8 = 0b100,
|
||||
SAMPLING_X16 = 0b101
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief power modes
|
||||
*/
|
||||
/**************************************************************************/
|
||||
enum sensor_mode {
|
||||
MODE_SLEEP = 0b00,
|
||||
MODE_FORCED = 0b01,
|
||||
MODE_NORMAL = 0b11
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief filter values
|
||||
*/
|
||||
/**************************************************************************/
|
||||
enum sensor_filter {
|
||||
FILTER_OFF = 0b000,
|
||||
FILTER_X2 = 0b001,
|
||||
FILTER_X4 = 0b010,
|
||||
FILTER_X8 = 0b011,
|
||||
FILTER_X16 = 0b100
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief standby duration in ms
|
||||
*/
|
||||
/**************************************************************************/
|
||||
enum standby_duration {
|
||||
STANDBY_MS_0_5 = 0b000,
|
||||
STANDBY_MS_10 = 0b110,
|
||||
STANDBY_MS_20 = 0b111,
|
||||
STANDBY_MS_62_5 = 0b001,
|
||||
STANDBY_MS_125 = 0b010,
|
||||
STANDBY_MS_250 = 0b011,
|
||||
STANDBY_MS_500 = 0b100,
|
||||
STANDBY_MS_1000 = 0b101
|
||||
};
|
||||
|
||||
// constructors
|
||||
Adafruit_BME280();
|
||||
Adafruit_BME280(int8_t cspin, SPIClass *theSPI = &SPI);
|
||||
Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin);
|
||||
~Adafruit_BME280(void);
|
||||
bool begin(uint8_t addr = BME280_ADDRESS, TwoWire *theWire = &Wire);
|
||||
bool init();
|
||||
|
||||
void setSampling(sensor_mode mode = MODE_NORMAL,
|
||||
sensor_sampling tempSampling = SAMPLING_X16,
|
||||
sensor_sampling pressSampling = SAMPLING_X16,
|
||||
sensor_sampling humSampling = SAMPLING_X16,
|
||||
sensor_filter filter = FILTER_OFF,
|
||||
standby_duration duration = STANDBY_MS_0_5);
|
||||
|
||||
bool takeForcedMeasurement(void);
|
||||
float readTemperature(void);
|
||||
float readPressure(void);
|
||||
float readHumidity(void);
|
||||
|
||||
float readAltitude(float seaLevel);
|
||||
float seaLevelForAltitude(float altitude, float pressure);
|
||||
uint32_t sensorID(void);
|
||||
|
||||
float getTemperatureCompensation(void);
|
||||
void setTemperatureCompensation(float);
|
||||
|
||||
Adafruit_Sensor *getTemperatureSensor(void);
|
||||
Adafruit_Sensor *getPressureSensor(void);
|
||||
Adafruit_Sensor *getHumiditySensor(void);
|
||||
|
||||
protected:
|
||||
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
|
||||
Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface
|
||||
|
||||
Adafruit_BME280_Temp *temp_sensor = NULL;
|
||||
//!< Adafruit_Sensor compat temperature sensor component
|
||||
|
||||
Adafruit_BME280_Pressure *pressure_sensor = NULL;
|
||||
//!< Adafruit_Sensor compat pressure sensor component
|
||||
|
||||
Adafruit_BME280_Humidity *humidity_sensor = NULL;
|
||||
//!< Adafruit_Sensor compat humidity sensor component
|
||||
|
||||
void readCoefficients(void);
|
||||
bool isReadingCalibration(void);
|
||||
|
||||
void write8(byte reg, byte value);
|
||||
uint8_t read8(byte reg);
|
||||
uint16_t read16(byte reg);
|
||||
uint32_t read24(byte reg);
|
||||
int16_t readS16(byte reg);
|
||||
uint16_t read16_LE(byte reg); // little endian
|
||||
int16_t readS16_LE(byte reg); // little endian
|
||||
|
||||
uint8_t _i2caddr; //!< I2C addr for the TwoWire interface
|
||||
int32_t _sensorID; //!< ID of the BME Sensor
|
||||
int32_t t_fine; //!< temperature with high resolution, stored as an attribute
|
||||
//!< as this is used for temperature compensation reading
|
||||
//!< humidity and pressure
|
||||
|
||||
int32_t t_fine_adjust = 0; //!< add to compensate temp readings and in turn
|
||||
//!< to pressure and humidity readings
|
||||
|
||||
bme280_calib_data _bme280_calib; //!< here calibration data is stored
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief config register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
struct config {
|
||||
// inactive duration (standby time) in normal mode
|
||||
// 000 = 0.5 ms
|
||||
// 001 = 62.5 ms
|
||||
// 010 = 125 ms
|
||||
// 011 = 250 ms
|
||||
// 100 = 500 ms
|
||||
// 101 = 1000 ms
|
||||
// 110 = 10 ms
|
||||
// 111 = 20 ms
|
||||
unsigned int t_sb : 3; ///< inactive duration (standby time) in normal mode
|
||||
|
||||
// filter settings
|
||||
// 000 = filter off
|
||||
// 001 = 2x filter
|
||||
// 010 = 4x filter
|
||||
// 011 = 8x filter
|
||||
// 100 and above = 16x filter
|
||||
unsigned int filter : 3; ///< filter settings
|
||||
|
||||
// unused - don't set
|
||||
unsigned int none : 1; ///< unused - don't set
|
||||
unsigned int spi3w_en : 1; ///< unused - don't set
|
||||
|
||||
/// @return combined config register
|
||||
unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; }
|
||||
};
|
||||
config _configReg; //!< config register object
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief ctrl_meas register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
struct ctrl_meas {
|
||||
// temperature oversampling
|
||||
// 000 = skipped
|
||||
// 001 = x1
|
||||
// 010 = x2
|
||||
// 011 = x4
|
||||
// 100 = x8
|
||||
// 101 and above = x16
|
||||
unsigned int osrs_t : 3; ///< temperature oversampling
|
||||
|
||||
// pressure oversampling
|
||||
// 000 = skipped
|
||||
// 001 = x1
|
||||
// 010 = x2
|
||||
// 011 = x4
|
||||
// 100 = x8
|
||||
// 101 and above = x16
|
||||
unsigned int osrs_p : 3; ///< pressure oversampling
|
||||
|
||||
// device mode
|
||||
// 00 = sleep
|
||||
// 01 or 10 = forced
|
||||
// 11 = normal
|
||||
unsigned int mode : 2; ///< device mode
|
||||
|
||||
/// @return combined ctrl register
|
||||
unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; }
|
||||
};
|
||||
ctrl_meas _measReg; //!< measurement register object
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief ctrl_hum register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
struct ctrl_hum {
|
||||
/// unused - don't set
|
||||
unsigned int none : 5;
|
||||
|
||||
// pressure oversampling
|
||||
// 000 = skipped
|
||||
// 001 = x1
|
||||
// 010 = x2
|
||||
// 011 = x4
|
||||
// 100 = x8
|
||||
// 101 and above = x16
|
||||
unsigned int osrs_h : 3; ///< pressure oversampling
|
||||
|
||||
/// @return combined ctrl hum register
|
||||
unsigned int get() { return (osrs_h); }
|
||||
};
|
||||
ctrl_hum _humReg; //!< hum register object
|
||||
};
|
||||
|
||||
#endif
|
||||
27
libraries/Adafruit_BME280_Library/LICENSE
Normal file
27
libraries/Adafruit_BME280_Library/LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2015, Limor Fried & Kevin Townsend for Adafruit Industries
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Adafruit Industries nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
54
libraries/Adafruit_BME280_Library/README.md
Normal file
54
libraries/Adafruit_BME280_Library/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Adafruit BME280 Library [](https://github.com/adafruit/Adafruit_BME280_Library/actions)[](http://adafruit.github.io/Adafruit_BME280_Library/html/index.html)
|
||||
|
||||
|
||||
<a href="http://www.adafruit.com/products/2652"><img src="./assets/board.jpg" width="500"/></a>
|
||||
|
||||
This is a library for the Adafruit BME280 Humidity, Barometric Pressure + Temp sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BME280 Breakout
|
||||
* http://www.adafruit.com/products/2652
|
||||
|
||||
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
# Installation
|
||||
To install, use the Arduino Library Manager and search for "Adafruit BME280" and install the library.
|
||||
|
||||
## Dependencies
|
||||
* [Adafruit Unified Sensor Driver](https://github.com/adafruit/Adafruit_Sensor)
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/Adafruit_PM25AQI/blob/master/CODE_OF_CONDUCT.md>)
|
||||
before contributing to help this project stay welcoming.
|
||||
|
||||
## Documentation and doxygen
|
||||
Documentation is produced by doxygen. Contributions should include documentation for any new code added.
|
||||
|
||||
Some examples of how to use doxygen can be found in these guide pages:
|
||||
|
||||
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen
|
||||
|
||||
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips
|
||||
|
||||
## Formatting and clang-format
|
||||
This library uses [`clang-format`](https://releases.llvm.org/download.html) to standardize the formatting of `.cpp` and `.h` files.
|
||||
Contributions should be formatted using `clang-format`:
|
||||
|
||||
The `-i` flag will make the changes to the file.
|
||||
```bash
|
||||
clang-format -i *.cpp *.h
|
||||
```
|
||||
If you prefer to make the changes yourself, running `clang-format` without the `-i` flag will print out a formatted version of the file. You can save this to a file and diff it against the original to see the changes.
|
||||
|
||||
Note that the formatting output by `clang-format` is what the automated formatting checker will expect. Any diffs from this formatting will result in a failed build until they are addressed. Using the `-i` flag is highly recommended.
|
||||
|
||||
### clang-format resources
|
||||
* [Binary builds and source available on the LLVM downloads page](https://releases.llvm.org/download.html)
|
||||
* [Documentation and IDE integration](https://clang.llvm.org/docs/ClangFormat.html)
|
||||
|
||||
## About this Driver
|
||||
Written by Ladyada for Adafruit Industries.
|
||||
|
||||
BSD license, check license.txt for more information
|
||||
|
||||
All text above must be included in any redistribution
|
||||
BIN
libraries/Adafruit_BME280_Library/assets/board.jpg
Normal file
BIN
libraries/Adafruit_BME280_Library/assets/board.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 431 KiB |
@@ -0,0 +1,159 @@
|
||||
/***************************************************************************
|
||||
This is a library for the BME280 humidity, temperature & pressure sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BME280 Breakout
|
||||
----> http://www.adafruit.com/products/2650
|
||||
|
||||
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
|
||||
to interface. The device's I2C address is either 0x76 or 0x77.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit andopen-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
|
||||
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
See the LICENSE file for details.
|
||||
***************************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BME280.h>
|
||||
|
||||
#define BME_SCK 13
|
||||
#define BME_MISO 12
|
||||
#define BME_MOSI 11
|
||||
#define BME_CS 10
|
||||
|
||||
#define SEALEVELPRESSURE_HPA (1013.25)
|
||||
|
||||
Adafruit_BME280 bme; // I2C
|
||||
//Adafruit_BME280 bme(BME_CS); // hardware SPI
|
||||
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
|
||||
|
||||
unsigned long delayTime;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("BME280 test"));
|
||||
|
||||
if (! bme.begin(0x77, &Wire)) {
|
||||
Serial.println("Could not find a valid BME280 sensor, check wiring!");
|
||||
while (1);
|
||||
}
|
||||
|
||||
Serial.println("-- Default Test --");
|
||||
Serial.println("normal mode, 16x oversampling for all, filter off,");
|
||||
Serial.println("0.5ms standby period");
|
||||
delayTime = 5000;
|
||||
|
||||
|
||||
// For more details on the following scenarious, see chapter
|
||||
// 3.5 "Recommended modes of operation" in the datasheet
|
||||
|
||||
/*
|
||||
// weather monitoring
|
||||
Serial.println("-- Weather Station Scenario --");
|
||||
Serial.println("forced mode, 1x temperature / 1x humidity / 1x pressure oversampling,");
|
||||
Serial.println("filter off");
|
||||
bme.setSampling(Adafruit_BME280::MODE_FORCED,
|
||||
Adafruit_BME280::SAMPLING_X1, // temperature
|
||||
Adafruit_BME280::SAMPLING_X1, // pressure
|
||||
Adafruit_BME280::SAMPLING_X1, // humidity
|
||||
Adafruit_BME280::FILTER_OFF );
|
||||
|
||||
// suggested rate is 1/60Hz (1m)
|
||||
delayTime = 60000; // in milliseconds
|
||||
*/
|
||||
|
||||
/*
|
||||
// humidity sensing
|
||||
Serial.println("-- Humidity Sensing Scenario --");
|
||||
Serial.println("forced mode, 1x temperature / 1x humidity / 0x pressure oversampling");
|
||||
Serial.println("= pressure off, filter off");
|
||||
bme.setSampling(Adafruit_BME280::MODE_FORCED,
|
||||
Adafruit_BME280::SAMPLING_X1, // temperature
|
||||
Adafruit_BME280::SAMPLING_NONE, // pressure
|
||||
Adafruit_BME280::SAMPLING_X1, // humidity
|
||||
Adafruit_BME280::FILTER_OFF );
|
||||
|
||||
// suggested rate is 1Hz (1s)
|
||||
delayTime = 1000; // in milliseconds
|
||||
*/
|
||||
|
||||
/*
|
||||
// indoor navigation
|
||||
Serial.println("-- Indoor Navigation Scenario --");
|
||||
Serial.println("normal mode, 16x pressure / 2x temperature / 1x humidity oversampling,");
|
||||
Serial.println("0.5ms standby period, filter 16x");
|
||||
bme.setSampling(Adafruit_BME280::MODE_NORMAL,
|
||||
Adafruit_BME280::SAMPLING_X2, // temperature
|
||||
Adafruit_BME280::SAMPLING_X16, // pressure
|
||||
Adafruit_BME280::SAMPLING_X1, // humidity
|
||||
Adafruit_BME280::FILTER_X16,
|
||||
Adafruit_BME280::STANDBY_MS_0_5 );
|
||||
|
||||
// suggested rate is 25Hz
|
||||
// 1 + (2 * T_ovs) + (2 * P_ovs + 0.5) + (2 * H_ovs + 0.5)
|
||||
// T_ovs = 2
|
||||
// P_ovs = 16
|
||||
// H_ovs = 1
|
||||
// = 40ms (25Hz)
|
||||
// with standby time that should really be 24.16913... Hz
|
||||
delayTime = 41;
|
||||
*/
|
||||
|
||||
/*
|
||||
// gaming
|
||||
Serial.println("-- Gaming Scenario --");
|
||||
Serial.println("normal mode, 4x pressure / 1x temperature / 0x humidity oversampling,");
|
||||
Serial.println("= humidity off, 0.5ms standby period, filter 16x");
|
||||
bme.setSampling(Adafruit_BME280::MODE_NORMAL,
|
||||
Adafruit_BME280::SAMPLING_X1, // temperature
|
||||
Adafruit_BME280::SAMPLING_X4, // pressure
|
||||
Adafruit_BME280::SAMPLING_NONE, // humidity
|
||||
Adafruit_BME280::FILTER_X16,
|
||||
Adafruit_BME280::STANDBY_MS_0_5 );
|
||||
|
||||
// Suggested rate is 83Hz
|
||||
// 1 + (2 * T_ovs) + (2 * P_ovs + 0.5)
|
||||
// T_ovs = 1
|
||||
// P_ovs = 4
|
||||
// = 11.5ms + 0.5ms standby
|
||||
delayTime = 12;
|
||||
*/
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
// Only needed in forced mode! In normal mode, you can remove the next line.
|
||||
bme.takeForcedMeasurement(); // has no effect in normal mode
|
||||
|
||||
printValues();
|
||||
delay(delayTime);
|
||||
}
|
||||
|
||||
|
||||
void printValues() {
|
||||
Serial.print("Temperature = ");
|
||||
Serial.print(bme.readTemperature());
|
||||
Serial.println(" *C");
|
||||
|
||||
Serial.print("Pressure = ");
|
||||
|
||||
Serial.print(bme.readPressure() / 100.0F);
|
||||
Serial.println(" hPa");
|
||||
|
||||
Serial.print("Approx. Altitude = ");
|
||||
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
|
||||
Serial.println(" m");
|
||||
|
||||
Serial.print("Humidity = ");
|
||||
Serial.print(bme.readHumidity());
|
||||
Serial.println(" %");
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
This is a library for the BME280 humidity, temperature & pressure sensor
|
||||
This example shows how to take Sensor Events instead of direct readings
|
||||
|
||||
Designed specifically to work with the Adafruit BME280 Breakout
|
||||
----> http://www.adafruit.com/products/2652
|
||||
|
||||
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
|
||||
to interface.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
|
||||
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <Adafruit_BME280.h>
|
||||
|
||||
Adafruit_BME280 bme; // use I2C interface
|
||||
Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
|
||||
Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
|
||||
Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("BME280 Sensor event test"));
|
||||
|
||||
if (!bme.begin()) {
|
||||
Serial.println(F("Could not find a valid BME280 sensor, check wiring!"));
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
bme_temp->printSensorDetails();
|
||||
bme_pressure->printSensorDetails();
|
||||
bme_humidity->printSensorDetails();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
sensors_event_t temp_event, pressure_event, humidity_event;
|
||||
bme_temp->getEvent(&temp_event);
|
||||
bme_pressure->getEvent(&pressure_event);
|
||||
bme_humidity->getEvent(&humidity_event);
|
||||
|
||||
Serial.print(F("Temperature = "));
|
||||
Serial.print(temp_event.temperature);
|
||||
Serial.println(" *C");
|
||||
|
||||
Serial.print(F("Humidity = "));
|
||||
Serial.print(humidity_event.relative_humidity);
|
||||
Serial.println(" %");
|
||||
|
||||
Serial.print(F("Pressure = "));
|
||||
Serial.print(pressure_event.pressure);
|
||||
Serial.println(" hPa");
|
||||
|
||||
Serial.println();
|
||||
delay(1000);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/***************************************************************************
|
||||
This is a library for the BME280 humidity, temperature & pressure sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BME280 Breakout
|
||||
----> http://www.adafruit.com/products/2650
|
||||
|
||||
These sensors use I2C or SPI to communicate, 2 or 4 pins are required
|
||||
to interface. The device's I2C address is either 0x76 or 0x77.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit andopen-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
|
||||
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
See the LICENSE file for details.
|
||||
***************************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BME280.h>
|
||||
|
||||
#define BME_SCK 13
|
||||
#define BME_MISO 12
|
||||
#define BME_MOSI 11
|
||||
#define BME_CS 10
|
||||
|
||||
#define SEALEVELPRESSURE_HPA (1013.25)
|
||||
|
||||
Adafruit_BME280 bme; // I2C
|
||||
//Adafruit_BME280 bme(BME_CS); // hardware SPI
|
||||
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
|
||||
|
||||
unsigned long delayTime;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while(!Serial); // time to get serial running
|
||||
Serial.println(F("BME280 test"));
|
||||
|
||||
unsigned status;
|
||||
|
||||
// default settings
|
||||
status = bme.begin();
|
||||
// You can also pass in a Wire library object like &Wire2
|
||||
// status = bme.begin(0x76, &Wire2)
|
||||
if (!status) {
|
||||
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
|
||||
Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16);
|
||||
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
|
||||
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
|
||||
Serial.print(" ID of 0x60 represents a BME 280.\n");
|
||||
Serial.print(" ID of 0x61 represents a BME 680.\n");
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
Serial.println("-- Default Test --");
|
||||
delayTime = 1000;
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
printValues();
|
||||
delay(delayTime);
|
||||
}
|
||||
|
||||
|
||||
void printValues() {
|
||||
Serial.print("Temperature = ");
|
||||
Serial.print(bme.readTemperature());
|
||||
Serial.println(" °C");
|
||||
|
||||
Serial.print("Pressure = ");
|
||||
|
||||
Serial.print(bme.readPressure() / 100.0F);
|
||||
Serial.println(" hPa");
|
||||
|
||||
Serial.print("Approx. Altitude = ");
|
||||
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
|
||||
Serial.println(" m");
|
||||
|
||||
Serial.print("Humidity = ");
|
||||
Serial.print(bme.readHumidity());
|
||||
Serial.println(" %");
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
10
libraries/Adafruit_BME280_Library/library.properties
Normal file
10
libraries/Adafruit_BME280_Library/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=Adafruit BME280 Library
|
||||
version=2.2.4
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Arduino library for BME280 sensors.
|
||||
paragraph=Arduino library for BME280 humidity and pressure sensors.
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_BME280_Library
|
||||
architectures=*
|
||||
depends=Adafruit Unified Sensor, Adafruit BusIO
|
||||
311
libraries/Adafruit_BMP085_Library/Adafruit_BMP085.cpp
Normal file
311
libraries/Adafruit_BMP085_Library/Adafruit_BMP085.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
/*!
|
||||
* @file Adafruit_BMP085.cpp
|
||||
*
|
||||
* @mainpage Adafruit BMP085 Library
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
* This is a library for the Adafruit BMP085/BMP180 Barometric Pressure + Temp
|
||||
* sensor
|
||||
*
|
||||
* Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
* ----> http://www.adafruit.com/products/391
|
||||
* ----> http://www.adafruit.com/products/1603
|
||||
*
|
||||
* These displays use I2C to communicate, 2 pins are required to
|
||||
* interface
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
* Updated by Samy Kamkar for cross-platform support.
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* BSD license, all text above must be included in any redistribution
|
||||
*/
|
||||
|
||||
#include "Adafruit_BMP085.h"
|
||||
#include <Adafruit_I2CDevice.h>
|
||||
|
||||
Adafruit_BMP085::Adafruit_BMP085() { i2c_dev = nullptr; }
|
||||
|
||||
bool Adafruit_BMP085::begin(uint8_t mode, TwoWire *wire) {
|
||||
if (mode > BMP085_ULTRAHIGHRES)
|
||||
mode = BMP085_ULTRAHIGHRES;
|
||||
oversampling = mode;
|
||||
|
||||
if (i2c_dev) {
|
||||
delete i2c_dev; // remove old interface
|
||||
}
|
||||
|
||||
i2c_dev = new Adafruit_I2CDevice(BMP085_I2CADDR, wire);
|
||||
|
||||
if (!i2c_dev->begin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read8(0xD0) != 0x55)
|
||||
return false;
|
||||
|
||||
/* read calibration data */
|
||||
ac1 = read16(BMP085_CAL_AC1);
|
||||
ac2 = read16(BMP085_CAL_AC2);
|
||||
ac3 = read16(BMP085_CAL_AC3);
|
||||
ac4 = read16(BMP085_CAL_AC4);
|
||||
ac5 = read16(BMP085_CAL_AC5);
|
||||
ac6 = read16(BMP085_CAL_AC6);
|
||||
|
||||
b1 = read16(BMP085_CAL_B1);
|
||||
b2 = read16(BMP085_CAL_B2);
|
||||
|
||||
mb = read16(BMP085_CAL_MB);
|
||||
mc = read16(BMP085_CAL_MC);
|
||||
md = read16(BMP085_CAL_MD);
|
||||
#if (BMP085_DEBUG == 1)
|
||||
Serial.print("ac1 = ");
|
||||
Serial.println(ac1, DEC);
|
||||
Serial.print("ac2 = ");
|
||||
Serial.println(ac2, DEC);
|
||||
Serial.print("ac3 = ");
|
||||
Serial.println(ac3, DEC);
|
||||
Serial.print("ac4 = ");
|
||||
Serial.println(ac4, DEC);
|
||||
Serial.print("ac5 = ");
|
||||
Serial.println(ac5, DEC);
|
||||
Serial.print("ac6 = ");
|
||||
Serial.println(ac6, DEC);
|
||||
|
||||
Serial.print("b1 = ");
|
||||
Serial.println(b1, DEC);
|
||||
Serial.print("b2 = ");
|
||||
Serial.println(b2, DEC);
|
||||
|
||||
Serial.print("mb = ");
|
||||
Serial.println(mb, DEC);
|
||||
Serial.print("mc = ");
|
||||
Serial.println(mc, DEC);
|
||||
Serial.print("md = ");
|
||||
Serial.println(md, DEC);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t Adafruit_BMP085::computeB5(int32_t UT) {
|
||||
int32_t X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) >> 15;
|
||||
int32_t X2 = ((int32_t)mc << 11) / (X1 + (int32_t)md);
|
||||
return X1 + X2;
|
||||
}
|
||||
|
||||
uint16_t Adafruit_BMP085::readRawTemperature(void) {
|
||||
write8(BMP085_CONTROL, BMP085_READTEMPCMD);
|
||||
delay(5);
|
||||
#if BMP085_DEBUG == 1
|
||||
Serial.print("Raw temp: ");
|
||||
Serial.println(read16(BMP085_TEMPDATA));
|
||||
#endif
|
||||
return read16(BMP085_TEMPDATA);
|
||||
}
|
||||
|
||||
uint32_t Adafruit_BMP085::readRawPressure(void) {
|
||||
uint32_t raw;
|
||||
|
||||
write8(BMP085_CONTROL, BMP085_READPRESSURECMD + (oversampling << 6));
|
||||
|
||||
if (oversampling == BMP085_ULTRALOWPOWER)
|
||||
delay(5);
|
||||
else if (oversampling == BMP085_STANDARD)
|
||||
delay(8);
|
||||
else if (oversampling == BMP085_HIGHRES)
|
||||
delay(14);
|
||||
else
|
||||
delay(26);
|
||||
|
||||
raw = read16(BMP085_PRESSUREDATA);
|
||||
|
||||
raw <<= 8;
|
||||
raw |= read8(BMP085_PRESSUREDATA + 2);
|
||||
raw >>= (8 - oversampling);
|
||||
|
||||
/* this pull broke stuff, look at it later?
|
||||
if (oversampling==0) {
|
||||
raw <<= 8;
|
||||
raw |= read8(BMP085_PRESSUREDATA+2);
|
||||
raw >>= (8 - oversampling);
|
||||
}
|
||||
*/
|
||||
|
||||
#if BMP085_DEBUG == 1
|
||||
Serial.print("Raw pressure: ");
|
||||
Serial.println(raw);
|
||||
#endif
|
||||
return raw;
|
||||
}
|
||||
|
||||
int32_t Adafruit_BMP085::readPressure(void) {
|
||||
int32_t UT, UP, B3, B5, B6, X1, X2, X3, p;
|
||||
uint32_t B4, B7;
|
||||
|
||||
UT = readRawTemperature();
|
||||
UP = readRawPressure();
|
||||
|
||||
#if BMP085_DEBUG == 1
|
||||
// use datasheet numbers!
|
||||
UT = 27898;
|
||||
UP = 23843;
|
||||
ac6 = 23153;
|
||||
ac5 = 32757;
|
||||
mc = -8711;
|
||||
md = 2868;
|
||||
b1 = 6190;
|
||||
b2 = 4;
|
||||
ac3 = -14383;
|
||||
ac2 = -72;
|
||||
ac1 = 408;
|
||||
ac4 = 32741;
|
||||
oversampling = 0;
|
||||
#endif
|
||||
|
||||
B5 = computeB5(UT);
|
||||
|
||||
#if BMP085_DEBUG == 1
|
||||
Serial.print("X1 = ");
|
||||
Serial.println(X1);
|
||||
Serial.print("X2 = ");
|
||||
Serial.println(X2);
|
||||
Serial.print("B5 = ");
|
||||
Serial.println(B5);
|
||||
#endif
|
||||
|
||||
// do pressure calcs
|
||||
B6 = B5 - 4000;
|
||||
X1 = ((int32_t)b2 * ((B6 * B6) >> 12)) >> 11;
|
||||
X2 = ((int32_t)ac2 * B6) >> 11;
|
||||
X3 = X1 + X2;
|
||||
B3 = ((((int32_t)ac1 * 4 + X3) << oversampling) + 2) / 4;
|
||||
|
||||
#if BMP085_DEBUG == 1
|
||||
Serial.print("B6 = ");
|
||||
Serial.println(B6);
|
||||
Serial.print("X1 = ");
|
||||
Serial.println(X1);
|
||||
Serial.print("X2 = ");
|
||||
Serial.println(X2);
|
||||
Serial.print("B3 = ");
|
||||
Serial.println(B3);
|
||||
#endif
|
||||
|
||||
X1 = ((int32_t)ac3 * B6) >> 13;
|
||||
X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16;
|
||||
X3 = ((X1 + X2) + 2) >> 2;
|
||||
B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15;
|
||||
B7 = ((uint32_t)UP - B3) * (uint32_t)(50000UL >> oversampling);
|
||||
|
||||
#if BMP085_DEBUG == 1
|
||||
Serial.print("X1 = ");
|
||||
Serial.println(X1);
|
||||
Serial.print("X2 = ");
|
||||
Serial.println(X2);
|
||||
Serial.print("B4 = ");
|
||||
Serial.println(B4);
|
||||
Serial.print("B7 = ");
|
||||
Serial.println(B7);
|
||||
#endif
|
||||
|
||||
if (B7 < 0x80000000) {
|
||||
p = (B7 * 2) / B4;
|
||||
} else {
|
||||
p = (B7 / B4) * 2;
|
||||
}
|
||||
X1 = (p >> 8) * (p >> 8);
|
||||
X1 = (X1 * 3038) >> 16;
|
||||
X2 = (-7357 * p) >> 16;
|
||||
|
||||
#if BMP085_DEBUG == 1
|
||||
Serial.print("p = ");
|
||||
Serial.println(p);
|
||||
Serial.print("X1 = ");
|
||||
Serial.println(X1);
|
||||
Serial.print("X2 = ");
|
||||
Serial.println(X2);
|
||||
#endif
|
||||
|
||||
p = p + ((X1 + X2 + (int32_t)3791) >> 4);
|
||||
#if BMP085_DEBUG == 1
|
||||
Serial.print("p = ");
|
||||
Serial.println(p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
int32_t Adafruit_BMP085::readSealevelPressure(float altitude_meters) {
|
||||
float pressure = readPressure();
|
||||
return (int32_t)(pressure / pow(1.0 - altitude_meters / 44330, 5.255));
|
||||
}
|
||||
|
||||
float Adafruit_BMP085::readTemperature(void) {
|
||||
int32_t UT, B5; // following ds convention
|
||||
float temp;
|
||||
|
||||
UT = readRawTemperature();
|
||||
|
||||
#if BMP085_DEBUG == 1
|
||||
// use datasheet numbers!
|
||||
UT = 27898;
|
||||
ac6 = 23153;
|
||||
ac5 = 32757;
|
||||
mc = -8711;
|
||||
md = 2868;
|
||||
#endif
|
||||
|
||||
B5 = computeB5(UT);
|
||||
temp = (B5 + 8) >> 4;
|
||||
temp /= 10;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
float Adafruit_BMP085::readAltitude(float sealevelPressure) {
|
||||
float altitude;
|
||||
|
||||
float pressure = readPressure();
|
||||
|
||||
altitude = 44330 * (1.0 - pow(pressure / sealevelPressure, 0.1903));
|
||||
|
||||
return altitude;
|
||||
}
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
uint8_t Adafruit_BMP085::read8(uint8_t a) {
|
||||
uint8_t ret;
|
||||
|
||||
// send 1 byte, reset i2c, read 1 byte
|
||||
i2c_dev->write_then_read(&a, 1, &ret, 1, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t Adafruit_BMP085::read16(uint8_t a) {
|
||||
uint8_t retbuf[2];
|
||||
uint16_t ret;
|
||||
|
||||
// send 1 byte, reset i2c, read 2 bytes
|
||||
// we could typecast uint16_t as uint8_t array but would need to ensure proper
|
||||
// endianness
|
||||
i2c_dev->write_then_read(&a, 1, retbuf, 2, true);
|
||||
|
||||
// write_then_read uses uint8_t array
|
||||
ret = retbuf[1] | (retbuf[0] << 8);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Adafruit_BMP085::write8(uint8_t a, uint8_t d) {
|
||||
// send d prefixed with a (a d [stop])
|
||||
i2c_dev->write(&d, 1, true, &a, 1);
|
||||
}
|
||||
112
libraries/Adafruit_BMP085_Library/Adafruit_BMP085.h
Normal file
112
libraries/Adafruit_BMP085_Library/Adafruit_BMP085.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*!
|
||||
* @file Adafruit_BMP085.h
|
||||
*
|
||||
* This is a library for the Adafruit BMP085/BMP180 Barometric Pressure + Temp
|
||||
* sensor
|
||||
*
|
||||
* Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
* ----> http://www.adafruit.com/products/391
|
||||
* ----> http://www.adafruit.com/products/1603
|
||||
*
|
||||
* These displays use I2C to communicate, 2 pins are required to
|
||||
* interface
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
* BSD license, all text above must be included in any redistribution
|
||||
*/
|
||||
|
||||
#ifndef ADAFRUIT_BMP085_H
|
||||
#define ADAFRUIT_BMP085_H
|
||||
|
||||
#include <Adafruit_I2CDevice.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#define BMP085_DEBUG 0 //!< Debug mode
|
||||
|
||||
#define BMP085_I2CADDR 0x77 //!< BMP085 I2C address
|
||||
|
||||
#define BMP085_ULTRALOWPOWER 0 //!< Ultra low power mode
|
||||
#define BMP085_STANDARD 1 //!< Standard mode
|
||||
#define BMP085_HIGHRES 2 //!< High-res mode
|
||||
#define BMP085_ULTRAHIGHRES 3 //!< Ultra high-res mode
|
||||
#define BMP085_CAL_AC1 0xAA //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_AC2 0xAC //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_AC3 0xAE //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_AC4 0xB0 //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_AC5 0xB2 //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_AC6 0xB4 //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_B1 0xB6 //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_B2 0xB8 //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_MB 0xBA //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_MC 0xBC //!< R Calibration data (16 bits)
|
||||
#define BMP085_CAL_MD 0xBE //!< R Calibration data (16 bits)
|
||||
|
||||
#define BMP085_CONTROL 0xF4 //!< Control register
|
||||
#define BMP085_TEMPDATA 0xF6 //!< Temperature data register
|
||||
#define BMP085_PRESSUREDATA 0xF6 //!< Pressure data register
|
||||
#define BMP085_READTEMPCMD 0x2E //!< Read temperature control register value
|
||||
#define BMP085_READPRESSURECMD 0x34 //!< Read pressure control register value
|
||||
|
||||
/*!
|
||||
* @brief Main BMP085 class
|
||||
*/
|
||||
class Adafruit_BMP085 {
|
||||
public:
|
||||
Adafruit_BMP085();
|
||||
/*!
|
||||
* @brief Starts I2C connection
|
||||
* @param mode Mode to set, ultra high-res by default
|
||||
* @param wire The I2C interface to use, defaults to Wire
|
||||
* @return Returns true if successful
|
||||
*/
|
||||
bool begin(uint8_t mode = BMP085_ULTRAHIGHRES, TwoWire *wire = &Wire);
|
||||
/*!
|
||||
* @brief Gets the temperature over I2C from the BMP085
|
||||
* @return Returns the temperature
|
||||
*/
|
||||
float readTemperature(void);
|
||||
/*!
|
||||
* @brief Gets the pressure over I2C from the BMP085
|
||||
* @return Returns the pressure
|
||||
*/
|
||||
int32_t readPressure(void);
|
||||
/*!
|
||||
* @brief Calculates the pressure at sea level
|
||||
* @param altitude_meters Current altitude (in meters)
|
||||
* @return Returns the calculated pressure at sea level
|
||||
*/
|
||||
int32_t readSealevelPressure(float altitude_meters = 0);
|
||||
/*!
|
||||
* @brief Reads the altitude
|
||||
* @param sealevelPressure Pressure at sea level, measured in pascals
|
||||
* @return Returns the altitude
|
||||
*/
|
||||
float readAltitude(float sealevelPressure = 101325); // std atmosphere
|
||||
/*!
|
||||
* @brief Reads the raw temperature
|
||||
* @return Returns the raw temperature
|
||||
*/
|
||||
uint16_t readRawTemperature(void);
|
||||
/*!
|
||||
* @brief Reads the raw pressure
|
||||
* @return Returns the raw pressure
|
||||
*/
|
||||
uint32_t readRawPressure(void);
|
||||
|
||||
private:
|
||||
int32_t computeB5(int32_t UT);
|
||||
uint8_t read8(uint8_t addr);
|
||||
uint16_t read16(uint8_t addr);
|
||||
void write8(uint8_t addr, uint8_t data);
|
||||
|
||||
Adafruit_I2CDevice *i2c_dev;
|
||||
uint8_t oversampling;
|
||||
|
||||
int16_t ac1, ac2, ac3, b1, b2, mb, mc, md;
|
||||
uint16_t ac4, ac5, ac6;
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_BMP085_H
|
||||
32
libraries/Adafruit_BMP085_Library/README.md
Normal file
32
libraries/Adafruit_BMP085_Library/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Adafruit BMP085 Library [](https://github.com/adafruit/Adafruit-BMP085-Library/actions)[](http://adafruit.github.io/Adafruit-BMP085-Library/html/index.html)
|
||||
|
||||
This is a library for the Adafruit BMP085/BMP180 Barometric Pressure + Temp sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
----> http://www.adafruit.com/products/391
|
||||
----> http://www.adafruit.com/products/1603
|
||||
|
||||
These displays use I2C to communicate, 2 pins are required to interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Check out the links above for our tutorials and wiring diagrams
|
||||
|
||||
Requires the https://github.com/adafruit/Adafruit_BusIO library for I2C abstraction
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
|
||||
To download. click the DOWNLOAD ZIP button, rename the uncompressed folder Adafruit_BMP085.
|
||||
Check that the Adafruit_BMP085 folder contains Adafruit_BMP085.cpp and Adafruit_BMP085.h
|
||||
|
||||
Place the Adafruit_BMP085 library folder your arduinosketchfolder/libraries/ folder.
|
||||
You may need to create the libraries subfolder if its your first library. Restart the IDE.
|
||||
|
||||
We also have a great tutorial on Arduino library installation at:
|
||||
http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <Adafruit_BMP085.h>
|
||||
|
||||
/***************************************************
|
||||
This is an example for the BMP085 Barometric Pressure & Temp Sensor
|
||||
|
||||
Designed specifically to work with the Adafruit BMP085 Breakout
|
||||
----> https://www.adafruit.com/products/391
|
||||
|
||||
These pressure and temperature sensors use I2C to communicate, 2 pins
|
||||
are required to interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
// Connect VCC of the BMP085 sensor to 3.3V (NOT 5.0V!)
|
||||
// Connect GND to Ground
|
||||
// Connect SCL to i2c clock - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 5
|
||||
// Connect SDA to i2c data - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 4
|
||||
// EOC is not used, it signifies an end of conversion
|
||||
// XCLR is a reset pin, also not used here
|
||||
|
||||
Adafruit_BMP085 bmp;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
if (!bmp.begin()) {
|
||||
Serial.println("Could not find a valid BMP085 sensor, check wiring!");
|
||||
while (1) {}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.print("Temperature = ");
|
||||
Serial.print(bmp.readTemperature());
|
||||
Serial.println(" *C");
|
||||
|
||||
Serial.print("Pressure = ");
|
||||
Serial.print(bmp.readPressure());
|
||||
Serial.println(" Pa");
|
||||
|
||||
// Calculate altitude assuming 'standard' barometric
|
||||
// pressure of 1013.25 millibar = 101325 Pascal
|
||||
Serial.print("Altitude = ");
|
||||
Serial.print(bmp.readAltitude());
|
||||
Serial.println(" meters");
|
||||
|
||||
Serial.print("Pressure at sealevel (calculated) = ");
|
||||
Serial.print(bmp.readSealevelPressure());
|
||||
Serial.println(" Pa");
|
||||
|
||||
// you can get a more precise measurement of altitude
|
||||
// if you know the current sea level pressure which will
|
||||
// vary with weather and such. If it is 1015 millibars
|
||||
// that is equal to 101500 Pascals.
|
||||
Serial.print("Real altitude = ");
|
||||
Serial.print(bmp.readAltitude(101500));
|
||||
Serial.println(" meters");
|
||||
|
||||
Serial.println();
|
||||
delay(500);
|
||||
}
|
||||
10
libraries/Adafruit_BMP085_Library/library.properties
Normal file
10
libraries/Adafruit_BMP085_Library/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=Adafruit BMP085 Library
|
||||
version=1.2.4
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=A powerful but easy to use BMP085/BMP180 Library
|
||||
paragraph=A powerful but easy to use BMP085/BMP180 Library
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit-BMP085-Library
|
||||
architectures=*
|
||||
depends=Adafruit Unified Sensor, Adafruit BusIO
|
||||
478
libraries/Adafruit_BMP085_Unified/Adafruit_BMP085_U.cpp
Normal file
478
libraries/Adafruit_BMP085_Unified/Adafruit_BMP085_U.cpp
Normal file
@@ -0,0 +1,478 @@
|
||||
/*!
|
||||
* @file Adafruit_BMP085_U.cpp
|
||||
*
|
||||
* @mainpage Adafruit BMP085 Pressure Sensor
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
* This is a library for the BMP085 pressure sensor
|
||||
*
|
||||
* Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
|
||||
* ----> http://www.adafruit.com/products/391
|
||||
* ----> http://www.adafruit.com/products/1603
|
||||
*
|
||||
* These displays use I2C to communicate, 2 pins are required to interface.
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit andopen-source hardware by purchasing products
|
||||
* from Adafruit!
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Kevin Townsend for Adafruit Industries.
|
||||
*
|
||||
* @section license License
|
||||
* BSD license, all text above must be included in any redistribution
|
||||
*/
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "Adafruit_BMP085_U.h"
|
||||
|
||||
static bmp085_calib_data
|
||||
_bmp085_coeffs; // Last read accelerometer data will be available here
|
||||
static uint8_t _bmp085Mode;
|
||||
|
||||
#define BMP085_USE_DATASHEET_VALS \
|
||||
(0) //!< Set to 1 for sanity check, when true, will use values from datasheet
|
||||
|
||||
/***************************************************************************
|
||||
PRIVATE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void writeCommand(byte reg, byte value) {
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)value);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void read8(byte reg, uint8_t *value) {
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)1);
|
||||
#if ARDUINO >= 100
|
||||
*value = Wire.read();
|
||||
#else
|
||||
*value = Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a 16 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void read16(byte reg, uint16_t *value) {
|
||||
Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write((uint8_t)reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)2);
|
||||
#if ARDUINO >= 100
|
||||
*value = (Wire.read() << 8) | Wire.read();
|
||||
#else
|
||||
*value = (Wire.receive() << 8) | Wire.receive();
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a signed 16 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readS16(byte reg, int16_t *value) {
|
||||
uint16_t i;
|
||||
read16(reg, &i);
|
||||
*value = (int16_t)i;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the factory-set coefficients
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readCoefficients(void) {
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
_bmp085_coeffs.ac1 = 408;
|
||||
_bmp085_coeffs.ac2 = -72;
|
||||
_bmp085_coeffs.ac3 = -14383;
|
||||
_bmp085_coeffs.ac4 = 32741;
|
||||
_bmp085_coeffs.ac5 = 32757;
|
||||
_bmp085_coeffs.ac6 = 23153;
|
||||
_bmp085_coeffs.b1 = 6190;
|
||||
_bmp085_coeffs.b2 = 4;
|
||||
_bmp085_coeffs.mb = -32768;
|
||||
_bmp085_coeffs.mc = -8711;
|
||||
_bmp085_coeffs.md = 2868;
|
||||
_bmp085Mode = 0;
|
||||
#else
|
||||
readS16(BMP085_REGISTER_CAL_AC1, &_bmp085_coeffs.ac1);
|
||||
readS16(BMP085_REGISTER_CAL_AC2, &_bmp085_coeffs.ac2);
|
||||
readS16(BMP085_REGISTER_CAL_AC3, &_bmp085_coeffs.ac3);
|
||||
read16(BMP085_REGISTER_CAL_AC4, &_bmp085_coeffs.ac4);
|
||||
read16(BMP085_REGISTER_CAL_AC5, &_bmp085_coeffs.ac5);
|
||||
read16(BMP085_REGISTER_CAL_AC6, &_bmp085_coeffs.ac6);
|
||||
readS16(BMP085_REGISTER_CAL_B1, &_bmp085_coeffs.b1);
|
||||
readS16(BMP085_REGISTER_CAL_B2, &_bmp085_coeffs.b2);
|
||||
readS16(BMP085_REGISTER_CAL_MB, &_bmp085_coeffs.mb);
|
||||
readS16(BMP085_REGISTER_CAL_MC, &_bmp085_coeffs.mc);
|
||||
readS16(BMP085_REGISTER_CAL_MD, &_bmp085_coeffs.md);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readRawTemperature(int32_t *temperature) {
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
*temperature = 27898;
|
||||
#else
|
||||
uint16_t t;
|
||||
writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READTEMPCMD);
|
||||
delay(5);
|
||||
read16(BMP085_REGISTER_TEMPDATA, &t);
|
||||
*temperature = t;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void readRawPressure(int32_t *pressure) {
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
*pressure = 23843;
|
||||
#else
|
||||
uint8_t p8;
|
||||
uint16_t p16;
|
||||
int32_t p32;
|
||||
|
||||
writeCommand(BMP085_REGISTER_CONTROL,
|
||||
BMP085_REGISTER_READPRESSURECMD + (_bmp085Mode << 6));
|
||||
switch (_bmp085Mode) {
|
||||
case BMP085_MODE_ULTRALOWPOWER:
|
||||
delay(5);
|
||||
break;
|
||||
case BMP085_MODE_STANDARD:
|
||||
delay(8);
|
||||
break;
|
||||
case BMP085_MODE_HIGHRES:
|
||||
delay(14);
|
||||
break;
|
||||
case BMP085_MODE_ULTRAHIGHRES:
|
||||
default:
|
||||
delay(26);
|
||||
break;
|
||||
}
|
||||
|
||||
read16(BMP085_REGISTER_PRESSUREDATA, &p16);
|
||||
p32 = (uint32_t)p16 << 8;
|
||||
read8(BMP085_REGISTER_PRESSUREDATA + 2, &p8);
|
||||
p32 += p8;
|
||||
p32 >>= (8 - _bmp085Mode);
|
||||
|
||||
*pressure = p32;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Compute B5 coefficient used in temperature & pressure calcs.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int32_t Adafruit_BMP085_Unified::computeB5(int32_t ut) {
|
||||
int32_t X1 =
|
||||
(ut - (int32_t)_bmp085_coeffs.ac6) * ((int32_t)_bmp085_coeffs.ac5) >> 15;
|
||||
int32_t X2 =
|
||||
((int32_t)_bmp085_coeffs.mc << 11) / (X1 + (int32_t)_bmp085_coeffs.md);
|
||||
return X1 + X2;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
CONSTRUCTOR
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new Adafruit_BMP085_Unified class
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_BMP085_Unified::Adafruit_BMP085_Unified(int32_t sensorID) {
|
||||
_sensorID = sensorID;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
PUBLIC FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BMP085_Unified::begin(bmp085_mode_t mode) {
|
||||
// Enable I2C
|
||||
Wire.begin();
|
||||
|
||||
/* Mode boundary check */
|
||||
if ((mode > BMP085_MODE_ULTRAHIGHRES) || (mode < 0)) {
|
||||
mode = BMP085_MODE_ULTRAHIGHRES;
|
||||
}
|
||||
|
||||
/* Make sure we have the right device */
|
||||
uint8_t id;
|
||||
read8(BMP085_REGISTER_CHIPID, &id);
|
||||
if (id != 0x55) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the mode indicator */
|
||||
_bmp085Mode = mode;
|
||||
|
||||
/* Coefficients need to be read once */
|
||||
readCoefficients();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the compensated pressure level in kPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getPressure(float *pressure) {
|
||||
int32_t ut = 0, up = 0, compp = 0;
|
||||
int32_t x1, x2, b5, b6, x3, b3, p;
|
||||
uint32_t b4, b7;
|
||||
|
||||
/* Get the raw pressure and temperature values */
|
||||
readRawTemperature(&ut);
|
||||
readRawPressure(&up);
|
||||
|
||||
/* Temperature compensation */
|
||||
b5 = computeB5(ut);
|
||||
|
||||
/* Pressure compensation */
|
||||
b6 = b5 - 4000;
|
||||
x1 = (_bmp085_coeffs.b2 * ((b6 * b6) >> 12)) >> 11;
|
||||
x2 = (_bmp085_coeffs.ac2 * b6) >> 11;
|
||||
x3 = x1 + x2;
|
||||
b3 = (((((int32_t)_bmp085_coeffs.ac1) * 4 + x3) << _bmp085Mode) + 2) >> 2;
|
||||
x1 = (_bmp085_coeffs.ac3 * b6) >> 13;
|
||||
x2 = (_bmp085_coeffs.b1 * ((b6 * b6) >> 12)) >> 16;
|
||||
x3 = ((x1 + x2) + 2) >> 2;
|
||||
b4 = (_bmp085_coeffs.ac4 * (uint32_t)(x3 + 32768)) >> 15;
|
||||
b7 = ((uint32_t)(up - b3) * (50000 >> _bmp085Mode));
|
||||
|
||||
if (b7 < 0x80000000) {
|
||||
p = (b7 << 1) / b4;
|
||||
} else {
|
||||
p = (b7 / b4) << 1;
|
||||
}
|
||||
|
||||
x1 = (p >> 8) * (p >> 8);
|
||||
x1 = (x1 * 3038) >> 16;
|
||||
x2 = (-7357 * p) >> 16;
|
||||
compp = p + ((x1 + x2 + 3791) >> 4);
|
||||
|
||||
/* Assign compensated pressure value */
|
||||
*pressure = compp;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the temperatures in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getTemperature(float *temp) {
|
||||
int32_t UT, B5; // following ds convention
|
||||
float t;
|
||||
|
||||
readRawTemperature(&UT);
|
||||
|
||||
#if BMP085_USE_DATASHEET_VALS
|
||||
// use datasheet numbers!
|
||||
UT = 27898;
|
||||
_bmp085_coeffs.ac6 = 23153;
|
||||
_bmp085_coeffs.ac5 = 32757;
|
||||
_bmp085_coeffs.mc = -8711;
|
||||
_bmp085_coeffs.md = 2868;
|
||||
#endif
|
||||
|
||||
B5 = computeB5(UT);
|
||||
t = (B5 + 8) >> 4;
|
||||
t /= 10;
|
||||
|
||||
*temp = t;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the altitude (in meters) from the specified atmospheric
|
||||
pressure (in hPa), and sea-level pressure (in hPa).
|
||||
|
||||
@param seaLevel Sea-level pressure in hPa
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel,
|
||||
float atmospheric) {
|
||||
// Equation taken from BMP180 datasheet (page 16):
|
||||
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||
|
||||
// Note that using the equation from wikipedia can give bad results
|
||||
// at high altitude. See this thread for more information:
|
||||
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
|
||||
|
||||
return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the altitude (in meters) from the specified atmospheric
|
||||
pressure (in hPa), and sea-level pressure (in hPa). Note that this
|
||||
function just calls the overload of pressureToAltitude which takes
|
||||
seaLevel and atmospheric pressure--temperature is ignored. The original
|
||||
implementation of this function was based on calculations from Wikipedia
|
||||
which are not accurate at higher altitudes. To keep compatibility with
|
||||
old code this function remains with the same interface, but it calls the
|
||||
more accurate calculation.
|
||||
|
||||
@param seaLevel Sea-level pressure in hPa
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
@param temp Temperature in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel,
|
||||
float atmospheric,
|
||||
float temp) {
|
||||
return pressureToAltitude(seaLevel, atmospheric);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the pressure at sea level (in hPa) from the specified altitude
|
||||
(in meters), and atmospheric pressure (in hPa).
|
||||
|
||||
@param altitude Altitude in meters
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude,
|
||||
float atmospheric) {
|
||||
// Equation taken from BMP180 datasheet (page 17):
|
||||
// http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||
|
||||
// Note that using the equation from wikipedia can give bad results
|
||||
// at high altitude. See this thread for more information:
|
||||
// http://forums.adafruit.com/viewtopic.php?f=22&t=58064
|
||||
|
||||
return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Calculates the pressure at sea level (in hPa) from the specified altitude
|
||||
(in meters), and atmospheric pressure (in hPa). Note that this
|
||||
function just calls the overload of seaLevelForAltitude which takes
|
||||
altitude and atmospheric pressure--temperature is ignored. The original
|
||||
implementation of this function was based on calculations from Wikipedia
|
||||
which are not accurate at higher altitudes. To keep compatibility with
|
||||
old code this function remains with the same interface, but it calls the
|
||||
more accurate calculation.
|
||||
|
||||
@param altitude Altitude in meters
|
||||
@param atmospheric Atmospheric pressure in hPa
|
||||
@param temp Temperature in degrees Celsius
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude,
|
||||
float atmospheric,
|
||||
float temp) {
|
||||
return seaLevelForAltitude(altitude, atmospheric);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Provides the sensor_t data for this sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_BMP085_Unified::getSensor(sensor_t *sensor) {
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy(sensor->name, "BMP085", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name) - 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_PRESSURE;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 1100.0F; // 300..1100 hPa
|
||||
sensor->min_value = 300.0F;
|
||||
sensor->resolution = 0.01F; // Datasheet states 0.01 hPa resolution
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads the sensor and returns the data as a sensors_event_t
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_BMP085_Unified::getEvent(sensors_event_t *event) {
|
||||
float pressure_kPa;
|
||||
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_PRESSURE;
|
||||
event->timestamp = 0;
|
||||
getPressure(&pressure_kPa);
|
||||
event->pressure = pressure_kPa / 100.0F;
|
||||
|
||||
return true;
|
||||
}
|
||||
154
libraries/Adafruit_BMP085_Unified/Adafruit_BMP085_U.h
Normal file
154
libraries/Adafruit_BMP085_Unified/Adafruit_BMP085_U.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/*!
|
||||
* @file Adafruit_BMP085_U.h
|
||||
*/
|
||||
|
||||
#ifndef __BMP085_H__
|
||||
#define __BMP085_H__
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Adafruit_Sensor.h>
|
||||
|
||||
#ifdef __AVR_ATtiny85__
|
||||
#include "TinyWireM.h"
|
||||
#define Wire TinyWireM
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @brief BMP085 I2C address/bits
|
||||
*/
|
||||
#define BMP085_ADDRESS (0x77)
|
||||
|
||||
/*!
|
||||
* @brief BMP085 I2C registers
|
||||
*/
|
||||
enum {
|
||||
BMP085_REGISTER_CAL_AC1 = 0xAA, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC2 = 0xAC, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC3 = 0xAE, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC4 = 0xB0, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC5 = 0xB2, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_AC6 = 0xB4, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_B1 = 0xB6, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_B2 = 0xB8, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MB = 0xBA, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MC = 0xBC, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CAL_MD = 0xBE, //!< R Calibration data (16 bits)
|
||||
BMP085_REGISTER_CHIPID = 0xD0, //!< Register that contains the chip ID
|
||||
BMP085_REGISTER_VERSION = 0xD1, //!< Register that contains the chip version
|
||||
BMP085_REGISTER_SOFTRESET = 0xE0, //!< Register for doing a soft reset
|
||||
BMP085_REGISTER_CONTROL = 0xF4, //!< Control register
|
||||
BMP085_REGISTER_TEMPDATA = 0xF6, //!< Temperature data register
|
||||
BMP085_REGISTER_PRESSUREDATA = 0xF6, //!< Pressure data register
|
||||
BMP085_REGISTER_READTEMPCMD =
|
||||
0x2E, //!< Read temperature control register value
|
||||
BMP085_REGISTER_READPRESSURECMD =
|
||||
0x34 //!< Read pressure control register value
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief BMP085 mode settings
|
||||
*/
|
||||
typedef enum {
|
||||
BMP085_MODE_ULTRALOWPOWER = 0,
|
||||
BMP085_MODE_STANDARD = 1,
|
||||
BMP085_MODE_HIGHRES = 2,
|
||||
BMP085_MODE_ULTRAHIGHRES = 3
|
||||
} bmp085_mode_t;
|
||||
/*=========================================================================*/
|
||||
|
||||
/*!
|
||||
* @brief Calibration data
|
||||
*/
|
||||
typedef struct {
|
||||
int16_t ac1; //!< R calibration coefficient (16-bits)
|
||||
int16_t ac2; //!< R calibration coefficient (16-bits)
|
||||
int16_t ac3; //!< R calibration coefficient (16-bits)
|
||||
uint16_t ac4; //!< R calibration coefficient (16-bits)
|
||||
uint16_t ac5; //!< R calibration coefficient (16-bits)
|
||||
uint16_t ac6; //!< R calibration coefficient (16-bits)
|
||||
int16_t b1; //!< R calibration coefficient (16-bits)
|
||||
int16_t b2; //!< R calibration coefficient (16-bits)
|
||||
int16_t mb; //!< R calibration coefficient (16-bits)
|
||||
int16_t mc; //!< R calibration coefficient (16-bits)
|
||||
int16_t md; //!< R calibration coefficient (16-bits)
|
||||
} bmp085_calib_data;
|
||||
|
||||
/*!
|
||||
* @brief Class that stores state and functions for interacting with BMP183
|
||||
*/
|
||||
class Adafruit_BMP085_Unified : public Adafruit_Sensor {
|
||||
public:
|
||||
Adafruit_BMP085_Unified(
|
||||
int32_t sensorID = -1); //!< @param sensorID ID of the BMP085 sensor
|
||||
|
||||
/*!
|
||||
* @brief Starts I2C connection
|
||||
* @param mode Mode to set, ultra high-res by default
|
||||
* @return Returns true if successful
|
||||
*/
|
||||
bool begin(bmp085_mode_t mode = BMP085_MODE_ULTRAHIGHRES);
|
||||
/*!
|
||||
* @brief Gets the temperature over I2C from the BMP085
|
||||
* @param temp Temperature
|
||||
* @return Returns the temperature
|
||||
*/
|
||||
void getTemperature(float *temp);
|
||||
/*!
|
||||
* @brief Gets the pressure over I2C from the BMP085
|
||||
* @param pressure Pressure
|
||||
* @return Returns the pressure
|
||||
*/
|
||||
void getPressure(float *pressure);
|
||||
/*!
|
||||
* @brief Calculates absolute pressure
|
||||
* @param seaLevel Pressure at sea level
|
||||
* @param atmospheric measured pressure
|
||||
* @return Absolute altitude
|
||||
*/
|
||||
float pressureToAltitude(float seaLevel, float atmospheric);
|
||||
/*!
|
||||
* @brief Calculates pressure at sea level
|
||||
* @param altitude Altitude
|
||||
* @param atmospheric measured pressure
|
||||
* @return Pressure at sea level
|
||||
*/
|
||||
float seaLevelForAltitude(float altitude, float atmospheric);
|
||||
// Note that the next two functions are just for compatibility with old
|
||||
// code that passed the temperature as a third parameter. A newer
|
||||
// calculation is used which does not need temperature.
|
||||
/*!
|
||||
* @brief Calculates absolute pressure
|
||||
* @param seaLevel Pressure at sea level
|
||||
* @param atmospheric Measured pressure
|
||||
* @param temp Temperature
|
||||
* @return Absolute altitude
|
||||
*/
|
||||
float pressureToAltitude(float seaLevel, float atmospheric, float temp);
|
||||
/*!
|
||||
* @brief Calculates pressure at sea level
|
||||
* @param altitude Altitude
|
||||
* @param atmospheric measured pressure
|
||||
* @param temp Temperature
|
||||
* @return Pressure at sea level
|
||||
*/
|
||||
float seaLevelForAltitude(float altitude, float atmospheric, float temp);
|
||||
/*!
|
||||
* @brief Used to read the sensor
|
||||
* @return Returns an event
|
||||
*/
|
||||
bool getEvent(sensors_event_t *);
|
||||
void getSensor(sensor_t *);
|
||||
|
||||
private:
|
||||
int32_t computeB5(int32_t ut);
|
||||
int32_t _sensorID;
|
||||
};
|
||||
|
||||
#endif
|
||||
27
libraries/Adafruit_BMP085_Unified/README.md
Normal file
27
libraries/Adafruit_BMP085_Unified/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Adafruit Unified BMP085/BMP180 Driver (Barometric Pressure Sensor) [](https://github.com/adafruit/Adafruit_BMP085_Unified/actions)[](http://adafruit.github.io/Adafruit_BMP085_Unified/html/index.html)
|
||||
|
||||
This driver is for the Adafruit BMP085 Breakout (http://www.adafruit.com/products/391) or BMP180 breakout (http://www.adafruit.com/products/1603), and is based on Adafruit's Unified Sensor Library (Adafruit_Sensor).
|
||||
|
||||
## About the BMP085 / BMP180 ##
|
||||
|
||||
This precision sensor from Bosch is the best low-cost sensing solution for measuring barometric pressure and temperature. Because pressure changes with altitude you can also use it as an altimeter!
|
||||
|
||||
## What is the Adafruit Unified Sensor Library? ##
|
||||
|
||||
The Adafruit Unified Sensor Library ([Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor)) provides a common interface and data type for any supported sensor. It defines some basic information about the sensor (sensor limits, etc.), and returns standard SI units of a specific type and scale for each supported sensor type.
|
||||
|
||||
It provides a simple abstraction layer between your application and the actual sensor HW, allowing you to drop in any comparable sensor with only one or two lines of code to change in your project (essentially the constructor since the functions to read sensor data and get information about the sensor are defined in the base Adafruit_Sensor class).
|
||||
|
||||
This is imporant useful for two reasons:
|
||||
|
||||
1.) You can use the data right away because it's already converted to SI units that you understand and can compare, rather than meaningless values like 0..1023.
|
||||
|
||||
2.) Because SI units are standardised in the sensor library, you can also do quick sanity checks when working with new sensors, or drop in any comparable sensor if you need better sensitivity or if a lower cost unit becomes available, etc.
|
||||
|
||||
Light sensors will always report units in lux, gyroscopes will always report units in rad/s, etc. ... freeing you up to focus on the data, rather than digging through the datasheet to understand what the sensor's raw numbers really mean.
|
||||
|
||||
## About this Driver ##
|
||||
|
||||
Adafruit invests time and resources providing this open source code. Please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
Written by Kevin (KTOWN) Townsend for Adafruit Industries.
|
||||
@@ -0,0 +1,132 @@
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BMP085_U.h>
|
||||
|
||||
/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor),
|
||||
which provides a common 'type' for sensor data and some helper functions.
|
||||
|
||||
To use this driver you will also need to download the Adafruit_Sensor
|
||||
library and include it in your libraries folder.
|
||||
|
||||
You should also assign a unique ID to this sensor for use with
|
||||
the Adafruit Sensor API so that you can identify this particular
|
||||
sensor in any data logs, etc. To assign a unique ID, simply
|
||||
provide an appropriate value in the constructor below (12345
|
||||
is used by default in this example).
|
||||
|
||||
Connections
|
||||
===========
|
||||
Connect SCL to analog 5
|
||||
Connect SDA to analog 4
|
||||
Connect VDD to 3.3V DC
|
||||
Connect GROUND to common ground
|
||||
|
||||
History
|
||||
=======
|
||||
2013/JUN/17 - Updated altitude calculations (KTOWN)
|
||||
2013/FEB/13 - First version (KTOWN)
|
||||
*/
|
||||
|
||||
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Displays some basic information on this sensor from the unified
|
||||
sensor API sensor_t type (see Adafruit_Sensor for more information)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void displaySensorDetails(void)
|
||||
{
|
||||
sensor_t sensor;
|
||||
bmp.getSensor(&sensor);
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" hPa");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" hPa");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" hPa");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino setup function (automatically called at startup)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("Pressure Sensor Test"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!bmp.begin())
|
||||
{
|
||||
/* There was a problem detecting the BMP085 ... check your connections */
|
||||
Serial.print("Ooops, no BMP085 detected ... Check your wiring or I2C ADDR!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
displaySensorDetails();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino loop function, called once 'setup' is complete (your own code
|
||||
should go here)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
bmp.getEvent(&event);
|
||||
|
||||
/* Display the results (barometric pressure is measure in hPa) */
|
||||
if (event.pressure)
|
||||
{
|
||||
/* Display atmospheric pressue in hPa */
|
||||
Serial.print("Pressure: ");
|
||||
Serial.print(event.pressure);
|
||||
Serial.println(" hPa");
|
||||
|
||||
/* Calculating altitude with reasonable accuracy requires pressure *
|
||||
* sea level pressure for your position at the moment the data is *
|
||||
* converted, as well as the ambient temperature in degress *
|
||||
* celcius. If you don't have these values, a 'generic' value of *
|
||||
* 1013.25 hPa can be used (defined as SENSORS_PRESSURE_SEALEVELHPA *
|
||||
* in sensors.h), but this isn't ideal and will give variable *
|
||||
* results from one day to the next. *
|
||||
* *
|
||||
* You can usually find the current SLP value by looking at weather *
|
||||
* websites or from environmental information centers near any major *
|
||||
* airport. *
|
||||
* *
|
||||
* For example, for Paris, France you can check the current mean *
|
||||
* pressure and sea level at: http://bit.ly/16Au8ol */
|
||||
|
||||
/* First we get the current temperature from the BMP085 */
|
||||
float temperature;
|
||||
bmp.getTemperature(&temperature);
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(temperature);
|
||||
Serial.println(" C");
|
||||
|
||||
/* Then convert the atmospheric pressure, and SLP to altitude */
|
||||
/* Update this next line with the current SLP for better results */
|
||||
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
|
||||
Serial.print("Altitude: ");
|
||||
Serial.print(bmp.pressureToAltitude(seaLevelPressure,
|
||||
event.pressure));
|
||||
Serial.println(" m");
|
||||
Serial.println("");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Sensor error");
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
10
libraries/Adafruit_BMP085_Unified/library.properties
Normal file
10
libraries/Adafruit_BMP085_Unified/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=Adafruit BMP085 Unified
|
||||
version=1.1.3
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Unified sensor driver for Adafruit's BMP085 & BMP180 breakouts
|
||||
paragraph=Unified sensor driver for Adafruit's BMP085 & BMP180 breakouts
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_BMP085_Unified
|
||||
architectures=*
|
||||
depends=Adafruit Unified Sensor
|
||||
401
libraries/Adafruit_BMP183_Library/Adafruit_BMP183.cpp
Normal file
401
libraries/Adafruit_BMP183_Library/Adafruit_BMP183.cpp
Normal file
@@ -0,0 +1,401 @@
|
||||
/*!
|
||||
* @file Adafruit_BMP183.cpp
|
||||
*
|
||||
* @mainpage Adafruit BMP183 Library
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
* This is a library for the Adafruit BMP183 Barometric Pressure + Temp sensor
|
||||
*
|
||||
* Designed specifically to work with the Adafruit BMP183 Breakout
|
||||
* ----> http://www.adafruit.com/products/1900
|
||||
*
|
||||
* These sensors use SPI to communicate, 4 pins are required to
|
||||
* interface
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* BSD license, all text above must be included in any redistribution
|
||||
*/
|
||||
|
||||
#include "Adafruit_BMP183.h"
|
||||
#ifdef __AVR__
|
||||
#include <util/delay.h>
|
||||
#endif
|
||||
#define _delay_ms(t) \
|
||||
delay(t) //!< Delay for use in-between different lines/parts of code
|
||||
#include <SPI.h>
|
||||
|
||||
/*!
|
||||
* @brief Instantiates a new Adafruit_BMP183 class using hardware SPI
|
||||
* @param SPICS
|
||||
* cs pin
|
||||
* @param *theSPI
|
||||
* optional SPI object, defaults to SPI
|
||||
*/
|
||||
Adafruit_BMP183::Adafruit_BMP183(int8_t SPICS, SPIClass *theSPI) {
|
||||
_cs = SPICS;
|
||||
_clk = _miso = _mosi = -1;
|
||||
_spi = theSPI;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Instantiates a new Adafruit_BMP183 class using software SPI
|
||||
* @param SPICLK
|
||||
* SPI chip clock
|
||||
* @param SPIMISO
|
||||
* SPI MISO (Data to microcontroller from sensor)
|
||||
* @param SPIMOSI
|
||||
* SPI MOSI (Data from microcontroller to sensor)
|
||||
* @param SPICS
|
||||
* SPI CS PIN
|
||||
*/
|
||||
Adafruit_BMP183::Adafruit_BMP183(int8_t SPICLK, int8_t SPIMISO, int8_t SPIMOSI,
|
||||
int8_t SPICS) {
|
||||
_cs = SPICS;
|
||||
_clk = SPICLK;
|
||||
_miso = SPIMISO;
|
||||
_mosi = SPIMOSI;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Setups the HW
|
||||
* @param mode
|
||||
* selected BMP183 mode
|
||||
* @return true if successful
|
||||
*/
|
||||
boolean Adafruit_BMP183::begin(bmp183_mode_t mode) {
|
||||
if (_clk == -1) {
|
||||
_spi->begin();
|
||||
_spi->setDataMode(SPI_MODE0);
|
||||
#ifdef __AVR__
|
||||
_spi->setClockDivider(SPI_CLOCK_DIV16);
|
||||
#endif
|
||||
#ifdef __SAM3X8E__
|
||||
_spi->setClockDivider(11); // 8-ish MHz (full! speed!)
|
||||
#endif
|
||||
} else {
|
||||
pinMode(_clk, OUTPUT);
|
||||
digitalWrite(_clk, HIGH);
|
||||
pinMode(_mosi, OUTPUT);
|
||||
digitalWrite(_mosi, HIGH);
|
||||
pinMode(_miso, INPUT);
|
||||
}
|
||||
pinMode(_cs, OUTPUT);
|
||||
digitalWrite(_cs, HIGH);
|
||||
|
||||
/* Mode boundary check */
|
||||
if ((mode > BMP183_MODE_ULTRAHIGHRES) || (mode < 0)) {
|
||||
mode = BMP183_MODE_ULTRAHIGHRES;
|
||||
}
|
||||
|
||||
/* Set the mode indicator */
|
||||
oversampling = mode;
|
||||
|
||||
if (read8(0xD0) != 0x55)
|
||||
return false;
|
||||
|
||||
/* Read calibration data */
|
||||
ac1 = read16(BMP183_REGISTER_CAL_AC1);
|
||||
ac2 = read16(BMP183_REGISTER_CAL_AC2);
|
||||
ac3 = read16(BMP183_REGISTER_CAL_AC3);
|
||||
ac4 = read16(BMP183_REGISTER_CAL_AC4);
|
||||
ac5 = read16(BMP183_REGISTER_CAL_AC5);
|
||||
ac6 = read16(BMP183_REGISTER_CAL_AC6);
|
||||
|
||||
b1 = read16(BMP183_REGISTER_CAL_B1);
|
||||
b2 = read16(BMP183_REGISTER_CAL_B2);
|
||||
|
||||
mb = read16(BMP183_REGISTER_CAL_MB);
|
||||
mc = read16(BMP183_REGISTER_CAL_MC);
|
||||
md = read16(BMP183_REGISTER_CAL_MD);
|
||||
#if (BMP183_DEBUG == 1)
|
||||
Serial.print("ac1 = ");
|
||||
Serial.println(ac1, DEC);
|
||||
Serial.print("ac2 = ");
|
||||
Serial.println(ac2, DEC);
|
||||
Serial.print("ac3 = ");
|
||||
Serial.println(ac3, DEC);
|
||||
Serial.print("ac4 = ");
|
||||
Serial.println(ac4, DEC);
|
||||
Serial.print("ac5 = ");
|
||||
Serial.println(ac5, DEC);
|
||||
Serial.print("ac6 = ");
|
||||
Serial.println(ac6, DEC);
|
||||
|
||||
Serial.print("b1 = ");
|
||||
Serial.println(b1, DEC);
|
||||
Serial.print("b2 = ");
|
||||
Serial.println(b2, DEC);
|
||||
|
||||
Serial.print("mb = ");
|
||||
Serial.println(mb, DEC);
|
||||
Serial.print("mc = ");
|
||||
Serial.println(mc, DEC);
|
||||
Serial.print("md = ");
|
||||
Serial.println(md, DEC);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads raw temperature reading
|
||||
* @return Raw Temeperature from BMP183_REGISTER_TEMPDATA.
|
||||
*/
|
||||
uint16_t Adafruit_BMP183::readRawTemperature() {
|
||||
write8(BMP183_REGISTER_CONTROL, BMP183_REGISTER_READTEMPCMD);
|
||||
_delay_ms(5);
|
||||
#if BMP183_DEBUG == 1
|
||||
Serial.print("Raw temp: ");
|
||||
Serial.println(read16(BMP183_REGISTER_TEMPDATA));
|
||||
#endif
|
||||
return read16(BMP183_REGISTER_TEMPDATA);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads raw pressure reading
|
||||
* @return Raw Pressure from BMP183_REGISTER_PRESSUREDATA
|
||||
*/
|
||||
uint32_t Adafruit_BMP183::readRawPressure() {
|
||||
uint32_t raw;
|
||||
|
||||
write8(BMP183_REGISTER_CONTROL,
|
||||
BMP183_REGISTER_READPRESSURECMD + (oversampling << 6));
|
||||
|
||||
if (oversampling == BMP183_MODE_ULTRALOWPOWER)
|
||||
_delay_ms(5);
|
||||
else if (oversampling == BMP183_MODE_STANDARD)
|
||||
_delay_ms(8);
|
||||
else if (oversampling == BMP183_MODE_HIGHRES)
|
||||
_delay_ms(14);
|
||||
else
|
||||
_delay_ms(26);
|
||||
|
||||
raw = read16(BMP183_REGISTER_PRESSUREDATA);
|
||||
|
||||
raw <<= 8;
|
||||
raw |= read8(BMP183_REGISTER_PRESSUREDATA + 2);
|
||||
raw >>= (8 - oversampling);
|
||||
|
||||
/* this pull broke stuff, look at it later?
|
||||
if (oversampling==0) {
|
||||
raw <<= 8;
|
||||
raw |= read8(BMP183_PRESSUREDATA+2);
|
||||
raw >>= (8 - oversampling);
|
||||
}
|
||||
*/
|
||||
|
||||
#if BMP183_DEBUG == 1
|
||||
Serial.print("Raw pressure: ");
|
||||
Serial.println(raw);
|
||||
#endif
|
||||
return raw;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Gets the compensated pressure level in hPa
|
||||
* @return Pressure value in hPa
|
||||
*/
|
||||
int32_t Adafruit_BMP183::getPressure() {
|
||||
int32_t UT, UP, B3, B5, B6, X1, X2, X3, p;
|
||||
uint32_t B4, B7;
|
||||
|
||||
UT = readRawTemperature();
|
||||
UP = readRawPressure();
|
||||
|
||||
#if BMP183_DEBUG == 1
|
||||
// use datasheet numbers!
|
||||
UT = 27898;
|
||||
UP = 23843;
|
||||
ac6 = 23153;
|
||||
ac5 = 32757;
|
||||
mc = -8711;
|
||||
md = 2868;
|
||||
b1 = 6190;
|
||||
b2 = 4;
|
||||
ac3 = -14383;
|
||||
ac2 = -72;
|
||||
ac1 = 408;
|
||||
ac4 = 32741;
|
||||
oversampling = 0;
|
||||
#endif
|
||||
|
||||
// do temperature calculations
|
||||
X1 = (UT - (int32_t)(ac6)) * ((int32_t)(ac5)) / pow(2, 15);
|
||||
X2 = ((int32_t)mc * pow(2, 11)) / (X1 + (int32_t)md);
|
||||
B5 = X1 + X2;
|
||||
|
||||
#if BMP183_DEBUG == 1
|
||||
Serial.print("X1 = ");
|
||||
Serial.println(X1);
|
||||
Serial.print("X2 = ");
|
||||
Serial.println(X2);
|
||||
Serial.print("B5 = ");
|
||||
Serial.println(B5);
|
||||
#endif
|
||||
|
||||
// do pressure calcs
|
||||
B6 = B5 - 4000;
|
||||
X1 = ((int32_t)b2 * ((B6 * B6) >> 12)) >> 11;
|
||||
X2 = ((int32_t)ac2 * B6) >> 11;
|
||||
X3 = X1 + X2;
|
||||
B3 = ((((int32_t)ac1 * 4 + X3) << oversampling) + 2) / 4;
|
||||
|
||||
#if BMP183_DEBUG == 1
|
||||
Serial.print("B6 = ");
|
||||
Serial.println(B6);
|
||||
Serial.print("X1 = ");
|
||||
Serial.println(X1);
|
||||
Serial.print("X2 = ");
|
||||
Serial.println(X2);
|
||||
Serial.print("B3 = ");
|
||||
Serial.println(B3);
|
||||
#endif
|
||||
|
||||
X1 = ((int32_t)ac3 * B6) >> 13;
|
||||
X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16;
|
||||
X3 = ((X1 + X2) + 2) >> 2;
|
||||
B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15;
|
||||
B7 = ((uint32_t)UP - B3) * (uint32_t)(50000UL >> oversampling);
|
||||
|
||||
#if BMP183_DEBUG == 1
|
||||
Serial.print("X1 = ");
|
||||
Serial.println(X1);
|
||||
Serial.print("X2 = ");
|
||||
Serial.println(X2);
|
||||
Serial.print("B4 = ");
|
||||
Serial.println(B4);
|
||||
Serial.print("B7 = ");
|
||||
Serial.println(B7);
|
||||
#endif
|
||||
|
||||
if (B7 < 0x80000000) {
|
||||
p = (B7 * 2) / B4;
|
||||
} else {
|
||||
p = (B7 / B4) * 2;
|
||||
}
|
||||
X1 = (p >> 8) * (p >> 8);
|
||||
X1 = (X1 * 3038) >> 16;
|
||||
X2 = (-7357 * p) >> 16;
|
||||
|
||||
#if BMP183_DEBUG == 1
|
||||
Serial.print("p = ");
|
||||
Serial.println(p);
|
||||
Serial.print("X1 = ");
|
||||
Serial.println(X1);
|
||||
Serial.print("X2 = ");
|
||||
Serial.println(X2);
|
||||
#endif
|
||||
|
||||
p = p + ((X1 + X2 + (int32_t)3791) >> 4);
|
||||
#if BMP183_DEBUG == 1
|
||||
Serial.print("p = ");
|
||||
Serial.println(p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads the temperatures in Celsius degrees
|
||||
* @return temperature in Celsius
|
||||
*/
|
||||
float Adafruit_BMP183::getTemperature() {
|
||||
int32_t UT, X1, X2, B5; // following ds convention
|
||||
float temp;
|
||||
|
||||
UT = readRawTemperature();
|
||||
|
||||
#if BMP183_DEBUG == 1
|
||||
// use datasheet numbers!
|
||||
UT = 27898;
|
||||
ac6 = 23153;
|
||||
ac5 = 32757;
|
||||
mc = -8711;
|
||||
md = 2868;
|
||||
#endif
|
||||
|
||||
// step 1
|
||||
X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) / pow(2, 15);
|
||||
X2 = ((int32_t)mc * pow(2, 11)) / (X1 + (int32_t)md);
|
||||
B5 = X1 + X2;
|
||||
temp = (B5 + 8) / pow(2, 4);
|
||||
temp /= 10;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Reads the altitude based on provided sea level pressure
|
||||
* @param sealevelPressure
|
||||
* pressure in hPa
|
||||
* @return altitude value in meters
|
||||
*/
|
||||
float Adafruit_BMP183::getAltitude(float sealevelPressure) {
|
||||
float altitude;
|
||||
|
||||
float pressure = getPressure(); // in Si units for Pascal
|
||||
pressure /= 100;
|
||||
|
||||
altitude = 44330 * (1.0 - pow(pressure / sealevelPressure, 0.1903));
|
||||
|
||||
return altitude;
|
||||
}
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
uint8_t Adafruit_BMP183::SPIxfer(uint8_t x) {
|
||||
if (_clk == -1) {
|
||||
return _spi->transfer(x);
|
||||
} else {
|
||||
// Serial.println("Software SPI");
|
||||
uint8_t reply = 0;
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
reply <<= 1;
|
||||
digitalWrite(_clk, LOW);
|
||||
digitalWrite(_mosi, x & (1 << i));
|
||||
digitalWrite(_clk, HIGH);
|
||||
if (digitalRead(_miso))
|
||||
reply |= 1;
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Adafruit_BMP183::read8(uint8_t reg) {
|
||||
uint8_t value;
|
||||
|
||||
digitalWrite(_cs, LOW);
|
||||
SPIxfer(0x80 | reg);
|
||||
value = SPIxfer(0x00);
|
||||
digitalWrite(_cs, HIGH);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
uint16_t Adafruit_BMP183::read16(uint8_t reg) {
|
||||
uint16_t value;
|
||||
|
||||
digitalWrite(_cs, LOW);
|
||||
SPIxfer(0x80 | reg);
|
||||
value = SPIxfer(0x00);
|
||||
value <<= 8;
|
||||
value |= SPIxfer(0x00);
|
||||
digitalWrite(_cs, HIGH);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void Adafruit_BMP183::write8(uint8_t reg, uint8_t value) {
|
||||
digitalWrite(_cs, LOW);
|
||||
SPIxfer(reg & 0x7F);
|
||||
SPIxfer(value);
|
||||
digitalWrite(_cs, HIGH);
|
||||
}
|
||||
77
libraries/Adafruit_BMP183_Library/Adafruit_BMP183.h
Normal file
77
libraries/Adafruit_BMP183_Library/Adafruit_BMP183.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*!
|
||||
* @file Adafruit_BMP183.h
|
||||
*/
|
||||
|
||||
#ifndef ADAFRUIT_BMP183_H
|
||||
#define ADAFRUIT_BMP183_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SPI.h"
|
||||
|
||||
// use the 'default' datasheet numbers to test calculations
|
||||
#define BMP183_DEBUG 0 //!< Enables or disables debug mode
|
||||
|
||||
/** Registers **/
|
||||
enum {
|
||||
BMP183_REGISTER_CAL_AC1 = 0xAA, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_AC2 = 0xAC, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_AC3 = 0xAE, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_AC4 = 0xB0, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_AC5 = 0xB2, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_AC6 = 0xB4, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_B1 = 0xB6, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_B2 = 0xB8, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_MB = 0xBA, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_MC = 0xBC, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CAL_MD = 0xBE, // R Calibration data (16 bits)
|
||||
BMP183_REGISTER_CHIPID = 0xD0,
|
||||
BMP183_REGISTER_VERSION = 0xD1,
|
||||
BMP183_REGISTER_SOFTRESET = 0xE0,
|
||||
BMP183_REGISTER_CONTROL = 0xF4,
|
||||
BMP183_REGISTER_TEMPDATA = 0xF6,
|
||||
BMP183_REGISTER_PRESSUREDATA = 0xF6,
|
||||
BMP183_REGISTER_READTEMPCMD = 0x2E,
|
||||
BMP183_REGISTER_READPRESSURECMD = 0x34
|
||||
};
|
||||
|
||||
/** Mode Settings **/
|
||||
typedef enum {
|
||||
BMP183_MODE_ULTRALOWPOWER = 0,
|
||||
BMP183_MODE_STANDARD = 1,
|
||||
BMP183_MODE_HIGHRES = 2,
|
||||
BMP183_MODE_ULTRAHIGHRES = 3
|
||||
} bmp183_mode_t;
|
||||
|
||||
/*!
|
||||
* @brief Class that stores state and functions for interacting with
|
||||
* BMP183
|
||||
*/
|
||||
class Adafruit_BMP183 {
|
||||
public:
|
||||
Adafruit_BMP183(int8_t SPICS, SPIClass *theSPI = &SPI);
|
||||
Adafruit_BMP183(int8_t SPICLK, int8_t SPIMISO, int8_t SPIMOSI, int8_t SPICS);
|
||||
|
||||
boolean
|
||||
begin(bmp183_mode_t mode = BMP183_MODE_ULTRAHIGHRES); // by default go highres
|
||||
float getTemperature();
|
||||
int32_t getPressure();
|
||||
float getAltitude(float sealevelPressure = 101325); // std atmosphere
|
||||
uint16_t readRawTemperature();
|
||||
uint32_t readRawPressure();
|
||||
SPIClass *_spi; //!< pointer to SPI object
|
||||
|
||||
private:
|
||||
uint8_t SPIxfer(uint8_t x);
|
||||
uint8_t read8(uint8_t addr);
|
||||
uint16_t read16(uint8_t addr);
|
||||
void write8(uint8_t addr, uint8_t data);
|
||||
|
||||
int8_t _cs, _clk, _miso, _mosi;
|
||||
|
||||
uint8_t oversampling;
|
||||
|
||||
int16_t ac1, ac2, ac3, b1, b2, mb, mc, md;
|
||||
uint16_t ac4, ac5, ac6;
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_BMP183_H
|
||||
23
libraries/Adafruit_BMP183_Library/README.md
Normal file
23
libraries/Adafruit_BMP183_Library/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Adafruit BMP183 [](https://github.com/adafruit/Adafruit_BMP183_Library/actions)[](http://adafruit.github.io/Adafruit_BMP183_Library/html/index.html)
|
||||
|
||||
|
||||
This is a library for the Adafruit BMP183 Barometric Pressure + Temp sensor
|
||||
|
||||
<a href="https://www.adafruit.com/products/1900"><img src="assets/board.jpg" height="300"/></a>
|
||||
|
||||
Pick one up today in the adafruit shop!
|
||||
* https://www.adafruit.com/products/1900
|
||||
|
||||
These Sensors use SPI to communicate, 4 pins are required to interface
|
||||
|
||||
To install, use the Arduino Library Manager and search for "Adafruit BMP183" and install the library.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Check out the links above for our tutorials and wiring diagrams
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
All text above must be included in any redistribution
|
||||
BIN
libraries/Adafruit_BMP183_Library/assets/board.jpg
Normal file
BIN
libraries/Adafruit_BMP183_Library/assets/board.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 394 KiB |
@@ -0,0 +1,92 @@
|
||||
#include <SPI.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BMP183.h>
|
||||
|
||||
// For hardware SPI:
|
||||
// Connect SCK to SPI Clock, SDO to SPI MISO, and SDI to SPI MOSI
|
||||
// See http://arduino.cc/en/Reference/SPI for your Arduino's SPI pins!
|
||||
// On UNO, Clock is #13, SDO/MISO is #12 and SDI/MOSI is #11
|
||||
|
||||
// You can also use software SPI and define your own pins!
|
||||
#define BMP183_CLK 13
|
||||
#define BMP183_SDO 12 // AKA MISO
|
||||
#define BMP183_SDI 11 // AKA MOSI
|
||||
|
||||
// You'll also need a chip-select pin, use any pin!
|
||||
#define BMP183_CS 10
|
||||
|
||||
// initialize with hardware SPI
|
||||
//Adafruit_BMP183 bmp = Adafruit_BMP183(BMP183_CS);
|
||||
// or initialize with software SPI and use any 4 pins
|
||||
Adafruit_BMP183 bmp = Adafruit_BMP183(BMP183_CLK, BMP183_SDO, BMP183_SDI, BMP183_CS);
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino setup function (automatically called at startup)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("BMP183 Pressure Sensor Test"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!bmp.begin())
|
||||
{
|
||||
/* There was a problem detecting the BMP183 ... check your connections */
|
||||
Serial.print("Ooops, no BMP183 detected ... Check your wiring!");
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino loop function, called once 'setup' is complete (your own code
|
||||
should go here)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop(void)
|
||||
{
|
||||
/* Display atmospheric pressue in Pascals */
|
||||
Serial.print("Pressure: ");
|
||||
Serial.print(bmp.getPressure());
|
||||
Serial.print(" Pascals / ");
|
||||
Serial.print(bmp.getPressure() / 100);
|
||||
Serial.println(" millibar (hPa)");
|
||||
|
||||
/* First we get the current temperature from the BMP085 */
|
||||
float temperature;
|
||||
temperature = bmp.getTemperature();
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(temperature);
|
||||
Serial.println(" C");
|
||||
|
||||
/* Calculating altitude with reasonable accuracy requires pressure *
|
||||
* sea level pressure for your position at the moment the data is *
|
||||
* converted. If you don't have these values, a 'generic' value of *
|
||||
* 1013.25 mbar can be used (defined as SENSORS_PRESSURE_SEALEVELHPA *
|
||||
* in sensors.h), but this isn't ideal and will give variable *
|
||||
* results from one day to the next. *
|
||||
* *
|
||||
* You can usually find the current SLP value by looking at weather *
|
||||
* websites or from environmental information centers near any major *
|
||||
* airport. *
|
||||
* *
|
||||
* For example, for Paris, France you can check the current mean *
|
||||
* pressure and sea level at: http://bit.ly/16Au8ol */
|
||||
|
||||
|
||||
/* Then convert the atmospheric pressure, SLP and temp to altitude */
|
||||
/* Update this next line with the current SLP for better results */
|
||||
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA; // should be ~1000
|
||||
Serial.print("Sea level pressure: ");
|
||||
Serial.print(SENSORS_PRESSURE_SEALEVELHPA);
|
||||
Serial.println(" millibar/hPa");
|
||||
|
||||
Serial.print("Altitude: ");
|
||||
Serial.print(bmp.getAltitude(seaLevelPressure));
|
||||
Serial.println(" m");
|
||||
Serial.println("");
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
7
libraries/Adafruit_BMP183_Library/keywords.txt
Normal file
7
libraries/Adafruit_BMP183_Library/keywords.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Adafruit_BMP183 KEYWORD1
|
||||
begin KEYWORD2
|
||||
getTemperature KEYWORD2
|
||||
getPressure KEYWORD2
|
||||
getAltitude KEYWORD2
|
||||
readRawTemperature KEYWORD2
|
||||
readRawPressure KEYWORD2
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user