I2C bus on Raspberry PI made easy.

 

Suppose you want to learn how to measure temperatures (or other variables) at many different locations using a Raspberry Pi (from now on written as rPi) and an i2c bus.

This article describes how to do so. I myself am not an expert and I noticed, that you can get an enormous amount of help on the internet, but it takes quite some time to filter out the help for experts (which I’m not and which I don’t understand) and the help that is wrong and does not give the desired results.

I will describe here the steps that make sense in a logical order, and explain why the specific steps bring the desired results.

The chapters are the order in which to take the steps. So the table of content is also a kind of a flow chart. You can use the table of content to jump to the desired chapter. People already more or less familiar to the rPi can skip the rPi part.

 

Table of content.

 

I2C bus on Raspberry PI made easy. 1

Table of content. 1

The rPi 1

Preparing the rPi for “general” use. 2

Some Linux commands you have to know. 2

Some Python commands. 2

Preparing the rPi for i2c. 2

Finding the right pins on your GPIO.. 3

The i2c device. 4

Identifying the i2cboard. 5

Reading the temperature of the SMT172 sensor. 5

Adding a second sensor to the i2c bus. 6

An i2cbus with two sensors. 7

Finally. 8

 

The rPi

If you buy a brand new rPi (including a power supply and a SD card) it is clean and will only work for you after you installed the necessary software on it. The software is installed on the SD card and you need to prepare the SD card using a “regular” PC. I used a combination of standard Raspbian Linux (the operating system for the rPi) commands and Python (an easy to master programming language for writing programs in a Linux environment). For this instruction I’m using the Raspberry Pi 3 Model B+. In the case you are using an older or different model, most of the times you can figure out how to deal with the differences.

Preparing the rPi for “general” use

If you are an experienced rPi user I suggest you will skip this part.

To get the software you best download “NOOBS” (New Out Of the Box Software) from the internet. By doing so you have the latest update and the same basis as I use in this instruction. Follow the instructions you find on the website from which you downloaded NOOBS. And most probably you will end up with a working rPi.

 

Some Linux commands you have to know.

In this instruction I will use a number of Linux commands and if you don’t know anything of Linux here you will have a handicap and they will need to spend some time to master the basic Linux commands. On the other hand there are a number of sites that are of great help and once you start asking help on the internet you can find a lot of answers. Sites that were very helpful to me were:

Basic-Linux-commands-for-beginners

Ten most important Linux commands

And a very useful online tutorial

Learn the Linux command line

 

Some Python commands

Because the programs I am using in this tutorial are written using the Python programming language you will have to learn more about Python. There are a number of Python commands you have to learn. I found the following sites useful:

Learn Python programming

Wikipedia summary of Python commands

Head start with Python Basics

 

When working in the Linux environment I’m using Nano as text editor, in the Windows environment I’m using Notepad (initially worked with Notepad++ but this gave indenting errors, so I switched to the simple Notepad). Some people are satisfied with Notepad++ after changing the settings (Settings > Preferences > MISC. > Auto-Indent (checkbox))

 

Once you have been studying above mentioned suggestions and sites, most probably you will be capable of following the rest of the more specific instructions om i2c and our specific i2c temperature sensor.

 

Preparing the rPi for i2c

 

OK by now you are more or less familiar with the rPi and Python. Now we are getting more specific.

First of all you have to make sure your rPi can handle the i2c information. To get there go to the command prompt in the Linux environment and type the Linux command: sudo raspi-config .

You will get a menu something like

Scroll to the desired options (here nr 5 Interfacing options) and from there choose the page the option P5 (or equivalent on your rPi).

The rPi will ask if you really want this, reassure it and go on until you can click <Finish>.

Check if the i2c bus is operational. To do so give the following Linux command: lsmod | grep i2c_

If the answer is something like the screenshot below, the i2c bus options are available in your rPi

The next thing is to get the i2c tools, for the rPi to handle the signals.

Give the following Linux command: sudo apt-get install i2c-tools

The reaction of your rPi will be to get the latest update from the internet.

Once this is done you have to reboot your rPi in order to get everything operational. The most easy way is to give the Linux command: sudo reboot now

By now you rPi is ready to handle i2c signals.

Without connecting an i2c device to you rPi the following Linux command: i2cdetect -y 1 (for older rPi models this command might be: i2cdetect -y 0)

This will give the following information:

 

This means your rPi is ready to read the i2c bus.

 

Finding the right pins on your GPIO

Now that your rPi is ready to handle i2c bus information you have to detect where and how to connect the bus. With the Linux command: pinout

If you have installed Raspbian Lite, you might not have pinout installed already. You will need to install it separately for your device (there are different versions for rPi and rPi zero).

You will get the layout of your specific rPi. It looks in my case like:

As mentioned by the rPi more information is to be found on https://pinout.xyz

As you can see  each pin has two number names. The board numbers (logical  1,2,3,4 etc) and functional names (5V, 3V3, GPIO2 where GPIO stands for General Purpose Input Output).

 

