Use the Raspberry Pi 3 to read barometric pressure and temperature information from the barometric pressure / temperature sensor BMP180. If you specify the sea level pressure, the altitude of the measurement point will be calculated based on the measured pressure. The programming language uses Java.
BMP180 |
---|
Use Pi4J to control the GPIO of the Raspberry Pi from Java. For the Pi4J environment, refer to "Installing Pi4J" in the following article.
Also, since this sensor communicates via I2C, enable the I2C communication function of the Raspberry Pi (it is disabled by default).
To enable it from the Raspbian GUI, open the settings panel from "Settings"-"Raspberry Pi Settings" from the "Menu" button on the taskbar, and select the "Interface" tab to enable "I2C". To enable it from the command line, enter the sudo raspi-config command, select Interfacing Options> I2C, and finally select Yes.
After setting, reboot just in case.
The Raspberry Pi and BMP180 are connected as follows.
When reading the barometric pressure, this sensor specifies one of four modes to read. The number of samplings (accuracy) and power consumption differ depending on the specified mode. This mode is valid only when reading barometric pressure and is not relevant for reading temperature.
(Reference) BMP180 datasheet
The program consists of the following two files. BMP180Demo.java BMP180.java
The sensor address assumes the default 77H. After connecting the sensor, enter the following command, and if it is recognized in a place other than 77H, set the value to the constant I2C_ADRESS defined in BMP180.java.
pi@raspberrypi:~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77
pi@raspberrypi:~ $
BMP180Demo.java
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class BMP180Demo {
public static void main(String[] args) throws Exception {
BMP180 bmp180 = new BMP180(); // use I2C bus 1, standard mode
// BMP180 bmp180 = new BMP180(BMP180.ULTRAHIGHRES); // use I2C bus 1, ultra high resolution mode
// BMP180 bmp180 = new BMP180(BMP180.HIGHRES); // use I2C bus 1, high resolution mode
// BMP180 bmp180 = new BMP180(BMP180.STANDARD); // use I2C bus 1, standared mode
// BMP180 bmp180 = new BMP180(BMP180.ULTRALOWPOWER); // use I2C bus 1, ultra low power mode
while (true) {
System.out.println("Last valid input: " + new Date());
double temperature = bmp180.readTemperature();
System.out.printf("Temperature: %.2f C (%.1f F)\n",
temperature, BMP180.convertToFahrenheit(temperature));
double pressure = bmp180.readPressure();
System.out.printf("Pressure : %.2f hPa\n", pressure);
// bmp180.setStandardSeaLevelPressure(pressure); // specify sea level pressure in hPa
System.out.printf("Altitude : %.2f m\n\n", bmp180.readAltitude());
TimeUnit.SECONDS.sleep(1);
}
}
}
BMP180.java
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;
import com.pi4j.io.i2c.I2CFactory.UnsupportedBusNumberException;
public class BMP180 {
// Hardware pressure sampling accuracy modes
public static final int ULTRALOWPOWER = 0;
public static final int STANDARD = 1;
public static final int HIGHRES = 2;
public static final int ULTRAHIGHRES = 3;
private int mode;
// Registers
private static final int CAL_AC1 = 0xAA;
private static final int CTRL_MEAS = 0xF4;
private static final int OUT_MSB = 0xF6;
// Commands
private static final byte CMD_READTEMP = 0x2E;
private static final byte CMD_READPRESSURE = 0x34;
private static final int I2C_BUS = I2CBus.BUS_1;
private static final int I2C_ADDRESS = 0x77;
private I2CDevice device;
private int AC1;
private int AC2;
private int AC3;
private int AC4;
private int AC5;
private int AC6;
private int B1 ;
private int B2 ;
private int MB ;
private int MC ;
private int MD ;
private double standardSeaLevelPressure = 1013.89; // avarage sea level pressure in Tokyo
public BMP180(int i2cBus, int i2cAddress, int mode) throws UnsupportedBusNumberException, IOException {
// Create I2C bus
I2CBus bus = I2CFactory.getInstance(i2cBus);
// Get I2C device
device = bus.getDevice(i2cAddress);
// Calibration Coefficients stored in EEPROM of the device
// Read 22 bytes of data from address 0xAA(170)
byte[] data = new byte[22];
device.read(CAL_AC1, data, 0, data.length);
// Convert the data
AC1 = INT (data[ 0], data[ 1]);
AC2 = INT (data[ 2], data[ 3]);
AC3 = INT (data[ 4], data[ 5]);
AC4 = UINT(data[ 6], data[ 7]);
AC5 = UINT(data[ 8], data[ 9]);
AC6 = UINT(data[10], data[11]);
B1 = INT (data[12], data[13]);
B2 = INT (data[14], data[15]);
MB = INT (data[16], data[17]);
MC = INT (data[18], data[19]);
MD = INT (data[20], data[21]);
this.mode = mode;
}
public BMP180(int mode) throws UnsupportedBusNumberException, IOException {
this(I2C_BUS, I2C_ADDRESS, mode);
}
public BMP180() throws UnsupportedBusNumberException, IOException {
this(BMP180.STANDARD);
}
private int readAndCalcB5() throws IOException, InterruptedException {
// Select measurement control register
// Enable temperature measurement
device.write(CTRL_MEAS, CMD_READTEMP);
TimeUnit.MILLISECONDS.sleep(5);
// Read 2 bytes of data from address 0xF6(246)
// temp msb, temp lsb
byte[] data = new byte[2];
device.read(OUT_MSB, data, 0, data.length);
// Convert the data
int UT = UINT(data[0], data[1]);
// Callibration for Temperature
int X1 = ((UT - AC6) * AC5) >> 15;
int X2 = (MC << 11) / (X1 + MD);
int B5 = X1 + X2;
return B5;
}
public double readTemperature() throws IOException, InterruptedException {
return ((readAndCalcB5() + 8) >> 4) / 10.0;
}
public static double convertToFahrenheit(double c) {
return c * 1.8 + 32.0;
}
public double readPressure() throws IOException, InterruptedException {
// Select measurement control register
// Enable pressure measurement
device.write(CTRL_MEAS, (byte)(CMD_READPRESSURE + (mode << 6)));
switch (mode) {
case ULTRALOWPOWER:
TimeUnit.MILLISECONDS.sleep(5);
break;
case STANDARD:
TimeUnit.MILLISECONDS.sleep(8);
break;
case HIGHRES:
TimeUnit.MILLISECONDS.sleep(14);
break;
default:
TimeUnit.MILLISECONDS.sleep(26); // ULTRAHIGHRES mode
break;
}
// Read 3 bytes of data from address 0xF6(246)
// pres msb1, pres msb, pres lsb
byte[] data = new byte[3];
device.read(OUT_MSB, data, 0, data.length);
int UP = UINT(data[0], data[1], data[2]) >> (8 - mode);
// Calibration for Pressure
int B6 = readAndCalcB5() - 4000;
int X1 = (B2 * (B6 * B6) >> 12) >> 11;
int X2 = (AC2 * B6) >> 11;
int X3 = X1 + X2;
int B3 = (((AC1 * 4 + X3) << mode) + 2) / 4;
X1 = (AC3 * B6) >> 13;
X2 = (B1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
int B4 = (AC4 * (X3 + 32768)) >> 15;
int B7 = (UP - B3) * (50000 >> mode);
int p = B7 < 0x80000000 ? (B7 * 2) / B4 : (B7 / B4) * 2;
X1 = (p >> 8) * (p >> 8);
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * p) >> 16;
p = p + ((X1 + X2 + 3791) >> 4);
return p / 100.0;
}
public void setStandardSeaLevelPressure(double standardSeaLevelPressure) {
this.standardSeaLevelPressure = standardSeaLevelPressure;
}
public double readAltitude() throws IOException, InterruptedException {
// Calculates the altitude in meters
double pressure = readPressure();
return 44330.0 * (1.0 - Math.pow(pressure / standardSeaLevelPressure, 0.1903));
}
private int INT(byte msb, byte lsb) {
int hi = msb & 0xFF;
return ((hi > 127 ? hi - 256 : hi) << 8) + (lsb & 0xFF);
}
private int UINT(byte msb, byte lsb) {
return ((msb & 0xFF) << 8) + (lsb & 0xFF);
}
private int UINT(byte msb, byte lsb, byte xlsb) {
return ((msb & 0xFF) << 16) + UINT(lsb, xlsb);
}
}
Place the above two files in a directory of your choice and compile.
pi@raspberrypi:~ $ pi4j -c BMP180Demo.java
--------------------------------------------
Pi4J - Compiling: BMP180Demo.java
--------------------------------------------
+ javac -classpath '.:classes:*:classes:/opt/pi4j/lib/*' -d . BMP180Demo.java
pi@raspberrypi:~ $
After compiling, execute it with root privileges. The temperature, barometric pressure, and altitude data are read and displayed every second.
For altitude, by specifying the sea level pressure in advance, the value is calculated based on the pressure difference from the measurement site. If no sea level is specified, the average annual sea level in Tokyo will be used as the default. On days when the atmospheric pressure is high, it may sink below the sea level.
Enter Ctrl + C to exit the program.
pi@raspberrypi:~ $ sudo pi4j BMP180Demo
+ java -classpath '.:classes:*:classes:/opt/pi4j/lib/*' BMP180Demo
Last valid input: Sun May 13 20:29:44 JST 2018
Temperature: 23.70 C (74.7 F)
Pressure : 1000.57 hPa
Altitude : 110.92 m
Last valid input: Sun May 13 20:29:45 JST 2018
Temperature: 23.60 C (74.5 F)
Pressure : 1000.73 hPa
Altitude : 109.57 m
Last valid input: Sun May 13 20:29:46 JST 2018
Temperature: 23.60 C (74.5 F)
Pressure : 1000.57 hPa
Altitude : 110.75 m
Last valid input: Sun May 13 20:29:47 JST 2018
Temperature: 23.60 C (74.5 F)
Pressure : 1000.69 hPa
Altitude : 110.08 m
^Cpi@raspberrypi:~ $
All you need to actually use the program is the BMP180.java file. The method of creating an instance and the methods that can be used are as follows.
There are three ways to specify the parameters of the constructor of class BMP180 as follows.
BMP180 bmp180 = new BMP180(); //I2C bus 1, address 0x77, operating in Standard mode
BMP180 bmp180 = new BMP180(BMP180.ULTRAHIGHRES); //I2C bus 1, address 0x77, operating in Ultra High Resoluion mode
BMP180 bmp180 = new BMP180(2, 0x01, BMP180.STANDARD); //Operates in I2C bus 2, address 0x01, Standard mode
To specify the mode, specify one of the following.
BMP180.ULTRALOWPOWER //Ultra Low Power mode
BMP180.STANDARD //Standard mode
BMP180.HIGHRES //High Resolution mode
BMP180.ULTRAHIGHRES //Ultra High Resolution mode
The following methods are available.
Methods and features |
---|
public double readTemperature() throws IOException, InterruptedException |
|
public static double convertToFahrenheit(double c) |
|
public double readPressure() throws IOException, InterruptedException |
|
public void setStandardSeaLevelPressure(double standardSeaLevelPressure) |
|
public double readAltitude() throws IOException, InterruptedException |
|
Recommended Posts