I2C or Inter-Integrated Circuit, is a really handy communication protocol that can be used to connect over 100 devices together with only 2 wires! In this video we will dive into that a little by taking a look at the uses of I2C, how to wire up multiple I2C devices, and taking a look at an I2C OLED module, an incredibly helpful device that can be added to any project.

Transcript

I2C is the last but certainly not the least protocol on our list. It only uses two wires, one for a clock signal to keep everything in sync like SPI, and one to send data between devices. But with only these two wires, you can connect a ridiculous amount of devices together. When using SPI, you're probably only going to be connecting two to maybe eight devices together, usually single-digit numbers. But I2C can connect over 100 devices with just two wires. Now you're probably not ever going to connect that many devices together, but if you had to connect six or so devices together, I2C is going to be far easier than SPI.

Like SPI, it also uses the controller target terminology. Your Pico will most likely be the controller, and the modules that you plug into it will be the targets. Now you will probably hear the term bus thrown around in COM protocols, especially with I2C. And a bus is just kind of a connection or a pathway that data is sent along. And so I might say that on my I2C bus, I have a Pico connected as a controller and some sensors connected as targets. It's just some helpful terminology to know that you might just get randomly thrown at you.

One of the downsides to I2C is that it is only half duplex. And what this means is that only one device can talk at a time on the bus. Two devices can't send and receive data at the same time. It's kind of like walkie-talkies where only one person can speak at a time, and if two people speak at once, their voices get muddled together and you can't understand anything. This just means that devices have to take turns talking to each other. That's all handled by the library. You don't have to worry about it. And a lot of the data transfer on I2C happens so fast that it basically seems like they're talking to each other at the same time.

Alright, let's jump into a demo and hook up some I2C modules. We are running into an issue again here where a lot of this is very library-dependent and a lot of the I2C setup is done behind the scenes with a library. To show you the process of using some I2C devices, I think we'll just make a little thing where we'll connect some sensors together and connect the display and just show that sensor data on that screen. So we're going to get started by connecting this very generic OLED display to our Pico. These are just tiny little black-and-white screens. They're really low-power and they're a really great addition to any project. So our display has four pins here, two on the left are for power and then we've got our serial clock and our serial data or SCL and SDA and these are our I2C wires. You connect SDA of your device to SDA of the Pico and SCL to SCL. It's really straightforward.

Now like you want an SPI, the Pico has two peripheral devices that we can use, I2-0 and I2-1 and there is a whole bunch of ways and different pins that we can use to access them. In fact, nearly every single GPIO pin on the Pico can access one of the I2C peripherals. For this example though, we will be using pins 8 and 9 because that's what the library we will be using needs. And if your library doesn't let you choose the pins, you'll need to check which ones it uses by default. So we're going to plug SDA into the Pico's SDA pin, which is pin 8, and plug SCL into pin 9, which is the SCL pin of the Pico. And then we're just also going to connect it to ground and the 3.3 Volts out because this is a 3.3 device and that's it. That's how easy it is to wire up an I2C device.

This OLED display we're using is just a really generic one. It's called the SSD-1306. It's really common and first we're going to need to find a library to drive it and some sample code. So I've just gone ahead to the product page here and I found the sample code and a link to the library on GitHub. Sweet. And I've gone ahead and it looks like to install this, we're going to need SSD-1306.py. I'm just going to go to here and then I'm going to download that file. We're going to plug it in first, that might help. And then I'm just going to go ahead into our libraries folder and I'm going to upload that to our libraries on our board. Sweet. So just as a starting point, I'm going to copy over the sample code from the documentation into our Thonny script and I'm just going to run it and we can see that we are printing Hello World on our display. And just taking a look at the code, it looks like we set up our library there, then we import time and then we import pin and I2C, which we use to set up our I2C peripheral down here. And this demo code declares the pins here as variables and then feeds them into here. But I'm not a big fan of that as this is just personal preference here, but I'm just going to change this to set it all up in one line instead. We can now delete them. And if I copy that into here, I'm basically just directly putting the number in instead of declaring the variable and then feeding that variable. And I just like it this way. It's all in one line and it's nice and neat. And the way these OLEDs work is that first we need to completely wipe everything off the screen with this OLED fill, zero fills it with just black pixels. And then the OLED.text is going to write text on it. And it looks like we've got an X and a Y coordinate here of where to actually place that on the screen. And then when we call OLED show, we push that change and we kind of update the display with what we've written on it. And something we're going to do preemptively here is I'm just going to add a while true loop here and set all of that inside of it like so. And if I run that, we can see that it's still printing Hello World.

Next we're going to connect this atmospheric sensor module, which will allow us to read temperature, humidity, and pressure. Now we could solder some pins onto the board here and connect it like we did with the OLED. But this module gives us an option to use a nice and convenient connector that we can use to plug it in like so. And this connection gives us our power pins and our I2C pins to plug in. And it is exactly the same process. We're going to plug our SDA into the SDA of the Pico and the SCL into the SCL of the Pico and then plug that into zero volts of ground and 3.3 volts. And that should power up. Like so. We've got a little LED status there. Now let's say we wanted to plug in another sensor. We are kind of running out of space on our breadboard here, but this sensor is part of the same PiicoDev ecosystem as this sensor, and it shares the same connector.This sensor is connected to the same I2C as this LED module and this sensor and that sensor. They're all sharing the same bus. Both of these sensors are part of the PiicoDev ecosystem, which is just a series of I2C devices that we make in-house here. And if you've got something like this PiicoDev adapter, you could go one step more convenient and place your Pico into it like so, and then just daisy-chain them, if I plug that in, daisy-chain them all off like so, without having to plug anything in. And each big brand like Adafruit and Seed Studio and Sparkfun have their own ecosystem of connectors that can be used like this to really easily put everything together. So I2C devices, you probably have a few different ways of wiring them up, but as long as they're all connected together, it doesn't matter which way you use.