Very important here is to know that for the i2c bus GPIO2 is the SDA (Serial Data connection) and GPIO3 is the SCL (Serial Clock connection). An i2c bus works with four (4) wires 5Volt, GND, SDA and SCL0. On my rPi I connect them on the board pins 4,6,3 and 5 respectively.

Now that we know this we are ready to start with our i2c device.

 

The i2c device

For the i2c device I have chosen the “SMT172 to I2C INTERFACE BOARD” by Smartec. The reason is simple: The SMT172 is the best temperature sensor in the world and available in a wide variety of housings. On top of that they have an excellent i2c interface board and pricing is reasonable (certainly when one realises the performance of these components). They can be used in temperatures from -40 till +150 ˚C. For my purposes this temperature range is perfect, so I have chosen for the Smartec stuff.

It looks like as shown in the picture, is easy to use and gives perfect results. You only have to make it work. The wiring diagram of this interface board is as given here:

The SMT172 has a pinout of GND (0-Volt), VDD (3.3 Volt) and PWM (Pulse Width Modulation) and has to be connected as indicated to the interface board. The output of the interfaceboard to the rPi has 4 wires GND (0 Volt), Vin (5 Volt) SCL (Serial Clock) and SDA (Serial Data). The standard colours of these wires are: GND Black to pin 6 of the rPi, Vin Red to pin 2 or 4 of the rPi, SDA Green to pin 3 of the rPi SCL White to pin5 of the rPi.

So from the side that has the sensor itself it’s wired like this:

 

 

In the picture you can see how I made the connections.

 

Identifying the i2cboard.

Once connected, you can run i2cdetect -y 1 and you will see the following screen print:

 This means that the SMT172 to i2c board has two addresses 6f and 73. Here something specific about this board. The 6f address is called the primary address (PDA) and is there for the manufacturer for testing purposes. You can use it if you want but all SMT172 to i2c boards have this address, so the 6f address is not specific for the board you want to call. For calling you should use the secondary address. We will use this knowledge later on.

 

Reading the temperature of the SMT172 sensor.

Now that your SMT172 to i2c board is connected you can read the temperature of the sensor using the following Python program: one_Tsensor_i2c.py.

To create this Python program in Linux, go to the directory, where you want the program and give the Linux command: nano one_Tsensor_i2c.py. You will get the Python editor and you might copy paste the program below in the editor. Be aware that with copy-paste you might loose the correct indents, so check on it!

Once you have edited the program  with the Linux command: python one_Tsensor_i2c.py

It reads as:

 

#!/bin/py

import smbus

from time import sleep

import sys

bus = smbus.SMBus(1)

pda = 0x6f

# 0x6f is primary device address.

# never use this as an i2c bus address, as all devices have this address and it does not make the component unique.

sda = 0x73

# use this address to identify the sensor

while True:

        try:

                a = bus.read_byte_data(sda, 0)

                b = bus.read_byte_data(sda, 1)

                c = bus.read_byte_data(sda, 2)

                temp = a*2**16 + b*2**8 + c-273150

                temp1 = temp/1000.0

                print ('De temp = %0.2f' %temp1),'C'

                sleep(1)

        except KeyboardInterrupt:

                  # KeyboardInterrupt is ctrl + C

                print 'OK folks we stopped measuring temperatures'

                  sys.exit()

 

 

The screenshot in the rPi looks like:

 

And the output like:

 

 

If you get an error message about smbus not being available you should install that.

 

Adding a second sensor to the i2c bus

Before we can add the second sensor we have to give the first sensor its unique (secondary) address. If the sensor is new by factory settings it will have 0x6f as primary address and 0x73 as secondary address. This (second) address has to be changed.

We can do so by using the  following Python program: assignsecaddress.py.

(Use the commands: nano assignsecaddress.py and python assignsecaddress.py)

It reads as:

 

#!/bin/py

import smbus

from time import sleep

a = input ('give the desired sec address of the i2csmt172 device in 0x.. format   ')

#With the value of a the desired secondary address is determined

bus = smbus.SMBus(1)

pda = 0x6F  

#  0x6f =  primary device address, never use this as identidyer on the i2c bus

sda = a

# a =  secondary device address given by the user

sda_write_value = sda * 2

#create secondary address

bus.write_byte_data(pda, 10, sda_write_value)  

bus.write_byte_data(pda, 11, sda_write_value)  

#write copy

print 'SDA written=', (sda, 'in hex' , hex(sda))

#Even if the input by 'a' is given in decimals, the output is given in hex

print 'Check this with i2cdetect -y 1 or  i2cdetect -y 0'

 

The screen-print of this program is:

The program will ask you to give the desired i2c address you want to give to this specific sensor. Preferably you give it in hex format, as this is the format later on used in the programs.

So when the program asks “give the desired sec address of the i2csmt172 device in 0x.. format” also write down the 0x part. For example 0x70.

 

The program suggests to check the address given and if you do so it will give the following result

 

As you can see in the screenshot we ran the assignsecaddress.py program. The program asked for the desired address (0x70) it confirmed 0x70 was written and the i2cdetect -y 1 command showed everything is working as intended.

 

An i2cbus with two sensors

