Модули на основе сборки BMP180 от компании Bosсh на сегодняшний день, наверное, самые популярные датчики атмосферного давления и температуры с цифровым интерфейсом I2C. Кстати, это не обязательно может быть атмосферное давление. Можно измерить, например, давление в закрытой бутылке, накачанной воздухом, или в салоне самолета, летящего на высоте 10000 м. Поскольку атмосферное давление напрямую связано с высотой, с помощью датчика можно определить, на какой высоте над уровнем моря он находится. Давление также зависит и от температуры, так что измерения этих двух величин одним датчиком способствует максимально точному вычислению высоты.
Наличие интерфейса I2C делает весьма простой задачу подключения датчика к микроконтроллеру, который считывает данные, производит необходимые вычисления, индицирует результаты и управляет необходимыми исполнительными устройствами.
В данном материале мы рассмотрим, как подключить BMP180 к Raspberry Pi 3 Model B, получить и обработать результаты измерений. Мы попробуем выполнить управляющую программу на двух алгоритмических языках: С и Python.
BMP180 — датчик абсолютного давления (барометр), построенный по пьезорезистивной схеме. Датчик имеет низкий уровень шумов и высокую линейность, а также высокую скорость установки показаний. На кристалле находится MEMS-датчик (микромеханический датчик) в виде гибкой кремниевой мембраны, закрывающей камеру со стандартным давлением. На мембране расположены тензодатчики, которые включены по схеме моста, и изменяют своё сопротивление при изгибе мембраны. Изгиб мембраны зависит от разности между окружающим давлением и давлением в камере. Таким образом, выходной сигнал, снимаемый с тензомоста, зависит от давления окружающей среды. Так как параметры мембраны и резисторов зависят от температуры, то на кристалле расположен цифровой термометр, показания которого используются для компенсации данных барометра, но термометр может использоваться и самостоятельно. Данные о температуре, снятые с других датчиков, для компенсации использовать не рекомендуется. Термометр в датчике BMP180 расположен на самом измерительном кристалле, и он измеряет температуру чувствительного элемента — поэтому показания встроенного термометра наиболее близки к температуре барометра. Максимальная точность измерения давления составляет 2 Пa, поэтому, если использовать датчик BMP180 как барометрический высотомер, то соответствующая погрешность измерения высоты составит 17 см.
Технические характеристики датчика BMP180:
- напряжение питания: 1,62 В — 3,6 В.
- интерфейс подключения: I2C.
- точность: до 0,02 гПа (17 см).
- диапазон: 300 – 1100 гПа (от -500 м до 9000 м высоты).
- выходные данные: 16 бит, давление и температура
- разрешение по давлению: 0,01 гПа
- разрешение по температуре: 0,1° С
- размер платы без разъема: 12 х 14 мм
Интерфейс барометра BMP180 — I2C, что делает работу с ним простой и удобной. На модуле кроме самого датчика установлен линейный стабилизатор на микросхеме XC6206P332MR в корпусе SOT-23 (падение напряжения на стабилизаторе составляет всего 250 мВ, собственное потребление — 1 мкА.)
При эксплуатации барометра следует учитывать некоторые особенности.
- Помните, что BMP180 необходим доступ окружающего воздуха для измерения его давления, так что не стоит его укладывать в герметичный корпус. С другой стороны, воздействие быстро движущихся воздушных потоков или ветра могут вызвать кратковременные колебания давления, которые будут влиять ваши показания. Защитите устройство от сильных воздушных потоков.
- Точное значение температуры необходимо для измерения давления, поэтому старайтесь не подвергать устройство резким изменениям температуры, держите его подальше от нагревающихся деталей и других источников тепла.
- BMP180 чувствителен к влаге и не должен контактировать с водой.
- BMP180 чувствителен к свету, который может войти в устройство через маленькое отверстие в металлической крышке корпуса чипа. Для достижения максимальной точности следует оградить датчик от окружающего света.
Подключается датчик BMP180 с помощью всего четырех проводов: питание +3,3 В (или +5 В - VCC), земля (GND), SDA (data) и SCL (clock).
Соответственно, подключение к разъему GPIO Raspberry будет выглядеть следующим образом:
Теперь нужно убедиться, разрешен ли в Raspberry обмен по шине I2С (по умолчанию он запрещен), и, если нет, то разрешить. Предполагается, что в системе Raspbian установлены пакеты i2c-tools. Кстати, проверить, установлен ли конкретный пакет, можно набрав команду: aptitude show имя_пакета.
Если пакет не установлен (в третьей строке Рис.3 - State: not installed), установите его командой: sudo apt-get install i2c-tools.
Наберите в терминале команду: i2cdetect –y 1. Если в результате выполнения команды при подключенном датчике будет найдено подключение с адресом 77, значит, обмен разрешен, и датчик давления BMP180 подключен правильно.
Если ни одного адреса не отображается, то, скорее всего датчик не подключен, или подключен неправильно, или запрещен обмен по шине I2C.
Для того чтобы разрешить обмен выполните в терминале команды:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
В данном файле (raspi-blacklist.conf) закомментируйте строчку (если она есть) blacklist i2c-bcm2708, добавив знак решетки # в начале строки. Сохраните изменения.
Добавьте модуль I2C в автозапуск системы. Команда редактирования:
sudo nano /etc/modules
В самый конец этого файла добавьте строчки i2c-dev и i2c-bcm2708. Сохраните файл.
Перезагрузите систему:
sudo reboot
Для проверки работоспособности выполните команду:
i2cdetect -y 1
Загрузка, компиляция и запуск программы на языке C.
После проверки подключения загрузите с сайта masterkit.ru и разархивируйте в корневой каталог программу на языке C:
cd ~
wget https://masterkit.ru/zip/bmp180-c.tar.gz
sudo tar zxvf bmp180-c.tar.gz
В результате в корневом каталоге появится папка bmp180-c с двумя файлами: bmp180.h и bmp180test.c. Теперь изменим рабочий каталог на bmp180-c и воспользуемся встроенным в OC Raspbian компилятором gcc для получения исполняемого файла:
cd bmp180-c
sudo gcc -Wall -o bmp180 bmp180test.c -lwiringPi -lm
В папке bmp180-c появится исполняемый файл bmp180. Запустим его на выполнение:
sudo ./bmp180
Символы ./ указывают на то, что файл должен быть запущен именно из текущего каталога.
Запустить файл можно также из Файлового Менеджера (File Manager) операционной системы. Файл запускается на выполнение двойным кликом мыши по его иконке, при появлении диалогового окна следует выбрать Execute in Terminal.
В окно терминала каждую секунду выводятся температура, давление и высота.
Принципы расчета высоты и текущего давления на уровне моря основаны на следующих формулах:
- при измеренном давлении p и давлении на уровне моря p0, например, 1013.25hPa, высота в метрах может быть рассчитана при помощи так называемой международной барометрической формулы:
Согласно этой формуле, изменение давления Δp = 1hPa соответствует 8,43 м на уровне моря.
- при измеренном давлении p и абсолютной высоте можно рассчитать давление на уровне моря:
Разница в высоте Δaltitude = 10m соответствует изменению давления 1,2hPa на уровне моря.
Ниже приведены листинги заголовочного файла bmp180.h и файла программы bmp180test.c:
Файл bmp180.h
#ifndef _BMP180_
#define _BMP180_
//i2c address
#define BMP180_Address 0x77
//Operating Modes
#define BMP180_ULTRALOWPOWER 0
#define BMP180_STANDARD 1
#define BMP180_HIGHRES 2
#define BMP180_ULTRAHIGHRES 3
//BMP185 Registers
#define BMP180_CAL_AC1 0xAA //Calibration data (16 bits)
#define BMP180_CAL_AC2 0xAC //Calibration data (16 bits)
#define BMP180_CAL_AC3 0xAE //Calibration data (16 bits)
#define BMP180_CAL_AC4 0xB0 //Calibration data (16 bits)
#define BMP180_CAL_AC5 0xB2 //Calibration data (16 bits)
#define BMP180_CAL_AC6 0xB4 //Calibration data (16 bits)
#define BMP180_CAL_B1 0xB6 //Calibration data (16 bits)
#define BMP180_CAL_B2 0xB8 //Calibration data (16 bits)
#define BMP180_CAL_MB 0xBA //Calibration data (16 bits)
#define BMP180_CAL_MC 0xBC //Calibration data (16 bits)
#define BMP180_CAL_MD 0xBE //Calibration data (16 bits)
#define BMP180_CONTROL 0xF4
#define BMP180_TEMPDATA 0xF6
#define BMP180_PRESSUREDATA 0xF6
//Commands
#define BMP180_READTEMPCMD 0x2E
#define BMP180_READPRESSURECMD 0x34
#endif
Файл bmp180test.c
#include < wiringPi.h>
#include < wiringPiI2C.h>
#include < stdio.h>
#include < math.h>
#include "bmp180.h"
#define OSS BMP180_STANDARD
short AC1,AC2,AC3,B1,B2,MB,MC,MD;
unsigned short AC4,AC5,AC6;
int fd;
char I2C_readByte(int reg)
{
return (char)wiringPiI2CReadReg8(fd,reg);
}
unsigned short I2C_readU16(int reg)
{
int MSB,LSB;
MSB = I2C_readByte(reg);
LSB = I2C_readByte(reg + 1);
int value = (MSB 32767)result -= 65536;
return (short)result;
}
void I2C_writeByte(int reg,int val)
{
wiringPiI2CWriteReg8(fd,reg,val);
}
void load_calibration()
{
AC1 = I2C_readS16(BMP180_CAL_AC1);
AC2 = I2C_readS16(BMP180_CAL_AC2);
AC3 = I2C_readS16(BMP180_CAL_AC3);
AC4 = I2C_readU16(BMP180_CAL_AC4);
AC5 = I2C_readU16(BMP180_CAL_AC5);
AC6 = I2C_readU16(BMP180_CAL_AC6);
B1 = I2C_readS16(BMP180_CAL_B1);
B2 = I2C_readS16(BMP180_CAL_B2);
MB = I2C_readS16(BMP180_CAL_MB);
MC = I2C_readS16(BMP180_CAL_MC);
MD = I2C_readS16(BMP180_CAL_MD);
}
int read_raw_temp()
{
int raw;
I2C_writeByte(BMP180_CONTROL,BMP180_READTEMPCMD);
delay(5); //5ms;
raw = I2C_readByte(BMP180_TEMPDATA)
raw += I2C_readByte(BMP180_TEMPDATA+1);
return raw;
}
int read_raw_pressure()
{
int MSB,LSB,XLSB,raw;
I2C_writeByte(BMP180_CONTROL,BMP180_READPRESSURECMD +(OSS
switch(OSS)
{
case BMP180_ULTRALOWPOWER:
delay(5);break;
case BMP180_HIGHRES:
delay(14);break;
case BMP180_ULTRAHIGHRES:
delay(26);break;
default :
delay(8);
}
MSB = I2C_readByte(BMP180_PRESSUREDATA);
LSB = I2C_readByte(BMP180_PRESSUREDATA + 1);
XLSB = I2C_readByte(BMP180_PRESSUREDATA + 2);
raw = ((MSB (8 - OSS);
return raw;
}
float read_temperature()
{
float T;
int UT,X1,X2,B5;
UT = read_raw_temp();
X1 = ((UT - AC6)*AC5) >> 15;
X2 = (MC > 4) /10.0;
return T;
}
int read_pressure()
{
int P;
int UT,UP,X1,X2,X3,B3,B5,B6;
unsigned int B4;
int B7;
UT = read_raw_temp();
UP = read_raw_pressure();
X1 = ((UT - AC6)*AC5) >> 15;
X2 = (MC > 12) >> 11;
X2 = (AC2 * B6) >> 11;
X3 = X1 + X2;
B3 = (((AC1 * 4 + X3) > 13;
X2 = (B1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = (AC4 * (X3 + 32768)) >> 15;
B7 = (UP - B3) * (50000 >> OSS);
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;
P = P + ((X1 + X2 + 3791) >> 4);
return P;
}
float read_altitude()
{
float pressure,altitude;
float sealevel_pa = 101325.0;
pressure = (float)read_pressure();
altitude = 44330.0 * (1.0 - pow(pressure / sealevel_pa,(1.0/5.255)));
return altitude;
}
float read_sealevel_pressure()
{
float altitude_m = 0.0;
float pressure,p0;
pressure =(float)read_pressure();
p0 = pressure / pow(1.0 - altitude_m/44330.0,5.255);
return p0;
}
int main(int argc,char **argv)
{
printf("BMP180 Test Program ...\n");
if(wiringPiSetup() < 0) return 1;
fd = wiringPiI2CSetup(BMP180_Address);
load_calibration();
while(1)
{
printf("\nTemperature : %.2f C\n",read_temperature());
printf("Pressure : %.2f hPa\n",read_pressure()/100.0);
printf("Altitude : %.2f h\n",read_altitude());
delay(1000);
}
return 0;
Загрузка и запуск программы на языке Python.
Для тех, кто предпочитает Python, рассмотрим, как аналогичный результат можно получить с помощью этого языка программирования.
В первую очередь, убедитесь, что библиотека Python RPi.GPIO, обеспечивающая взаимодействие программ на Python с контактами GPIO Raspberry установлена. Запустите в терминале интерпретатор python и в ответ на приглашение >>> выполните одну за другой следующие команды:
import RPi.GPIO
RPi.GPIO.VERSION
Выход из интерпретатора – Ctrl-D.
Если ошибок не возникло и выведен номер версии библиотеки, то можно продолжать.
Выполните в терминале команду sudo apt-get install python-smbus для установки пакета для связи по шине I2C из программ на Python, если он еще не установлен.
После проверки подключения загрузите с сайта masterkit.ru и разархивируйте в корневой каталог программу на языке Python:
cd ~
wget https://masterkit.ru/zip/bmp180-python.tar.gz
sudo tar zxvf bmp180-python.tar.gz
В корневом каталоге появится папка bmp180-python с тремя файлами: bmp180.py, bmp180.pyc и bmp180test.py. Файл bmp180.pyc является скомпилированным вариантом исходного файла bmp180.py и будет использован при работе основного файла программы bmp180test.py.
Перейдите в каталог bmp180-python и запустите программу:
cd bmp180-python
sudo python ./BMP180test.py
Подсоединенный к Raspberry Pi датчик давления
Результат работы программы на экране планшета. Raspberry и планшет находятся в локальной сети посредством подключения по WiFi, на Raspberry работает VNC-server, на планшете – VNC-viewer.
Ниже приведены листинги программ BMP180.py и BMP180test.py:
Файл BMP180.py
import time
import smbus
# BMP085 default address.
BMP180_I2CADDR = 0x77
# Operating Modes
BMP180_ULTRALOWPOWER = 0
BMP180_STANDARD = 1
BMP180_HIGHRES = 2
BMP180_ULTRAHIGHRES = 3
# BMP085 Registers
BMP180_CAL_AC1 = 0xAA # R Calibration data (16 bits)
BMP180_CAL_AC2 = 0xAC # R Calibration data (16 bits)
BMP180_CAL_AC3 = 0xAE # R Calibration data (16 bits)
BMP180_CAL_AC4 = 0xB0 # R Calibration data (16 bits)
BMP180_CAL_AC5 = 0xB2 # R Calibration data (16 bits)
BMP180_CAL_AC6 = 0xB4 # R Calibration data (16 bits)
BMP180_CAL_B1 = 0xB6 # R Calibration data (16 bits)
BMP180_CAL_B2 = 0xB8 # R Calibration data (16 bits)
BMP180_CAL_MB = 0xBA # R Calibration data (16 bits)
BMP180_CAL_MC = 0xBC # R Calibration data (16 bits)
BMP180_CAL_MD = 0xBE # R Calibration data (16 bits)
BMP180_CONTROL = 0xF4
BMP180_TEMPDATA = 0xF6
BMP180_PRESSUREDATA = 0xF6
# Commands
BMP180_READTEMPCMD = 0x2E
BMP180_READPRESSURECMD = 0x34
class BMP180(object):
def __init__(self, address=BMP180_I2CADDR, mode=BMP180_STANDARD):
self._mode = mode
self._address = address
self._bus = smbus.SMBus(1)
# Load calibration values.
self._load_calibration()
def _read_byte(self,cmd):
return self._bus.read_byte_data(self._address,cmd)
def _read_u16(self,cmd):
MSB = self._bus.read_byte_data(self._address,cmd)
LSB = self._bus.read_byte_data(self._address,cmd+1)
return (MSB 32767:result -= 65536
return result
def _write_byte(self,cmd,val):
self._bus.write_byte_data(self._address,cmd,val)
def _load_calibration(self):
"load calibration"
self.cal_AC1 = self._read_s16(BMP180_CAL_AC1) # INT16
self.cal_AC2 = self._read_s16(BMP180_CAL_AC2) # INT16
self.cal_AC3 = self._read_s16(BMP180_CAL_AC3) # INT16
self.cal_AC4 = self._read_u16(BMP180_CAL_AC4) # UINT16
self.cal_AC5 = self._read_u16(BMP180_CAL_AC5) # UINT16
self.cal_AC6 = self._read_u16(BMP180_CAL_AC6) # UINT16
self.cal_B1 = self._read_s16(BMP180_CAL_B1) # INT16
self.cal_B2 = self._read_s16(BMP180_CAL_B2) # INT16
self.cal_MB = self._read_s16(BMP180_CAL_MB) # INT16
self.cal_MC = self._read_s16(BMP180_CAL_MC) # INT16
self.cal_MD = self._read_s16(BMP180_CAL_MD) # INT16
def read_raw_temp(self):
"""Reads the raw (uncompensated) temperature from the sensor."""
self._write_byte(BMP180_CONTROL, BMP180_READTEMPCMD)
time.sleep(0.005) # Wait 5ms
MSB = self._read_byte(BMP180_TEMPDATA)
LSB = self._read_byte(BMP180_TEMPDATA+1)
raw = (MSB
return raw
def read_raw_pressure(self):
"""Reads the raw (uncompensated) pressure level from the sensor."""
self._write_byte(BMP180_CONTROL, BMP180_READPRESSURECMD + (self._mode
if self._mode == BMP180_ULTRALOWPOWER:
time.sleep(0.005)
elif self._mode == BMP180_HIGHRES:
time.sleep(0.014)
elif self._mode == BMP180_ULTRAHIGHRES:
time.sleep(0.026)
else:
time.sleep(0.008)
MSB = self._read_byte(BMP180_PRESSUREDATA)
LSB = self._read_byte(BMP180_PRESSUREDATA+1)
XLSB = self._read_byte(BMP180_PRESSUREDATA+2)
raw = ((MSB (8 - self._mode)
return raw
def read_temperature(self):
"""Gets the compensated temperature in degrees celsius."""
UT = self.read_raw_temp()
X1 = ((UT - self.cal_AC6) * self.cal_AC5) >> 15
X2 = (self.cal_MC > 4) / 10.0
return temp
def read_pressure(self):
"""Gets the compensated pressure in Pascals."""
UT = self.read_raw_temp()
UP = self.read_raw_pressure()
X1 = ((UT - self.cal_AC6) * self.cal_AC5) >> 15
X2 = (self.cal_MC > 12) >> 11
X2 = (self.cal_AC2 * B6) >> 11
X3 = X1 + X2
B3 = (((self.cal_AC1 * 4 + X3) > 13
X2 = (self.cal_B1 * ((B6 * B6) >> 12)) >> 16
X3 = ((X1 + X2) + 2) >> 2
B4 = (self.cal_AC4 * (X3 + 32768)) >> 15
B7 = (UP - B3) * (50000 >> self._mode)
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
p = p + ((X1 + X2 + 3791) >> 4)
return p
def read_altitude(self, sealevel_pa=101325.0):
"""Calculates the altitude in meters."""
# Calculation taken straight from section 3.6 of the datasheet.
pressure = float(self.read_pressure())
altitude = 44330.0 * (1.0 - pow(pressure / sealevel_pa, (1.0/5.255)))
return altitude
def read_sealevel_pressure(self, altitude_m=0.0):
"""Calculates the pressure at sealevel when given a known altitude in
meters. Returns a value in Pascals."""
pressure = float(self.read_pressure())
p0 = pressure / pow(1.0 - altitude_m/44330.0, 5.255)
return p0
Файл BMP180test.py
import time
from BMP180 import BMP180
# Initialise the BMP085 and use STANDARD mode (default value)
# bmp = BMP085(0x77, debug=True)
bmp = BMP180()
# To specify a different operating mode, uncomment one of the following:
# bmp = BMP085(0x77, 0) # ULTRALOWPOWER Mode
# bmp = BMP085(0x77, 1) # STANDARD Mode
# bmp = BMP085(0x77, 2) # HIRES Mode
# bmp = BMP085(0x77, 3) # ULTRAHIRES Mode
while True:
temp = bmp.read_temperature()
# Read the current barometric pressure level
pressure = bmp.read_pressure()
# To calculate altitude based on an estimated mean sea level pressure
# (1013.25 hPa) call the function as follows, but this won't be very accurate
altitude = bmp.read_altitude()
# To specify a more accurate altitude, enter the correct mean sea level
# pressure level. For example, if the current pressure level is 1023.50 hPa
# enter 102350 since we include two decimal places in the integer value
# altitude = bmp.readAltitude(102350)
print "Temperature: %.2f C" % temp
print "Pressure: %.2f hPa" % (pressure / 100.0)
print "Altitude: %.2f\n" % altitude
time.sleep(2)