//**********************************
//* BMP085 and BMP180 version *
//**********************************
// This is the Poor Mans Vario code for the cheaper BMP085 and the BMP180 sensor by BOSCH Sensortec
// Arduino <> Sensor: Connect VCC to VCC and GND to GND, SCL goes to analogue pin 5, SDA to analogue pin4.
// Servo signal input, connect to Arduino pin D3
// Audio output to transmitter on pin D2
// All code by Rolf R Bakke, Oct 2012
// Modified by Hans Meijdam, June 2013: added altitude feature
// Modified by Hans Meijdam, November 2013: Sensor routine created for BMP085 and BMP180.
// Modified by Hans Meijdam, July 2014: BETA Version
// - Switch to select if whole meters are called out if below 100 meters altitude
// - Deadband to make vario silent if no certain climb or sink level is achieved
// - Negative altitude becomes now indicated as if it was positive altitude
// Modified by Ludger Kuhnen, January 2020
// - Deadband adjustable via 2nd Receiver-channel ( input D6 1000 - 2000µs sets 0 to 300 deadband )
// ****** This is a customizable variable that acts as a switch *****
// choose "1" if you also want to hear the altitude in meters if you fly below 100 meters.
// choose "0" if you only want to hear the 10 meters rounded altitude at all times.
// Default is 0.
//const byte altitude_per_meter = 0; // only altitude in 10 meters
const byte altitude_per_meter = 1; // altitude in whole meters if below 100 meters
// ****** This is a customizable variable (0 - 300 range) that defines how large the dead band is ******
// A dead band of "0" (= default) means that the vario will beep constantly, even with no climb or sink at all.
// A small dead band (e.g. value 25 - 50) means that with a small amount of climb or sink the vario will start beeping
// A medium dead band (e.g. value 50 - 100) means that the vario will be silent, unless it observes a medium rate of climb or medium rate of sink.
// A high dead band (> 100) makes the vario only active at high rates of sink or climb.
int deadband = 0; // no deadband or deadband defined by RC-channel
// int deadband = 25; // small deadband
// int deadband = 75; // medium deadband
// int deadband = 150; // large deadband
// ****** Alternatively the deadband can be dynamically set by connecting a 10K potmeter over pins 12, A1 (rocker) and A2 ******
//const byte deadbandchannel = 0; // no deadband potmeter present
const char deadbandchannel = 1; // deadband channel is present (on digital INPUT D6)
#include "Wire.h"
const byte led = 13;
unsigned long time = 0;
float toneFreq, toneFreqLowpass, flpressure, lowpassFast, lowpassSlow ;
float p0; // this will be used to store the airfield elevation pressure
int altitude;
int ch1; // Here's where we'll keep our channel values
int ch2; // Value for deadband by 2nd channel of TX, preferred by rc-channel, instead of switch
int ddsAcc;
#define I2C_ADDRESS 0x77
const unsigned char oversampling_setting = 3; //oversamplig for measurement
const unsigned char pressure_waittime[4] = {
5, 8, 14, 26
};
//Sensor parameters taken from the BMP085 datasheet
int ac1, ac2, ac3;
unsigned int ac4, ac5, ac6;
int b1, b2, mb, mc, md;
int temperature;
long pressure;
int analogpin1 = 0;
void setup()
{
Serial.begin(9600); // start serial for output
analogpin1 = analogRead(1); // read the input pin A1 potmeter value
//Serial.print("Analog pin A0 value: ");
//Serial.println(analogpin1);
//Serial.println("Setting up BMP085");
Wire.begin();
bmp085_get_cal_data();
bmp085_read_temperature_and_pressure(&temperature, &pressure);
flpressure = pressure; // move long type pressure into float type flpressure
p0 = lowpassFast = lowpassSlow = flpressure;
//Serial.print(" p0 = ");
//Serial.println(p0);
pinMode(3, INPUT); // Set our input pins as such for altitude command input from receiver via pin D3
pinMode(6, INPUT); //Input for RC-Channel to set (change ) deadband during flight
}
void loop()
{
bmp085_read_temperature_and_pressure(&temperature, &pressure);
float t = temperature / 10.0;
//Serial.println(t,1);
//Serial.println(" ");
float p = flpressure / 100;
//Serial.println(p,2);
// Serial.print(" ");
//Serial.println(deadband);
//Serial.println(ch1);
flpressure = pressure;// move long type pressure into float type flpressure
altitude = (float)44330 * (1 - pow(((float) flpressure / p0), 0.190295));
//Serial.print(" ");
//Serial.println(altitude);
altitude = abs(altitude); // if flying from hills negative altitude becomes indicated as positive
lowpassFast = lowpassFast + (flpressure - lowpassFast) * 0.2;
lowpassSlow = lowpassSlow + (flpressure - lowpassSlow) * 0.1;
toneFreq = (lowpassSlow - lowpassFast) * 50;
toneFreqLowpass = toneFreqLowpass + (toneFreq - toneFreqLowpass) * 0.1;
toneFreq = constrain(toneFreqLowpass, -500, 500);
ddsAcc += toneFreq * 100 + 2000;
if (deadbandchannel == 1)
{
int ch2 = pulseIn(6, HIGH, 25000);
if (ch2 < 1000) {
ch2 = 1000; //otherwise over-value gives sensless results!
}
if (ch2 > 2000) {
ch2 = 2000; //otherwise over-value gives sensless results!
}
deadband = (map(ch2, 1000, 2000, 0, 300));
}
if (toneFreq < 0 || ddsAcc > 0)
{
if (abs(toneFreq) > deadband)
{
tone(2, toneFreq + 550);
ledOn(); // the Arduino led will blink if the Vario plays a tone, so you can test without having audio connected
}
}
else
{
noTone(2);
ledOff();
}
while (millis() < time); //loop frequency timer
time += 20;
int ones = altitude % 10;
int tens = (altitude / 10) % 10;
int hundreds = (altitude / 100) % 10;
int thousands = (altitude / 1000) % 10;
ch1 = pulseIn(3, HIGH, 25000); // Read the pulse width of servo signal connected to pin D3
// Serial.print (ch1);
//
// if(ch1>1000){
// Serial.println("Left Switch: Engaged");
// }
// if(ch1<1000){
// Serial.println("Left Switch: Disengaged");
// }
if ((map(ch1, 1000, 2000, -500, 500)) > 0) // interpret the servo channel pulse, if the Vario should beep altitude or send vario sound
{
noTone(2); // create 750 ms of silence, or you won't hear the first altitude beep
ledOff();
delay(750);
if (hundreds == 0)
{
tone(2, 900); //long duration tone if the number is zero
ledOn();
delay(600);
noTone(2);
ledOff();
}
else
for (char a = 0; a < hundreds; a++) //this loop makes a beep for each hundred meters altitude
{
tone(2, 900); // 900 Hz tone frequency for the hundreds
ledOn();
delay(200);
noTone(2);
ledOff();
delay(200);
}
delay(750); //longer delay between hundreds and tens
if (tens == 0)
{
tone(2, 1100); //long pulse if the number is zero
ledOn();
delay(600);
noTone(2);
ledOff();
}
else
for (char a = 0; a < tens; a++) //this loop makes a beep for each ten meters altitude
{
tone(2, 1100); //1100 Hz tone frequency for the tens
ledOn();
delay(200);
noTone(2);
ledOff();
delay(200);
}
if (altitude_per_meter == 1 && hundreds == 0)
{
delay(750); //longer delay between tens and ones
if (ones == 0)
{
tone(2, 1300); //long pulse if the number is zero
ledOn();
delay(600);
noTone(2);
ledOff();
}
else
for (char a = 0; a < ones; a++) //this loop makes a beep for each meter altitude
{
tone(2, 1300); //1300 Hz tone frequency for the ones
ledOn();
delay(200);
noTone(2);
ledOff();
delay(200);
}
}
}
}
void bmp085_read_temperature_and_pressure(int* temperature, long* pressure) {
int ut = bmp085_read_ut();
long up = bmp085_read_up();
long x1, x2, x3, b3, b5, b6, p;
unsigned long b4, b7;
//calculate the temperature
x1 = ((long)ut - ac6) * ac5 >> 15;
x2 = ((long) mc << 11) / (x1 + md);
b5 = x1 + x2;
*temperature = (b5 + 8) >> 4;
//calculate the pressure
b6 = b5 - 4000;
x1 = (b2 * (b6 * b6 >> 12)) >> 11;
x2 = ac2 * b6 >> 11;
x3 = x1 + x2;
if (oversampling_setting == 3) b3 = ((int32_t) ac1 * 4 + x3 + 2) << 1;
if (oversampling_setting == 2) b3 = ((int32_t) ac1 * 4 + x3 + 2);
if (oversampling_setting == 1) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 1;
if (oversampling_setting == 0) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 2;
x1 = ac3 * b6 >> 13;
x2 = (b1 * (b6 * b6 >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;
b7 = ((uint32_t) up - b3) * (50000 >> oversampling_setting);
p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
*pressure = p + ((x1 + x2 + 3791) >> 4);
}
unsigned int bmp085_read_ut() {
write_register(0xf4, 0x2e);
delay(5); //longer than 4.5 ms
return read_int_register(0xf6);
}
void bmp085_get_cal_data() {
// Serial.println("Reading Calibration Data");
ac1 = read_int_register(0xAA);
// Serial.print("AC1: ");
// Serial.println(ac1,DEC);
ac2 = read_int_register(0xAC);
// Serial.print("AC2: ");
// Serial.println(ac2,DEC);
ac3 = read_int_register(0xAE);
// Serial.print("AC3: ");
// Serial.println(ac3,DEC);
ac4 = read_int_register(0xB0);
// Serial.print("AC4: ");
// Serial.println(ac4,DEC);
ac5 = read_int_register(0xB2);
// Serial.print("AC5: ");
// Serial.println(ac5,DEC);
ac6 = read_int_register(0xB4);
// Serial.print("AC6: ");
// Serial.println(ac6,DEC);
b1 = read_int_register(0xB6);
// Serial.print("B1: ");
// Serial.println(b1,DEC);
b2 = read_int_register(0xB8);
// Serial.print("B2: ");
// Serial.println(b2,DEC);
mb = read_int_register(0xBA);
// Serial.print("MB: ");
// Serial.println(mb,DEC);
mc = read_int_register(0xBC);
// Serial.print("MC: ");
// Serial.println(mc,DEC);
md = read_int_register(0xBE);
// Serial.print("MD: ");
// Serial.println(md,DEC);
}
long bmp085_read_up() {
write_register(0xf4, 0x34 + (oversampling_setting << 6));
delay(pressure_waittime[oversampling_setting]);
unsigned char msb, lsb, xlsb;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(0xf6); // register to read
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 3); // read a byte
while (!Wire.available()) {
// waiting
}
msb = Wire.read();
while (!Wire.available()) {
// waiting
}
lsb |= Wire.read();
while (!Wire.available()) {
// waiting
}
xlsb |= Wire.read();
return (((long)msb << 16) | ((long)lsb << 8) | ((long)xlsb)) >> (8 - oversampling_setting);
}
void write_register(unsigned char r, unsigned char v)
{
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r);
Wire.write(v);
Wire.endTransmission();
}
char read_register(unsigned char r)
{
unsigned char v;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r); // register to read
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 1); // read a byte
while (!Wire.available()) {
// waiting
}
v = Wire.read();
return v;
}
int read_int_register(unsigned char r)
{
unsigned char msb, lsb;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r); // register to read
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 2); // read a byte
while (!Wire.available()) {
// waiting
}
msb = Wire.read();
while (!Wire.available()) {
// waiting
}
lsb = Wire.read();
return (((int)msb << 8) | ((int)lsb));
}
void ledOn()
{
digitalWrite(led, 1);
}
void ledOff()
{
digitalWrite(led, 0);
}