I2C (eye-squared-cee) is a communication protocol that the Raspberry Pi can use to speak to other embedded devices (temperature sensors, displays, accelerometers, etc). In this example, we’ll be connecting a BMP180 Temperature/Pressure Sensor to our Raspberry Pi.
I2C is a two wire bus, the connections are called SDA (Serial Data) and SCL (Serial Clock). Each I2C bus has one or more masters (the Raspberry Pi) and one or more slave devices, like the I/O Expander. As the same data and clock lines are shared between multiple slaves, we need some way to choose which device to communicate with. With I2C, every device has an address that each communication must be prefaced with. The temperature sensor defaults to an address of 0x77. Remember this number as we’ll see it shortly when we try to detect the chip using i2cdetect.
The Rasperry Pi has two I2C buses. One is available on the GPIO (P1) header, the other is only available from the P5 header. To access the P5 header, you’ll need to solder on your own header pins. This is generally unnecessary as you typically only need a single I2C bus.
Connecting the BMP180
Preparing RPi for I2C
Activate I2C Drivers
On your Raspberry Pi, you must first enable the I2C drivers.
Run sudo raspi-config
At the menu, choose option 5. Interfacing Options
Select P5 I2C and then say “Yes” to enable the I2C driver and “Yes” again to load the driver by default
Reboot your Raspberry Pi by running sudo rebootback at the command line
Add i2c-dev to /etc/modules
pi@raspberrypi:~$ sudo nano /etc/modules i2c-dev
Then from the prompt run:
sudo modprobe i2c-dev
Confirm that the i2c modules are loaded and active:
i2c-tools includes some cool utilities, like i2cdetect, which will enumerate the addresses of all slave devices on a single bus. Try it out by running sudo i2cdetect -y 1 with the sensor connected. Another utility, i2cdump lets you query the state of individual settings (registers) on a specific I2C device. This is the output you should see with the sensor connected as below, and configured for the default address of 0x77:
# Can enable debug output by uncommenting: #import logging #logging.basicConfig(level=logging.DEBUG)
import Adafruit_BMP.BMP085 as BMP085
# Default constructor will pick a default I2C bus. # # For the Raspberry Pi this means you should hook up to the only exposed I2C bus # from the main GPIO header and the library will figure out the bus number based # on the Pi's revision. # # For the Beaglebone Black the library will assume bus 1 by default, which is # exposed with SCL = P9_19 and SDA = P9_20. sensor = BMP085.BMP085()
# Optionally you can override the bus number: #sensor = BMP085.BMP085(busnum=2)
# You can also optionally change the BMP085 mode to one of BMP085_ULTRALOWPOWER, # BMP085_STANDARD, BMP085_HIGHRES, or BMP085_ULTRAHIGHRES. See the BMP085 # datasheet for more details on the meanings of each mode (accuracy and power # consumption are primarily the differences). The default mode is STANDARD. #sensor = BMP085.BMP085(mode=BMP085.BMP085_ULTRAHIGHRES)
Question: When I run the script, I get the following error:
1 2 3 4 5
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.7/dist-packages/Adafruit_BMP-1.0.0-py2.7.egg/Adafruit_BMP/BMP085.py", line 66, in __init__ self._device = I2C.Device(address, busnum) File "/usr/local/lib/python2.7/dist-packages/Adafruit_GPIO-0.5.5-py2.7.egg/Adafruit_GPIO/I2C.py", line 68, in __init__ self._bus = smbus.SMBus(busnum) IOError: [Errno 2] No such file or directory
Answer: Ensure you have loaded the i2c_bcm2708 and i2c-dev modules using lsmod. If they are not present, follow the instructions at the top of the page to modify the files in /etc/modules
Question: When I run the script, I get the flollowing error:
1 2 3 4 5 6 7 8 9 10
Traceback (most recent call last): File "simpletest.py", line 37, in <module> sensor = BMP085.BMP085() File "build/bdist.linux-armv7l/egg/Adafruit_BMP/BMP085.py", line 69, in __init__ File "build/bdist.linux-armv7l/egg/Adafruit_BMP/BMP085.py", line 72, in _load_calibration File "build/bdist.linux-armv7l/egg/Adafruit_GPIO/I2C.py", line 202, in readS16BE File "build/bdist.linux-armv7l/egg/Adafruit_GPIO/I2C.py", line 179, in readS16 File "build/bdist.linux-armv7l/egg/Adafruit_GPIO/I2C.py", line 166, in readU16 File "build/bdist.linux-armv7l/egg/Adafruit_PureIO/smbus.py", line 187, in read_word_data IOError: [Errno 121] Remote I/O error`
Answer:sudo i2cdetect -y 1 should report a device on address 0x77 (the bmp180). If not check the connections between the PI and bmp180.
# 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
defread_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 << 8) + LSB return raw
defread_raw_pressure(self): """Reads the raw (uncompensated) pressure level from the sensor.""" self._write_byte(BMP180_CONTROL, BMP180_READPRESSURECMD + (self._mode << 6)) 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 << 16) + (LSB << 8) + XLSB) >> (8 - self._mode) return raw
defread_temperature(self): """Gets the compensated temperature in degrees celsius.""" UT = self.read_raw_temp()
defread_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
defread_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
# 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 whileTrue: 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)