making a weather station

Hello all,

I'm making a portable weather station that communicates via bluetooth.

bluetooth: http://www.sparkfun.com/products/158 thermistor: http://www.sparkfun.com/products/250 humidity: http://www.sparkfun.com/products/9569 barometer: http://www.sparkfun.com/products/9694 arduino 2560: http://www.sparkfun.com/products/9949

The thermistor and humidity are analog voltage, but the barometer is an I2C connection, which I don't quite understand yet. (But i found this: http://mitat.tuu.fi/?p=78 links to http://sensorapp.net/?p=278 and broken down and described at http://interactive-matter.eu/2009/12/arduino-barometric-pressure-sensor-bmp085/)

Once I get this working on the 2560, I'd like to hardwire it on a lilypad, pro, or other similar small-scale board.

The bluetooth will be sending the results to my phone via amarino preferably.

What do I need to do in setup(), how do I read the I2C from the barometric pressure, and how do I write out to the phone over bluetooth?

Also, since the Baro is a 3.3V board, I need a logic Level Convertor? Like this -> http://www.sparkfun.com/products/8745

How do those work/how are they wired in?

Many Thanks, Steve

Here's the pseudo in my mind:

function temperature(){

thermVal = analogRead(thermistor)
thermVal = thermVal * 5 / 1023;
thermVal = thermVal/((5 - thermVal)/10000);
tempK = 1 / ((.003354016)+(.0002569850(log(thermVal/10000)))+(.000002620131(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));
return tempK

}

function humidity(){

humidityVal = analogRead(humidity)
(humidityVal - 0.8) / 0.03 = relHumid
return relHumid

}

function gamma(tempC,Humidity){

gammavalue = ((17.271 * tempC) / (237.7 + tempC)) + ln(humidity/100)
return gammavalue

}

function baroPres(){

baroVal = ....barometer input of I2C

}

function vapor(dewpoint){

pow = (7.5 * dewpoint) / (237.7 + dewpoint);
vaporPres = 6.11 * pow(10,pow);

}

function virTemp(millibar,vapor,tempK){

denom = ((1 - (vapor / millibar)) * (1-0.622));
virTemp = tempK / denom;
return virTemp;

}

function airDensity(inHg,virTemp){

inner = (17.326 * inHg) / virTemp;
middle = 1 - pow(inner,0.235);
density = 145366 * middle;
return density;

}

unsigned long currentMillis = millis();

if(currentMillis - previousMillis > interval) {

previousMillis = currentMillis; 

tempK = temperature();
tempC = tempK - 273.15;
tempF = (tempC * (9/5)) + 32;

humidity = humidity();

dewPoint = (237.7 * gamma(tempC,humidity)) / (17.271 - gamma(tempC,humidity));

baro_Millibar = baroPres();
baroInHg = baro_Millibar / 0.0295333727;

vaporPres = vapor(dewPoint);

virTemp = virTemp(baro_Millibar,vaporPres,tempK);

airDensity = airDensity(baroInHg,virTemp);

****
Send tempF, humidity, baroInHg, vaporPres, and airDensity to phone over bluetooth
**** 

}

Bildr seems to have a tutorial for that barometric sensor and some example code. http://bildr.org/2011/06/bmp085-arduino/

Good luck.

Pauly, thanks, I like that code better, it just seems easier to read.

Question: Because Arduino has an onboard 3.3V regualtor, could I connect the barometer sensor to the 3.3V line, instead of using a level converter? Or would that affect things downstream?

Also, I'd like to run this whole setup on solar panels- maybe not so much with the mega 2560, but once I have it on a lilypad, proboard, ect, I'd like to. I am figuring on using a solar trickle charger for a car, as I would imagine one in decent sunlight should be able to provide 500 ma or so, which should be enough for even the mega if I wanted to?

somethign like this: http://www.amazon.com/Sunforce-50013-Motorcycle-Powersports-Battery/dp/B001D6GYLO

It says rated at 1 watt, which would be 1/12 amps- 125ma. I don't think that would be enough for the mega, but maybe when I put it on a smaller board...?

I have powered an XBEE directly from the 3.3 V line with no issues. I would try that first before getting into a regulator. That seems like a decent solar panel but for a 12 volt battery. I would check out Adafruit.http://www.adafruit.com/products/390 They have a solar panel for about $25, the batteries and the regulators/chargers.

I made something almost exactly like the second photo, the one with the Minty Boost last year for recharging my cell phone and it works great.

Pauly: I have powered an XBEE directly from the 3.3 V line with no issues. I would try that first before getting into a regulator. That seems like a decent solar panel but for a 12 volt battery. I would check out Adafruit.http://www.adafruit.com/products/390 They have a solar panel for about $25, the batteries and the regulators/chargers.

I made something almost exactly like the second photo, the one with the Minty Boost last year for recharging my cell phone and it works great.

I thought arduino's spec input was 7-12VDC?

So I should be able to plug in the I2C barometer into the 3.3V port and it'll be ok? Or will I2C still be at 5 volts?

If arduino will take a 6V input, i figure 1 or 2 6V solar panels in parallel would be sufficient?

I added in the barometer reading stuff, and did some extra formatting/fixing.

Still have to insert how to send the information to my phone, replace “function” with the datatypes (I’m guessing floats for most?), and specify datatypes for the variables (again, floats?)

#include <Wire.h>

#define BMP085_ADDRESS 0x77  // I2C address of BMP085

const unsigned char OSS = 0;  // Oversampling Setting

// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;

// b5 is calculated in bmp085GetTemperature(...), this variable is also used in bmp085GetPressure(...)
// so ...Temperature(...) must be called before ...Pressure(...).
long b5; 

void setup(){

	Serial.begin(9600);
	Wire.begin();

	bmp085Calibration();

}

void loop(){

	unsigned long currentMillis = millis();

	if(currentMillis - previousMillis > interval) {

		previousMillis = currentMillis; 

		tempK = temperature();
		tempC = tempK - 273.15;
		tempF = (tempC * (9/5)) + 32;
		
		float temperatureC = bmp085GetTemperature(bmp085ReadUT()); //MUST be called first
		float temperatureK = temperatureC + 273.15;
		float temperatureF = (temperatureC * (9/5)) + 32;
		
		float avg_TemperatureF = (tempF + temperatureF) / 2;
		float avg_TemperatureC = (tempC + temperatureC) / 2;
		float avg_TemperatureK = (tempK + temperatureK) / 2;

		humidity = humidity();

		dewPoint = (237.7 * gamma(tempC,humidity)) / (17.271 - gamma(tempC,humidity)); //use Thermistor, Barometer Temp, or Avg?
		
  		float pascals = bmp085GetPressure(bmp085ReadUP()); // in pascals
  		float atm = pressure / 101325; // "standard atmosphere atms"
  		float baro_Millibars = pascals * 100;
  		float baro_inHg = baro_millibars * 33.86;
  		  		
  		float altitude = calcAltitude(pascals); //Uncompensated caculation - in Meters 

		vaporPres = vapor(dewPoint);

		virTemp = virTemp(baro_Millibars,vaporPres,tempK); //use Thermistor, Barometer Temp, or Avg?

		airDensity = airDensity(baro_InHg,virTemp);

		****
		Send tempF, temperature F, avg_TemperatureF, humidity, dewPoint, baro_InHg, altitude, vaporPres, and airDensity to phone over bluetooth
		**** 
	
	}

}


function temperature(){

	thermVal = analogRead(thermistorPin)
	thermVal = thermVal * 5 / 1023;
	thermVal = thermVal/((5 - thermVal)/10000);
	tempK = 1 / ((.003354016)+(.0002569850(log(thermVal/10000)))+(.000002620131(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));
	return tempK

}

function humidity(){

	humidityVal = analogRead(humidityPin)
	(humidityVal - 0.8) / 0.03 = relHumid
	return relHumid

}

function gamma(tempC,Humidity){

	gammavalue = ((17.271 * tempC) / (237.7 + tempC)) + ln(humidity/100)
	return gammavalue

}

// Stores all of the bmp085's calibration values into global variables
// Calibration values are required to calculate temp and pressure
// This function should be called at the beginning of the program
void bmp085Calibration()
{
  ac1 = bmp085ReadInt(0xAA);
  ac2 = bmp085ReadInt(0xAC);
  ac3 = bmp085ReadInt(0xAE);
  ac4 = bmp085ReadInt(0xB0);
  ac5 = bmp085ReadInt(0xB2);
  ac6 = bmp085ReadInt(0xB4);
  b1 = bmp085ReadInt(0xB6);
  b2 = bmp085ReadInt(0xB8);
  mb = bmp085ReadInt(0xBA);
  mc = bmp085ReadInt(0xBC);
  md = bmp085ReadInt(0xBE);
}

// Calculate temperature in deg C
float bmp085GetTemperature(unsigned int ut){
  long x1, x2;

  x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
  x2 = ((long)mc << 11)/(x1 + md);
  b5 = x1 + x2;

  float temp = ((b5 + 8)>>4);
  temp = temp /10;

  return temp;
}

// Calculate pressure given up
// calibration values must be known
// b5 is also required so bmp085GetTemperature(...) must be called first.
// Value returned will be pressure in units of Pa.
long bmp085GetPressure(unsigned long up){
  long x1, x2, x3, b3, b6, p;
  unsigned long b4, b7;

  b6 = b5 - 4000;
  // Calculate B3
  x1 = (b2 * (b6 * b6)>>12)>>11;
  x2 = (ac2 * b6)>>11;
  x3 = x1 + x2;
  b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;

  // Calculate B4
  x1 = (ac3 * b6)>>13;
  x2 = (b1 * ((b6 * b6)>>12))>>16;
  x3 = ((x1 + x2) + 2)>>2;
  b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;

  b7 = ((unsigned long)(up - b3) * (50000>>OSS));
  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;
  p += (x1 + x2 + 3791)>>4;

  long pascal = p;
  return pascal;
}

// Read 1 byte from the BMP085 at 'address'
char bmp085Read(unsigned char address)
{
  unsigned char data;

  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.send(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 1);
  while(!Wire.available())
    ;

  return Wire.receive();
}

// Read 2 bytes from the BMP085
// First byte will be from 'address'
// Second byte will be from 'address'+1
int bmp085ReadInt(unsigned char address)
{
  unsigned char msb, lsb;

  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.send(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 2);
  while(Wire.available()<2)
    ;
  msb = Wire.receive();
  lsb = Wire.receive();

  return (int) msb<<8 | lsb;
}

// Read the uncompensated temperature value
unsigned int bmp085ReadUT(){
  unsigned int ut;

  // Write 0x2E into Register 0xF4
  // This requests a temperature reading
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.send(0xF4);
  Wire.send(0x2E);
  Wire.endTransmission();

  // Wait at least 4.5ms
  delay(5);

  // Read two bytes from registers 0xF6 and 0xF7
  ut = bmp085ReadInt(0xF6);
  return ut;
}

// Read the uncompensated pressure value
unsigned long bmp085ReadUP(){

  unsigned char msb, lsb, xlsb;
  unsigned long up = 0;

  // Write 0x34+(OSS<<6) into register 0xF4
  // Request a pressure reading w/ oversampling setting
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.send(0xF4);
  Wire.send(0x34 + (OSS<<6));
  Wire.endTransmission();

  // Wait for conversion, delay time dependent on OSS
  delay(2 + (3<<OSS));

  // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
  msb = bmp085Read(0xF6);
  lsb = bmp085Read(0xF7);
  xlsb = bmp085Read(0xF8);

  up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);

  return up;
}

void writeRegister(int deviceAddress, byte address, byte val) {
    Wire.beginTransmission(deviceAddress); // start transmission to device 
    Wire.send(address);       // send register address
    Wire.send(val);         // send value to write
    Wire.endTransmission();     // end transmission
}

int readRegister(int deviceAddress, byte address){

    int v;
    Wire.beginTransmission(deviceAddress);
    Wire.send(address); // register to read
    Wire.endTransmission();

    Wire.requestFrom(deviceAddress, 1); // read a byte

    while(!Wire.available()) {
        // waiting
    }

    v = Wire.receive();
    return v;
}

float calcAltitude(float pressure){

  float A = pressure/101325;
  float B = 1/5.25588;
  float C = pow(A,B);
  C = 1 - C;
  C = C /0.0000225577;

  return C;
}

function vapor(dewpoint){

	pow = (7.5 * dewpoint) / (237.7 + dewpoint);
	vaporPres = 6.11 * pow(10,pow);

}

function virTemp(millibar,vapor,tempK){

	denom = ((1 - (vapor / millibar)) * (1-0.622));
	virTemp = tempK / denom;
	return virTemp;

}

function airDensity(inHg,virTemp){

	inner = (17.326 * inHg) / virTemp;
	middle = 1 - pow(inner,0.235);
	density = 145366 * middle;
	return density;

}

The Mega specs 6-18V for input. If you plug anything to the 3.3 v line it will be operating at 3.3 V. First I would find a battery that fits your needs, then I would find a solar panel that can recharge the battery. Another website to look at for batteries/ solar panels would be Volataic. http://www.voltaicsystems.com/

Pauly: The Mega specs 6-18V for input. If you plug anything to the 3.3 v line it will be operating at 3.3 V. First I would find a battery that fits your needs, then I would find a solar panel that can recharge the battery. Another website to look at for batteries/ solar panels would be Volataic. http://www.voltaicsystems.com/

In final build, however, I'd like to use an arduino pro-mini 5V, with a seperate 3.3V regulator for the barometer sensor, simply to make things small. IE, the solar panel(s) will be the biggest part, and ideally, will be completely seperate. The idea is to be able to hang the sensors (inside a project box without a lid) under our hauler in the shade, and have the solar panels exposed on a power line to send power to the sensors. I'd prefer to not have a battery at all, as then I would need a controller, ect. Seems easier to me to just have a solar panel feeding power directly to the system. The only time that wouldn't work is when we're racing at night, I don't know if the tungsten/halogen/whatever track lighting will be enough to get the necessary voltage and current out of the panel. At which point I could just piggyback a USB cord off my phone charger, which is plugged into the hauler's power system. That said, nothing says that I couldn't just run it permanently off said USB line, either..... hmm.

The reason I lean towards solar power, is that we also run a laptop and radio off an inverter, and actually killed the hauler's battery last weekend. So I'd like it to have a dedicated power input that would work even when we don't have any power, and also not have the problem of having to charge and deal with batteries. Thus solar came to mind.

The pro Mini would allow me to use a 6V solar panel, like this -> http://www.adafruit.com/products/200 or http://www.adafruit.com/products/500

Here is what ALMOST passes the compiler. I get 2 errors now, but I don’t understand what they mean. Do I need to use something besides float because the numbers are so small?

weather_station.cpp: In function ‘float temperature()’:
weather_station:89: error: ‘2.5698498939163982868194580078125e-4’ cannot be used as a function
weather_station:89: error: ‘2.62013099927571602165699005126953125e-6’ cannot be used as a function

float tempK = 1 / ((.003354016)+(.0002569850(log(thermVal/10000)))+(.000002620131(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));

#include <Wire.h>
#include <Math.h>

#define BMP085_ADDRESS 0x77 // I2C address of BMP085

long previousMillis = 0;
long interval = 1000;
const int humidityPin = 5;
const int thermistorPin = 6;

const unsigned char OSS = 0; // Oversampling Setting

// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;

// b5 is calculated in bmp085GetTemperature(…), this variable is also used in bmp085GetPressure(…)
// so …Temperature(…) must be called before …Pressure(…).
long b5;

void setup(){

Serial.begin(9600);
Wire.begin();

bmp085Calibration();

}

void loop(){

unsigned long currentMillis = millis();

if(currentMillis - previousMillis > interval) {

previousMillis = currentMillis;

float tempK = temperature();
float tempC = tempK - 273.15;
float tempF = (tempC * (9/5)) + 32;

float temperatureC = bmp085GetTemperature(bmp085ReadUT()); //MUST be called first
float temperatureK = temperatureC + 273.15;
float temperatureF = (temperatureC * (9/5)) + 32;

float avg_TemperatureF = (tempF + temperatureF) / 2;
float avg_TemperatureC = (tempC + temperatureC) / 2;
float avg_TemperatureK = (tempK + temperatureK) / 2;

float humidity_r = humidity();

float dewPoint = (237.7 * gamma(tempC,humidity_r)) / (17.271 - gamma(tempC,humidity_r)); //use Thermistor, Barometer Temp, or Avg?

float pascals = bmp085GetPressure(bmp085ReadUP()); // in pascals
float atm = pascals / 101325; // “standard atmosphere atms”
float baro_millibars = pascals * 100;
float baro_inHg = baro_millibars * 33.86;

float altitude = calcAltitude(pascals); //Uncompensated caculation - in Meters

float vaporPres = vapor(dewPoint);

float virTemp_r = virTemp(baro_millibars,vaporPres,tempK); //use Thermistor, Barometer Temp, or Avg?

float airDensity_r = airDensity(baro_inHg,virTemp_r);

//****
//Send tempF, temperature F, avg_TemperatureF, humidity, dewPoint, baro_InHg, altitude, vaporPres, and airDensity to phone over bluetooth
//****

}

}

float temperature(){

float thermVal = analogRead(thermistorPin);
thermVal = thermVal * 5 / 1023;
thermVal = thermVal/((5 - thermVal)/10000);
float tempK = 1 / ((.003354016)+(.0002569850(log(thermVal/10000)))+(.000002620131(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));
return tempK;

}

float humidity(){

float humidityVal = analogRead(humidityPin);
float relHumid = (humidityVal - 0.8) / 0.03;
return relHumid;

}

float gamma(float tempC,float humidity){

float gammavalue = ((17.271 * tempC) / (237.7 + tempC)) + log(humidity/100);
return gammavalue;

}

// Stores all of the bmp085’s calibration values into global variables
// Calibration values are required to calculate temp and pressure
// This function should be called at the beginning of the program
void bmp085Calibration()
{
ac1 = bmp085ReadInt(0xAA);
ac2 = bmp085ReadInt(0xAC);
ac3 = bmp085ReadInt(0xAE);
ac4 = bmp085ReadInt(0xB0);
ac5 = bmp085ReadInt(0xB2);
ac6 = bmp085ReadInt(0xB4);
b1 = bmp085ReadInt(0xB6);
b2 = bmp085ReadInt(0xB8);
mb = bmp085ReadInt(0xBA);
mc = bmp085ReadInt(0xBC);
md = bmp085ReadInt(0xBE);
}

// Calculate temperature in deg C
float bmp085GetTemperature(unsigned int ut){
long x1, x2;

x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
x2 = ((long)mc << 11)/(x1 + md);
b5 = x1 + x2;

float temp = ((b5 + 8)>>4);
temp = temp /10;

return temp;
}

// Calculate pressure given up
// calibration values must be known
// b5 is also required so bmp085GetTemperature(…) must be called first.
// Value returned will be pressure in units of Pa.
long bmp085GetPressure(unsigned long up){
long x1, x2, x3, b3, b6, p;
unsigned long b4, b7;

b6 = b5 - 4000;
// Calculate B3
x1 = (b2 * (b6 * b6)>>12)>>11;
x2 = (ac2 * b6)>>11;
x3 = x1 + x2;
b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;

// Calculate B4
x1 = (ac3 * b6)>>13;
x2 = (b1 * ((b6 * b6)>>12))>>16;
x3 = ((x1 + x2) + 2)>>2;
b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;

b7 = ((unsigned long)(up - b3) * (50000>>OSS));
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;
p += (x1 + x2 + 3791)>>4;

long pascal = p;
return pascal;
}

// Read 1 byte from the BMP085 at ‘address’
char bmp085Read(unsigned char address)
{
unsigned char data;

Wire.beginTransmission(BMP085_ADDRESS);
Wire.send(address);
Wire.endTransmission();

Wire.requestFrom(BMP085_ADDRESS, 1);
while(!Wire.available())
;

return Wire.receive();
}

// Read 2 bytes from the BMP085
// First byte will be from ‘address’
// Second byte will be from ‘address’+1
int bmp085ReadInt(unsigned char address)
{
unsigned char msb, lsb;

Wire.beginTransmission(BMP085_ADDRESS);
Wire.send(address);
Wire.endTransmission();

Wire.requestFrom(BMP085_ADDRESS, 2);
while(Wire.available()<2)
;
msb = Wire.receive();
lsb = Wire.receive();

return (int) msb<<8 | lsb;
}

// Read the uncompensated temperature value
unsigned int bmp085ReadUT(){
unsigned int ut;

// Write 0x2E into Register 0xF4
// This requests a temperature reading
Wire.beginTransmission(BMP085_ADDRESS);
Wire.send(0xF4);
Wire.send(0x2E);
Wire.endTransmission();

// Wait at least 4.5ms
delay(5);

// Read two bytes from registers 0xF6 and 0xF7
ut = bmp085ReadInt(0xF6);
return ut;
}

// Read the uncompensated pressure value
unsigned long bmp085ReadUP(){

unsigned char msb, lsb, xlsb;
unsigned long up = 0;

// Write 0x34+(OSS<<6) into register 0xF4
// Request a pressure reading w/ oversampling setting
Wire.beginTransmission(BMP085_ADDRESS);
Wire.send(0xF4);
Wire.send(0x34 + (OSS<<6));
Wire.endTransmission();

// Wait for conversion, delay time dependent on OSS
delay(2 + (3<<OSS));

// Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
msb = bmp085Read(0xF6);
lsb = bmp085Read(0xF7);
xlsb = bmp085Read(0xF8);

up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);

return up;
}

void writeRegister(int deviceAddress, byte address, byte val) {
Wire.beginTransmission(deviceAddress); // start transmission to device
Wire.send(address); // send register address
Wire.send(val); // send value to write
Wire.endTransmission(); // end transmission
}

int readRegister(int deviceAddress, byte address){

int v;
Wire.beginTransmission(deviceAddress);
Wire.send(address); // register to read
Wire.endTransmission();

Wire.requestFrom(deviceAddress, 1); // read a byte

while(!Wire.available()) {
// waiting
}

v = Wire.receive();
return v;
}

float calcAltitude(float pressure){

float A = pressure/101325;
float B = 1/5.25588;
float C = pow(A,B);
C = 1 - C;
C = C /0.0000225577;

return C;
}

float vapor(float dewpoint){

float power = (7.5 * dewpoint) / (237.7 + dewpoint);
float vaporPres = 6.11 * pow(10,power);
return vaporPres;

}

float virTemp(float millibar,float vapor,float tempK){

float denom = ((1 - (vapor / millibar)) * (1-0.622));
float virTemp = tempK / denom;
return virTemp;

}

float airDensity(float inHg,float virTemp){

float inner = (17.326 * inHg) / virTemp;
float middle = 1 - pow(inner,0.235);
float density = 145366 * middle;
return density;

}

float tempK = 1 / ((.003354016)+(.0002569850(log(thermVal/10000)))+(.000002620131(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));

would compile if it were

float tempK = 1 / ((.003354016)+(.0002569850*(log(thermVal/10000)))+(.000002620131*(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));

(missing multiplication symbol after two of your constants)

wildbill:

float tempK = 1 / ((.003354016)+(.0002569850(log(thermVal/10000)))+(.000002620131(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));

would compile if it were

float tempK = 1 / ((.003354016)+(.0002569850*(log(thermVal/10000)))+(.000002620131*(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));

(missing multiplication symbol after two of your constants)

Here’s the comment that has the code: http://www.sparkfun.com/products/250#comment-4eaad856757b7fd35100ab33

It is based on number 8 in the table on page 4 (pg 78) of the datasheet: http://www.sparkfun.com/datasheets/Sensors/Thermistor23816403-1.pdf

So that is the correct formula, as corrected:

float temperature(){

float thermVal = analogRead(thermistorPin);
thermVal = thermVal * 5 / 1023;
thermVal = thermVal/((5 - thermVal)/10000);
float tempK = 1 / ((.003354016)+(.0002569850*(log(thermVal/10000)))+(.000002620131*(pow((log(thermVal/10000)),2)))+(.00000006383091*(pow((log(thermVal/10000)),3))));
return tempK;

}

I added the serial.println commands. Is this all that I have to do to send the data over BlueTooth, or is there more to be done?

void loop(){

unsigned long currentMillis = millis();

if(currentMillis - previousMillis > interval) {

previousMillis = currentMillis;

float tempK = temperature(); float tempC = tempK - 273.15; float tempF = (tempC * (9/5)) + 32;

float temperatureC = bmp085GetTemperature(bmp085ReadUT()); //MUST be called first float temperatureK = temperatureC + 273.15; float temperatureF = (temperatureC * (9/5)) + 32;

float avg_TemperatureF = (tempF + temperatureF) / 2; float avg_TemperatureC = (tempC + temperatureC) / 2; float avg_TemperatureK = (tempK + temperatureK) / 2;

float humidity_r = humidity();

float dewPoint = (237.7 * gamma(tempC,humidity_r)) / (17.271 - gamma(tempC,humidity_r)); //use Thermistor, Barometer Temp, or Avg?

float pascals = bmp085GetPressure(bmp085ReadUP()); // in pascals float atm = pascals / 101325; // "standard atmosphere atms" float baro_millibars = pascals * 100; float baro_inHg = baro_millibars * 33.86;

float altitude = calcAltitude(pascals); //Uncompensated caculation - in Meters

float vaporPres = vapor(dewPoint);

float virTemp_r = virTemp(baro_millibars,vaporPres,tempK); //use Thermistor, Barometer Temp, or Avg?

float airDensity_r = airDensity(baro_inHg,virTemp_r);

Serial.println("Thermistor: " + tempF + " DegF"); Serial.println("Barometer Temp: " + temperatureF + " DegF"); Serial.println("Avg Temp: " + avg_TemperatureF + " DegF"); Serial.println("Humidity: " + humidity_r + " %"); Serial.println("Dew Point: " + dewPointF + " DegF"); Serial.println("Barometer: " + baro_inHg + " inHg"); Serial.println("Physical Altitude: " + altitude + " Feet"); Serial.println("Vapor Pressure: " + vaporPres ); Serial.println("Air Density Altitude: " + airDensity_r + " Feet");

//**** //Send tempF, temperature F, avg_TemperatureF, humidity, dewPoint, baro_InHg, altitude, vaporPres, and airDensity to phone over bluetooth //****

}

}

Question:

If I wanted to record values to an SD card every time the sensors are checked, how much more difficult would it be?

Also,

How would I set an interrupt so that if I send a character from my phone to the arduino, it would send me back a live sensor read?

Would I just copy what is inside the if statement now, and put it in a serial.avaliable() if statement, or something down that line?

It wouldn't mater if it reset the time counter or not.

Also, slightly more important: Is there a way to print the current time from the RTC? Or does the RTC reset whenever power is taken away?

So here’s what I’ve come up with:

DS1307 RTC with breakout: http://www.sparkfun.com/products/99

Use the library from here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1191209057

Use the code base from here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235070596

SD card shield: http://www.sparkfun.com/products/9802http://arduino.cc/en/Tutorial/Datalogger

Then I can read the I2C to print the time along with all the weather data.

Question I don’t know, is how to read the time on I2C as well as the barometer on I2c. Both are 3.3V chips.

To listen for my phone and write to Sd card, I would just do the following routine, correct? I haven’t added the RTC code yet, since I dont know how to do multiple I2C communication…

#include <Wire.h>
#include <Math.h>
#include <SD.h>

#define BMP085_ADDRESS 0x77 // I2C address of BMP085

long previousMillis = 0;
long interval = 1000;
const int humidityPin = 5;
const int thermistorPin = 6;

const unsigned char OSS = 0; // Oversampling Setting
const int chipSelect = 10; // CS pin for SD card, pin 53 for Mega

// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;

// b5 is calculated in bmp085GetTemperature(…), this variable is also used in bmp085GetPressure(…)
// so …Temperature(…) must be called before …Pressure(…).
long b5;

void setup(){

Serial.begin(9600);
Wire.begin();
pinMode(10, OUTPUT);

bmp085Calibration();

}

void loop(){

unsigned long currentMillis = millis();

if(currentMillis - previousMillis > interval) {

previousMillis = currentMillis;
getConditions();

}

if (Serial.available()) {
command = Serial.read();
if ((command == 85) || (command == 117)) {

previousMillis = currentMillis; // reset the timer

getConditions();

}
}

void getConditions(){

float tempK = temperature();
float tempC = tempK - 273.15;
float tempF = (tempC * (9/5)) + 32;

float temperatureC = bmp085GetTemperature(bmp085ReadUT()); //MUST be called first
float temperatureK = temperatureC + 273.15;
float temperatureF = (temperatureC * (9/5)) + 32;

float avg_TemperatureF = (tempF + temperatureF) / 2;
float avg_TemperatureC = (tempC + temperatureC) / 2;
float avg_TemperatureK = (tempK + temperatureK) / 2;

float humidity_r = humidity();

float dewPoint = (237.7 * gamma(tempC,humidity_r)) / (17.271 - gamma(tempC,humidity_r)); //use Thermistor, Barometer Temp, or Avg?

float pascals = bmp085GetPressure(bmp085ReadUP()); // in pascals
float atm = pascals / 101325; // “standard atmosphere atms”
float baro_millibars = pascals * 100;
float baro_inHg = baro_millibars * 33.86;

float altitude = calcAltitude(pascals); //Uncompensated caculation - in Meters

float vaporPres = vapor(dewPoint);

float virTemp_r = virTemp(baro_millibars,vaporPres,tempK); //use Thermistor, Barometer Temp, or Avg?

float airDensity_r = airDensity(baro_inHg,virTemp_r);

Serial.println(“Thermistor: " + tempF + " DegF”);
Serial.println(“Barometer Temp: " + temperatureF + " DegF”);
Serial.println(“Avg Temp: " + avg_TemperatureF + " DegF”);
Serial.println(“Humidity: " + humidity_r + " %”);
Serial.println(“Dew Point: " + dewPointF + " DegF”);
Serial.println(“Barometer: " + baro_inHg + " inHg”);
Serial.println(“Physical Altitude: " + altitude + " Feet”);
Serial.println("Vapor Pressure: " + vaporPres );
Serial.println(“Air Density Altitude: " + airDensity_r + " Feet”);

File dataFile = SD.open(“wx_log.txt”, FILE_WRITE);

if (dataFile) {

dataFile.println(“Thermistor: " + tempF + " DegF”);
dataFile.println(“Barometer Temp: " + temperatureF + " DegF”);
dataFile.println(“Avg Temp: " + avg_TemperatureF + " DegF”);
dataFile.println(“Humidity: " + humidity_r + " %”);
dataFile.println(“Dew Point: " + dewPointF + " DegF”);
dataFile.println(“Barometer: " + baro_inHg + " inHg”);
dataFile.println(“Physical Altitude: " + altitude + " Feet”);
dataFile.println("Vapor Pressure: " + vaporPres );
dataFile.println(“Air Density Altitude: " + airDensity_r + " Feet”);

dataFile.close();

}

}

so now, given the code above (I haven't touched anything else in the calculations or anything), all I need to know is how to read the I2C Real Time clock in addition to the I2C Barometric Pressure Sensor.

And I think that's it?

Now try ‘code’, and not ‘quote’.
For each post, click on ‘modify’, then change the quote tags into code tags.

attached.

weather_station.pde (16.6 KB)

if ((command == 85) || (command == 117)) {  // u or U input from phone

Either you really enjoy typing unnecessary comments, or you haven’t understood the rules of the obfuscated programming competition

if ((command == 'U') || (command == 'u')) {

AWOL: if ((command == 85) || (command == 117)) {  // u or U input from phone

Either you really enjoy typing unnecessary comments, or you haven't understood the rules of the obfuscated programming competition

if ((command == 'U') || (command == 'u')) {

I was following the syntax from the code that I had previously sourced. But I have corrected it to read as a string rather than an ASCII # for all instances.