By now we have two sensors. One with the 0x73 secondary address and one with the 0x70 secondary address. And now we can see the big advantages of the i2c bus.

Connecting both sensors on the bus (5V is red, 0V is black, SDA is green and SCL is white) we can read both sensors by running the following Python program: <two_Tsensor_i2c.py.>

It reads as follows:

 

#!/bin/py

import smbus

from time import sleep

import sys

# Check with command <i2cdetect -y 1> or i2cdetect -y 0> whether your rPi use bus 1 or bus 0.

# in our case it uses bus 1.

# If both fail your rPi is not yet ready for handling the i2c bus data.

# Use the commands <sudo raspi-config> and <sudo apt-get install i2c-tools> to correct this

bus = smbus.SMBus(1)

# pda = 0x6f

# 0x6f primary device address, don't use it as an i2cbus address

sda1 = 0x73

sda2 = 0x70

while True:

                try:

                               a = bus.read_byte_data(sda1, 0)

                               b = bus.read_byte_data(sda1, 1)

                               c = bus.read_byte_data(sda1, 2)

                               temp = a*2**16 + b*2**8 + c-273150

                               temp1 = temp/1000.0

                               a = bus.read_byte_data(sda2, 0)

                              b = bus.read_byte_data(sda2, 1)

              c = bus.read_byte_data(sda2, 2)

                              temp = a*2**16 + b*2**8 + c-273150

              temp2 = temp/1000.0

                               print ('Temp1  = %0.2f' %temp1), ('Temp2 %0.2f' %temp2), 'C'

                               sleep(1)

                except KeyboardInterrupt:

                # Keyboard interrupt = ctrl+C

                               print 'OK folks. We stopped measuring temperatures.'

                               sys.exit()

Again, be aware, that with copy paste the indent might change and you have to check on this.

 

The screenshot  looks like:

 

And the output like:

 

N.B. you might notice, that sensor 2 is about 1.5 ˚C higher than sensor 1. Reason is, it is about 30 cm closer to me (a heat source) then the other. This shows how sensitive these sensors are, but what can you expect from the best sensors in the world 😉.

 

Finally

Now that we have two sensors up and running, it is a piece of cake to get more sensors to the bus.

The steps are:

Give each sensor its unique secondary address for this bus, using <assignsecaddress.py>

Expand the program <two_Tsensor_i2c.py> to the desired number. In this example it expanded it to 5 sensors, so I called it <five_Tsensor_i2c.py>

 

#!/bin/py

import smbus

from time import sleep

import sys

# Check with command <i2cdetect -y 1> or i2cdetect -y 0> whether your rPi use bus 1 or bus 0.

# in our case it uses bus 1.

# If both fail your rPi is not yet ready for handling the i2c bus data.

# Use the commands <sudo raspi-config> and <sudo apt-get install i2c-tools> to correct this

bus = smbus.SMBus(1)

# pda = 0xf. Dit is het primaire address, dat door de fabrikant gebruikt wordt om te testen. Gebruik dit adsress niet

sda1 = 0x70

sda2 = 0x73

sda3 = 0x74

sda4 = 0x75

sda5 = 0x76

while True:

        try:

 

                # temp1 op 0x70

                a = bus.read_byte_data(sda1, 0)

                b = bus.read_byte_data(sda1, 1)

                c = bus.read_byte_data(sda1, 2)

                temp = a*256**2 + b*256 + c-273150

                temp1 = temp/1000.0

                # temp 2 op 0x71

                a = bus.read_byte_data(sda2, 0)

                b = bus.read_byte_data(sda2, 1)

                c = bus.read_byte_data(sda2, 2)

                temp = a*256**2 + b*256 + c-273150

                temp2 = temp/1000.0

                # temp 3 op 0x72

                a = bus.read_byte_data(sda3, 0)

                b = bus.read_byte_data(sda3, 1)

                c = bus.read_byte_data(sda3, 2)

                temp = a*256**2 + b*256 + c-273150

                temp3 = temp/1000.0

                # temp 4 op 0x73

                a = bus.read_byte_data(sda4, 0)

                b = bus.read_byte_data(sda4, 1)

                c = bus.read_byte_data(sda4, 2)

                temp = a*256**2 + b*256 + c-273150

                temp4 = temp/1000.0

                # temp 5 op 0x74

                a = bus.read_byte_data(sda5, 0)

                b = bus.read_byte_data(sda5, 1)

                c = bus.read_byte_data(sda5, 2)

                temp = a*256**2 + b*256 + c-273150

                temp5 = temp/1000.0

                print ('Temp1 %0.2f' %temp1), ('Temp2 %0.2f' %temp2),('Temp3 %0.2f' %temp3),('Temp4 %0.2f' %temp4),('Temp5 %0.2f' %temp5),'C'

                sleep(1)

        except KeyboardInterrupt:

        # Keyboard interrupt = ctrl+C

                print 'Thats all for the moment'

                sys.exit()

 

The screenshot of the program is:

 

 

 

And the output looks like:

 

Once you can address and read five sensors, you feel like an expert. Have fun.