I2C Sensors are fun and easy

 I've responded to quite a few Facebook posts over the past few years where users were struggling with getting data from a DHT-11 temperature sensor.  They, or often another commenter on the thread, often seem offended or even angry when I suggest smashing the DHT-11 with a hammer and using a Bosch BMP-280 instead.  So I've decided to do write a quick tutorial to cover why.

For the TL;DR impatient: no there isn't a video.

Two questions that come up often in the comments are:

  • Aren't they more complicated than the DHT?  Yes, the sensors are more complicated, which is why the interface to the sensors is less complicated.
  • Aren't they more expensive than the DHT?  Yes, a little bit.  Checking Amazon, I found BMP-280 modules for as little as $2 each, including jumper wires to connect them to your Pi.  That's a little more than a cheap DHT-11, or about the same price as a DHT-11 on a module with the interface electronics and some pins.
Bosch Sensortec makes an entire family of environmental sensors that use both I2C and SPI interfaces and a common communications protocol.  For this tutorial, we will focus on the BMP-280, the least expensive, which measures both temperature and air pressure.  Other family members include the BME-280, which adds humidity sensing, and the BME-680, which adds a volatile organic compound (VOC) detectors, primarily to detect methane gas and the like.



BME-280 module
Once you have dealt with the BMP-280, the hardware interfaces to the BME-280 and BME-680 are identical, while the software interfaces are very similar.

Since this is a Quickstart tutorial, I'm going to rocket through a number of steps without adding a lot of explanation.  You can always search the web for more information about each of the topics.

I am developing this on the Raspberry Pi 4 on my desktop, but the instructions will apply to all Raspberry Pi models.  The will possibly work on Pi-alike computers like the Tinker Board, but library support tends to be spotty on platforms other than Raspberry OS, which is also why I don't recommend learning like this on other distros.

First, start with an up to date OS:

$ sudo apt update

$ sudo apt upgrade

Anytime we're going to start adding libraries, it's best to start from an up to date base.  Next, we will update python on your system to be ready for the sensor libraries.  Don't worry if some of these commands report you already have that, we want to make sure everything is up to date.

$ sudo apt install --upgrade python3 python3-pip

$ sudo apt install --upgrade python3-setuptools

Now we can install the libraries for the Bosh sensor, and support libraries, provided by Adafruit.  Adafruit is a great resource for learning how to connect, configure, and program things on Raspberry Pi, by the way.

$ sudo pip3 install --upgrade adafruit-python-shell

$ wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/raspi-blinka.py

$ sudo python3 raspi-blinka.py

Obviously, you always want to be careful when running scripts downloaded from the internet, especially as root.  Adafruit is a trusted source, feel free to check into their repository in GitHub and download the script via a more secure method if you care to.  You may also use the GitHub web UI to get a hash of the file you can check before running.

Running the Blinka script will do several things on your Pi, including enable the I2C and SPI interfaces.  You can check that Blinka enabled these interfaces with:

$ ls -l /dev/i2c* /dev/spi*

On Pi B models, you should see:

crw-rw---- 1 root i2c  89, 1 Apr 12 22:18 /dev/i2c-1

crw-rw---- 1 root spi 153, 0 Apr 12 22:18 /dev/spidev0.0

crw-rw---- 1 root spi 153, 1 Apr 12 22:18 /dev/spidev0.1

On the original Pi (with the composite video connector) you will see only one SPI bus.

Now that we have the base library installed and our buses enabled, we can install the Adafruit library for the BMP-280:

$ sudo pip3 install adafruit-circuitpython-bmp280

Now comes the hardware part.  This is simpler than the DHT-11.  First, shutdown your Pi from the Raspberry menu, or with sudo shutdown now.  You need to connect 4 wires--typically jumper wires with socket ends, between your sensor and the Pi:

Note that the color of the wires is important only in keeping them straight as you complete the connections.  Only four wires are needed:

Pi Sensor Color
3V3 (1) Vcc Red
SDA (3) SDA Green
SCL (5) SCL Blue
GND (6) GND Black

Typically Red is used for the Vcc and Black for Ground.  The other two serve only to not confuse you.  The colors I list here are what I have used in my photos.  Hardware-wise, this is it, we are wired and ready to go.

NOTE: I DO NOT recommend plugging wires onto your GPIO pins while your Pi is running.  Mistakes with power lines could be costly, in terms of rebooting your Pi unexpectedly or actually damaging something.  Modern Pis boot fast, why risk it?

Once you have it all wired together, reboot your Pi.  

Once you are back up, you will need to determine which address your BMP-280 is on the I2C bus; it will typically be 0x76 or 0x77.  There is probably a small jumper on the module that allows you to cut or solder the jumper to configure the address.  This means with a tiny bit of surgery you can read from two sensors on the same bus.

The i2cdetect utility will help us identify which address you ended up with, and it's easier than pouring through documentation:


$ 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: -- -- -- -- -- -- 76 --

In this case, mine is at address 0x76. You will need this in just a moment.  The Adafruit library assumes the BMP280 is at address 0x77, but you can specify it when you create the object in your python program.

Enter this python program with any editor you prefer (yes, I have opinions on those too):

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""Simpletest Example that shows how to get temperature,
   pressure, and altitude readings from a BMP280"""
import time
import board

# import digitalio # For use with SPI
import busio
import adafruit_bmp280

# Create library object using our Bus I2C port
i2c = busio.I2C(board.SCL, board.SDA)
bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c, 0x76)

# OR create library object using our Bus SPI port
# spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
# bmp_cs = digitalio.DigitalInOut(board.D10)
# bmp280 = adafruit_bmp280.Adafruit_BMP280_SPI(spi, bmp_cs)

# change this to match the location's pressure (hPa) at sea level
bmp280.sea_level_pressure = 1013.25

while True:
    print("\nTemperature: %0.1f C" % bmp280.temperature)
    print("Pressure: %0.1f hPa" % bmp280.pressure)
    print("Altitude = %0.2f meters" % bmp280.altitude)
    time.sleep(2)

This is copied from the Adafruit website, with one modification: specifying the I2C
address of my BMP-280 module.  If your address you found is different from 0x76,
change the highlighted code to reflect your module address (0x77).

Now you should be able to run your program and get temperature and pressure readings:

$ python3 bmp280test.py

Temperature: 23.4 C
Pressure: 986.0 hPa
Altitude = 228.95 meters

Temperature: 23.4 C
Pressure: 986.0 hPa
Altitude = 229.17 meters
...

That's it, you have built a Raspberry Pi environment sensor.  

Check out my weatherPi project at SourceForge if you would like to see how to weave multiple sensors into a sensing network with data recording.

Comments

Popular posts from this blog

I2C Sensors Part Deux