├── MANIFEST.rst ├── bmp180 ├── __init__.py └── bmp180.py ├── TODO.md ├── bin └── bmp180-example ├── README.rst ├── setup.py ├── .gitignore └── LICENSE /MANIFEST.rst: -------------------------------------------------------------------------------- 1 | include README.rst 2 | -------------------------------------------------------------------------------- /bmp180/__init__.py: -------------------------------------------------------------------------------- 1 | from .bmp180 import bmp180 2 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | Add: 2 | - Add different modes 3 | 4 | Fix: 5 | - get_altitude 6 | 7 | Test: -------------------------------------------------------------------------------- /bin/bmp180-example: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | Released under the MIT License 4 | Copyright 2015-2016 MrTijn/Tijndagamer 5 | """ 6 | 7 | from bmp180 import bmp180 8 | 9 | bmp = bmp180(0x77) 10 | 11 | print("Temp: " + str(bmp.get_temp()) + " Celcius") 12 | print("Pressure: " + str(bmp.get_pressure()) + " Pascal") 13 | print("Altitude: " + str(bmp.get_altitude()) + " meter") 14 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | bmp180 2 | ====== 3 | 4 | A Python module for accessing the BMP-180 digital temperature and pressure sensor 5 | 6 | Usage 7 | ----- 8 | 9 | For examples and information on how to use this module, please refer to the included 10 | examples and the comments in the source code. 11 | 12 | Dependencies 13 | ------------ 14 | 15 | * smbus-cffi 16 | 17 | You can either install smbus-cffi using pip or install the python-smbus package using apt. 18 | 19 | Installation 20 | ------------ 21 | 22 | Clone the repository and run setup.py 23 | :: 24 | 25 | git clone https://github.com/Tijndagamer/bmp180.git 26 | python setup.py install 27 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | def readme(): 4 | with open("README.rst") as f: 5 | return f.read() 6 | 7 | setup(name='bmp180-raspberrypi', 8 | version='1.0', 9 | description='A package to handle the i2c communication between a Raspberry Pi and a BMP180', 10 | classifiers=[ 11 | 'License :: OSI Approved :: MIT License', 12 | 'Topic :: Software Development :: Libraries', 13 | 'Programming Language :: Python :: 2.7', 14 | ], 15 | keywords='bmp180 raspberrypi raspberry pi', 16 | url='https://github.com/Tijndagamer/BMP180-Python', 17 | author='MrTijn/Tijndagamer', 18 | license='MIT', 19 | packages=['bmp180'], 20 | install_requires=[ 21 | 'smbus', 22 | ], 23 | scripts=['bin/bmp180-example'], 24 | zip_safe=False) 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | 59 | /dist/ 60 | /*.egg-info 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 MrTijn/Tijndagamer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /bmp180/bmp180.py: -------------------------------------------------------------------------------- 1 | """ 2 | This program handles the communication over I2C between a Raspberry Pi and a 3 | BMP180 Temperature/Pressure sensor. 4 | Made by: MrTijn/Tijndagamer 5 | Copyright 2015-2017 6 | Released under the MIT license. 7 | """ 8 | 9 | import smbus 10 | import math 11 | from time import sleep 12 | 13 | class bmp180: 14 | # Global variables 15 | address = None 16 | bus = smbus.SMBus(1) 17 | mode = 1 # TODO: Add a way to change the mode 18 | 19 | # BMP180 registers 20 | CONTROL_REG = 0xF4 21 | DATA_REG = 0xF6 22 | 23 | # Calibration data registers 24 | CAL_AC1_REG = 0xAA 25 | CAL_AC2_REG = 0xAC 26 | CAL_AC3_REG = 0xAE 27 | CAL_AC4_REG = 0xB0 28 | CAL_AC5_REG = 0xB2 29 | CAL_AC6_REG = 0xB4 30 | CAL_B1_REG = 0xB6 31 | CAL_B2_REG = 0xB8 32 | CAL_MB_REG = 0xBA 33 | CAL_MC_REG = 0xBC 34 | CAL_MD_REG = 0xBE 35 | 36 | # Calibration data variables 37 | calAC1 = 0 38 | calAC2 = 0 39 | calAC3 = 0 40 | calAC4 = 0 41 | calAC5 = 0 42 | calAC6 = 0 43 | calB1 = 0 44 | calB2 = 0 45 | calMB = 0 46 | calMC = 0 47 | calMD = 0 48 | 49 | 50 | def __init__(self, address): 51 | self.address = address 52 | 53 | # Get the calibration data from the BMP180 54 | self.read_calibration_data() 55 | 56 | # I2C methods 57 | 58 | def read_signed_16_bit(self, register): 59 | """Reads a signed 16-bit value. 60 | 61 | register -- the register to read from. 62 | Returns the read value. 63 | """ 64 | msb = self.bus.read_byte_data(self.address, register) 65 | lsb = self.bus.read_byte_data(self.address, register + 1) 66 | 67 | if msb > 127: 68 | msb -= 256 69 | 70 | return (msb << 8) + lsb 71 | 72 | def read_unsigned_16_bit(self, register): 73 | """Reads an unsigned 16-bit value. 74 | 75 | Reads the given register and the following, and combines them as an 76 | unsigned 16-bit value. 77 | register -- the register to read from. 78 | Returns the read value. 79 | """ 80 | msb = self.bus.read_byte_data(self.address, register) 81 | lsb = self.bus.read_byte_data(self.address, register + 1) 82 | 83 | return (msb << 8) + lsb 84 | 85 | # BMP180 interaction methods 86 | 87 | def read_calibration_data(self): 88 | """Reads and stores the raw calibration data.""" 89 | self.calAC1 = self.read_signed_16_bit(self.CAL_AC1_REG) 90 | self.calAC2 = self.read_signed_16_bit(self.CAL_AC2_REG) 91 | self.calAC3 = self.read_signed_16_bit(self.CAL_AC3_REG) 92 | self.calAC4 = self.read_unsigned_16_bit(self.CAL_AC4_REG) 93 | self.calAC5 = self.read_unsigned_16_bit(self.CAL_AC5_REG) 94 | self.calAC6 = self.read_unsigned_16_bit(self.CAL_AC6_REG) 95 | self.calB1 = self.read_signed_16_bit(self.CAL_B1_REG) 96 | self.calB2 = self.read_signed_16_bit(self.CAL_B2_REG) 97 | self.calMB = self.read_signed_16_bit(self.CAL_MB_REG) 98 | self.calMC = self.read_signed_16_bit(self.CAL_MC_REG) 99 | self.calMD = self.read_signed_16_bit(self.CAL_MD_REG) 100 | 101 | def get_raw_temp(self): 102 | """Reads and returns the raw temperature data.""" 103 | # Write 0x2E to CONTROL_REG to start the measurement 104 | self.bus.write_byte_data(self.address, self.CONTROL_REG, 0x2E) 105 | 106 | # Wait 4,5 ms 107 | sleep(0.0045) 108 | 109 | # Read the raw data from the DATA_REG, 0xF6 110 | raw_data = self.read_unsigned_16_bit(self.DATA_REG) 111 | 112 | # Return the raw data 113 | return raw_data 114 | 115 | def get_raw_pressure(self): 116 | """Reads and returns the raw pressure data.""" 117 | # Write appropriate data to sensor to start the measurement 118 | self.bus.write_byte_data(self.address, self.CONTROL_REG, 0x34 + (self.mode << 6)) 119 | 120 | # Sleep for 8 ms. 121 | # TODO: Way to use the correct wait time for the current mode 122 | sleep(0.008) 123 | 124 | MSB = self.bus.read_byte_data(self.address, self.DATA_REG) 125 | LSB = self.bus.read_byte_data(self.address, self.DATA_REG + 1) 126 | XLSB = self.bus.read_byte_data(self.address, self.DATA_REG + 2) 127 | 128 | raw_data = ((MSB << 16) + (LSB << 8) + XLSB) >> (8 - self.mode) 129 | 130 | return raw_data 131 | 132 | def get_temp(self): 133 | """Reads the raw temperature and calculates the actual temperature. 134 | 135 | The calculations used to get the actual temperature are from the BMP-180 136 | datasheet. 137 | Returns the actual temperature in degrees Celcius. 138 | """ 139 | UT = self.get_raw_temp() 140 | 141 | X1 = 0 142 | X2 = 0 143 | B5 = 0 144 | actual_temp = 0.0 145 | 146 | X1 = ((UT - self.calAC6) * self.calAC5) / math.pow(2, 15) 147 | X2 = (self.calMC * math.pow(2, 11)) / (X1 + self.calMD) 148 | B5 = X1 + X2 149 | actual_temp = ((B5 + 8) / math.pow(2, 4)) / 10 150 | 151 | return actual_temp 152 | 153 | def get_pressure(self): 154 | """Reads and calculates the actual pressure. 155 | 156 | Returns the actual pressure in Pascal. 157 | """ 158 | UP = self.get_raw_pressure() 159 | UT = self.get_raw_temp() 160 | B3 = 0 161 | B4 = 0 162 | B5 = 0 163 | B6 = 0 164 | B7 = 0 165 | X1 = 0 166 | X2 = 0 167 | X3 = 0 168 | pressure = 0 169 | 170 | # These calculations are from the BMP180 datasheet, page 15 171 | 172 | # Not sure if these calculations should be here, maybe they could be 173 | # removed? 174 | X1 = ((UT - self.calAC6) * self.calAC5) / math.pow(2, 15) 175 | X2 = (self.calMC * math.pow(2, 11)) / (X1 + self.calMD) 176 | B5 = X1 + X2 177 | 178 | # Todo: change math.pow cals to constants 179 | B6 = B5 - 4000 180 | X1 = (self.calB2 * (B6 * B6 / math.pow(2, 12))) / math.pow(2, 11) 181 | X2 = self.calAC2 * B6 / math.pow(2, 11) 182 | X3 = X1 + X2 183 | B3 = (((self.calAC1 * 4 + int(X3)) << self.mode) + 2) / 4 184 | X1 = self.calAC3 * B6 / math.pow(2, 13) 185 | X2 = (self.calB1 * (B6 * B6 / math.pow(2, 12))) / math.pow(2, 16) 186 | X3 = ((X1 + X2) + 2) / math.pow(2, 2) 187 | B4 = self.calAC4 * (X3 + 32768) / math.pow(2,15) 188 | B7 = (UP - B3) * (50000 >> self.mode) 189 | 190 | if B7 < 0x80000000: 191 | pressure = (B7 * 2) / B4 192 | else: 193 | pressure = (B7 / B4) * 2 194 | 195 | X1 = (pressure / math.pow(2, 8)) * (pressure / math.pow(2, 8)) 196 | X1 = (X1 * 3038) / math.pow(2, 16) 197 | X2 = (-7357 * pressure) / math.pow(2, 16) 198 | pressure = pressure + (X1 + X2 + 3791) / math.pow(2, 4) 199 | 200 | return pressure 201 | 202 | def get_altitude(self, sea_level_pressure = 101325): 203 | """Calulates the altitude. 204 | 205 | This method calculates the altitude using the pressure. 206 | This method is not reliable when the sensor is inside. 207 | sea_level_pressure -- the pressure at the sea level closest to you in 208 | Pascal. 209 | Returns the altitude in meters. 210 | 211 | !!! This method probably does not work correctly. I've tried to test 212 | it but at the moment I have no way of verifying the data. !!! 213 | """ 214 | altitude = 0.0 215 | pressure = float(self.get_pressure()) 216 | 217 | altitude = 44330.0 * (1.0 - math.pow(pressure / sea_level_pressure, 0.00019029495)) 218 | 219 | return altitude 220 | 221 | if __name__ == "__main__": 222 | bmp = bmp180(0x77) 223 | print(bmp.get_temp()) 224 | print(bmp.get_pressure()) 225 | print(bmp.get_altitude()) 226 | --------------------------------------------------------------------------------