Basic weather station
Measures pressure and temperature from a BMP085 sparkfun sensor board
Power to the 3V3 regulator is sourced from digital pin 8
Readings are output on serial and to a 2x16 LCD (using a 595 latch to reduce the pincount needed to control the LCD)
Matt Wright 2011
Assorted code from various sources including:
SparkFun Electronics
*/
#include <Wire.h>
//LCD lib, via shift register (595 chip)
#include <LiquidCrystal595.h>
//Watchdog statements
#include <avr/sleep.h>
#include <avr/wdt.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
volatile boolean f_wdt=1;
#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;
short temperature;
long pressure;
// LCD panel
// initialize the library with the numbers of the interface pins + the row count
// datapin, latchpin, clockpin, num_lines
LiquidCrystal595 lcd(4,5,6);
String strStatus = "Wx station v01";
void setup()
{
Serial.begin(9600);
Serial.println("Starting up pressure sensor...");
//power up the 3V3 rail, wait 100ms for everything to get going???
pinMode(8, OUTPUT);
digitalWrite(8, HIGH);
delay(50);
//Start comms with the BMP085 board
Wire.begin();
bmp085Calibration();
lcd.begin(16, 2);
print_to_LCD();
//config watchdog
cbi( SMCR,SE ); // sleep enable, power down mode
cbi( SMCR,SM0 ); // power down mode
sbi( SMCR,SM1 ); // power down mode
cbi( SMCR,SM2 ); // power down mode
setup_watchdog(9);
}
void loop()
{
if (f_wdt==1)
{ // wait for timed out watchdog / flag is set when a watchdog timeout occurs
f_wdt=0; // reset flag
//turn on 3V3 rail to sensor
digitalWrite(8, HIGH);
delay(50);
//get readings
temperature = bmp085GetTemperature(bmp085ReadUT());
pressure = bmp085GetPressure(bmp085ReadUP());
//turn off supply to sensor
digitalWrite(8, LOW);
print_to_LCD();
//wait for LCD print to finish then go back to sleep!
delay(200);
system_sleep();
}
//delay(5000);
}
// 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);
Serial.println("Calibrated sensor");
}
// Calculate temperature given ut.
// Value returned will be in units of 0.1 deg C
short bmp085GetTemperature(unsigned int ut)
{
long x1, x2;
x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
x2 = ((long)mc << 11)/(x1 + md);
b5 = x1 + x2;
return ((b5 + 8)>>4);
}
// 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;
return p;
}
// 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)
Wire.beginTransmission(BMP085_ADDRESS);
Wire.send(0xF6);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 3);
// Wait for data to become available
while(Wire.available() < 3)
;
msb = Wire.receive();
lsb = Wire.receive();
xlsb = Wire.receive();
up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);
return up;
}
void print_to_LCD()
{
/*
LCD formatting
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
P = x x x m B . T = x x . x
s t a t u s s t r i n g
*/
int pr = pressure*0.01;
int te = temperature*0.1;
String readout = String(pressure);
lcd.setCursor(2,0);
lcd.print(readout);
readout = String(temperature);
lcd.setCursor(11,0);
lcd.print(readout);
lcd.setCursor(10,0);
lcd.print(readout);
lcd.setCursor(12,0);
lcd.print(".");
lcd.setCursor(0,1);
lcd.print(strStatus);
lcd.setCursor(0,0);
lcd.print("P=");
lcd.setCursor(5,0);
lcd.print("mB");
lcd.setCursor(8,0);
lcd.print("T=");
lcd.setCursor(14,0);
lcd.print("C");
}
//////////////////////////
//watchdog funcs
void system_sleep() {
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
sleep_mode(); // System sleeps here
sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
}
//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii)
{
byte bb;
int ww;
if (ii > 9 ) ii=9;
bb=ii & 7;
if (ii > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;
Serial.println(ww);
MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCSR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCSR = bb;
WDTCSR |= _BV(WDIE);
}
//****************************************************************
// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect)
{
f_wdt=1; // set global flag
}
I am a new in this kind of development. I have arduino mega 2560 and BMP085.I also use serial 2x16 LCD. In Arduino IDE a just copied and pasted the above code but the IDE sayes some kind of error. The problem reported is in LiquidCrystal595 library I supose because is saying some kind error of name. Can you somehow help ? Thanks!
ReplyDeleteI'm using a serial-in-parallel-out 74HC595 latch chip to reduce the number of pins being used on my Arduino Uno to talk to the LCD board. This means that I needed to use a modified LiquidCrystal library. If you're not using a 595 latch chip, then just replace the references to LiquidCrystal595 with the standard library and its object (eg the line in the setup "LiquidCrystal595 lcd(4,5,6)"
ReplyDeletesee http://www.arduino.cc/en/Tutorial/ShiftOut for more on the 595 latch chip!