Now let's get this atmospheric sensor going. And it's basically the same process of find a library, find some sample code and adapt the sample code to your needs. So I've gone ahead to the documentation page and seen that I need to download these two libraries here like so. And then I'm going to upload them to our libraries folder on the Pico like so. And then I'm just going to go ahead here and look for this sample code. And looking at this, it looks like this is a very important one because we're importing the library. And then here it looks like they're importing Sleep MS from the unified library instead of the time library like we usually do. So I don't think we're going to need Sleep MS, so we'll just leave it there. Then we set up our sensor or initialize it with that. That looks very important. Here it looks like they're getting an initial altitude reading for something that we're not going to use. So we'll skip it. And here it looks like we have the beef of our code, which is actually reading the sensors. And we'll just paste that in there like so inside of our while true loop. We'll close that, give us a bit more room. And here it looks like we're just converting our pressure and then we're printing it and the rest. I don't think we'll need any of that. So back in our code, we'll just run it to make sure that everything is working and it seems all right.

Now we're going to modify it to start printing that data. So to start with, I'm just going to shift this over a little bit like so. I'm just going to kind of position it there. I'm just trying to lay everything out here so it's nicely put and laid out on the screen. And then here I'm going to print our first value, which is temp C, and I'm just going to shift it over maybe a little bit like so, just across the screen. And before that, we're just going to print temp. And if we run that, we can see that we need to convert it to a string first because this can't take a float. Run that. And we can now see that we are printing out our temperature on our OLED display. And here we've gone the first string, which is temp, and the second string, which is just printing out that variable, but converting it to a string first. And the rest of this looks pretty straightforward. All I'm going to do is copy and paste that a few times like so. And then this one, I'm going to say pressure is something. And this one, I'm going to say humidity is something, and I'm just going to change where these are positioned. I'll move this one a few pixels down, and then I'll move this one a few more pixels down like so. Oh, and I nearly forgot, we need to actually update our variables. So here I'm going to print the pressure like so, and then here I'm going to print the humidity like so. And if we run that, we can now see that we are printing out our values on our OLED screen. And we are achieving quite a lot quite easily, if you think about it. A few lines of copy and pasted code, and we're reading a whole bunch of sensor data and printing it on an OLED display. We've built kind of like a nice little weather station here. If you wanted to take this even further, you could draw some lines and make some, I don't know, like a nice little UI design, or repeat this process and add some more I2C devices. You could control some RGB LEDs, or maybe add an ultrasonic sensor, or control some servos, or even add some motion detection with an accelerometer, or I don't know, even add a compass to it. There is a crazy amount of things that you can find that use I2C, and it's really easy to daisy-chain them together like we have here, especially when they're from the same ecosystem.

Let's end this video by talking about I2C addresses, because it's pretty darn important. Every target device that we connect to an I2C bus must have a unique identifier known as an address. When you purchase a module, it will come with that address already assigned to it, and the address is just a number in hexadecimal format. So you might see 0X1B, or 0X25, or 0X1A. Just for example, we won't be going into hexadecimal, it's just a different way of counting numbers. You just need to know that these are addresses of the devices. So when our Pico here sends information, it sends it to every single thing on the bus, so both the display and this sensor here receive that message. And this is where I2C gets really clever. In that message, it also sends the address of the device that it's trying to actually send the message to. So if the sensor receives a message, but it is addressed to the display, it's just going to ignore it. And that's how we can have so many devices talking only over two wires. They use this addressing system to choose who to communicate with. But this means that there can't be a doubling up of addresses. Two devices can't share the same address, or this system won't work. Now if I bought another one of these displays, chances are it's going to come with the same address as the other display, and it won't work. And the problem is, is that these addresses are kind of hardware bound. You can't just go into the software and change their address. If you're lucky though, your device will probably have these solder terminals on the back. If you desolder this resistor and moved it over, you can change the address of this device. So on this one, you can have two separate addresses and have two devices on the same I2C bus. If you're even luckier, your device might have some switches on it like this servo driver does.This one allows us to change the address based on the positions of the switch. It's way more convenient than having to desolder and resolder a little resistor. If you're still out of luck after these options, you can find an I2C multiplexer. We won't be covering it in this video, but it will allow you to use multiple devices with the same address, just in case you're in a real pickle there.

All of this is leading to an important thing. Before you purchase modules for your project, check the I2C addresses and make sure that you won't have any address conflicts, or that you can at least change the address of some devices to avoid it.

Three key takeaways:
1. I2C is a communication protocol that allows you to connect many devices together with only two wires.
2. When using a device, you always connect SCL to SCL and SDA to SDA, and you'll probably need to use a library to interact with it.
3. Each device on an I2C bus must have a unique address, and there may be ways to change a device's address.

Comments


Loading...
Feedback

Please continue if you would like to leave feedback for any of these topics:

  • Website features/issues
  • Content errors/improvements
  • Missing products/categories
  • Product assignments to categories
  • Search results relevance

For all other inquiries (orders status, stock levels, etc), please contact our support team for quick assistance.

Note: click continue and a draft email will be opened to edit. If you don't have an email client on your device, then send a message via the chat icon on the bottom left of our website.

Makers love reviews as much as you do, please follow this link to review the products you have purchased.