What’s the deal with Raspberry Pi and Arduino Uno?
Well, they’re both microcontrollers, they’re both widely documented, and both ideal for beginners. Apart from that, they’re as different as The Flash and Judge Dredd.
The Raspberry Pi is a full-fledged microcomputer in its own right. It can run Linux, connect keyboards, monitors and USB sticks, connect to networks and the internet, even run a graphical desktop environment and perform server roles. You can use the Raspberry Pi as a development environment and program it in just about any language you like.
The Arduino Uno has a tiny fraction of the processing power and only runs programs written and compiled for it on another computer. Where it really excels is that it’s much more versatile with the range of electronic components it can interact with.
It supplies a higher voltage than the Raspberry Pi and can supply more current. Because it’s such a simple device, you work much closer to the metal. This gives you incredibly low-level control. It’s especially handy for interacting with analogue circuits.
The Raspberry Pi’s computational muscle and the Arduino Uno’s precision and I/O capabilities mean that together, they’re an excellent team. Happily, they both support the I2C serial protocol, which makes it super easy for them to communicate.
I2C stands for Inter-Integrated Circuit Protocol. This is a serial bus that allows communication in both directions. This protocol is designed for communication across short distances, within a device.
You can control hundreds of components using just two pins: the SDA (or serial data) pin and the SCL (or serial clock) pin.
It’s also a good idea to tie the ground pins together so that we’re sure the ground reference voltage is the same on each board. This doesn’t really count as a signal line, but it’s still a wire to connect.
Every slave device on the I2C bus requires a unique address, written in hexadecimal. In most implementations this is a 7-bit address space.
The ability to connect so many components to just 2 pins is I2C’s great advantage over other common serial protocols. UART only connects two components together; SPI can run any number of slaves but requires an additional pin on the master device for each one.
With I2C, you can even connect multiple masters, though they take it in turns to talk.
The trade-off for this is that everything on the bus shares a rather modest bandwidth, sometimes as low as 100kbit/s. That’s still a luxurious amount for I2C’s intended purpose of sending command and control messages, reading values from sensors and such.
To transfer files, stream media and so on, use a higher bandwidth serial bus protocol like SPI or USB.
The Raspberry Pi runs on 3.3-volts while the Arduino Uno runs on 5-volts. This means we have to take care in how we connect them.
It’s usually no problem to send a 3.3-volt signal to a 5-volt device. It certainly won’t damage it and, most of the time, this voltage is above the minimum threshold and will be detected as a high signal.
The trouble starts when you send a 5-volt signal to a 3.3-volt device like the Raspberry Pi. This can either fry it instantly or cause it to wear out very fast.
What makes this all much easier to manage is that when you use the Raspberry Pi as a master device, the Arduino Uno will use an open-collector output that uses the 3.3-volt pull-up resistor on the Raspberry Pi for the high signal. You could think of this as using the Raspberry Pi to control the Arduino.
Still, don’t take this to mean you can connect just about anything. Do your homework and make sure that nothing you connect will pull the voltage up to 5-volts. Use a bidirectional logic level converter if you need to.
Using I2C on the Arduino Uno is extremely simple – you just include the Wire library in your code and then connect the right pins.
The Arduino IDE comes with the Wire library installed and you can include it in your code with the following header:
#include<Wire.h>
The Raspberry Pi is a vastly more complicated device, so using I2C on it requires (slightly) more steps. First, it needs to be enabled in the configuration tool. At the command line, type:
sudo raspi-config
Select ‘Interfacing Options’ and then ‘I2C’. When it asks you whether you would like it enabled, select yes.
The Raspberry Pi actually has two I2C buses: I2C0 and I2C1. I2C1 is available for general purpose use and is the one we’re most interested in. We can see what’s connected to it by typing:
i2cdetect -y 1
Of course, you won’t see any I2C devices here because none are connected. Let’s do something about that.
If you’ve already got the Arduino IDE installed on another computer and would prefer to use that, you can skip this step.
First, update your operating system:
sudo apt update && sudo apt upgrade -y
Now install the Arduino IDE with the following command:
sudo apt install arduino -y
Connect the Arduino Uno and start the Arduino IDE. Type the following code into the IDE:
#include<Wire.h>
const int GreenLedPin = 6;
const int RedLedPin = 7;
void setup() {
//Join the I2C bus at address 0x8
wire.begin(0x8);
//When data is received, run the switchLed function below
wire.onReceive(switchLed);
//Setup pin 6 as an output pin for a green LED and turn it off
pinMode(GreenLedPin, OUTPUT);
digitalWrite(GreenLedPin, LOW);
//Setup pin 7 as an output pin for a red LED and turn it off
pinMode(RedLedPin, OUTPUT);
digitalWrite(RedLedPin, LOW);
}
//This function switches LEDs on and off when the Raspberry Pi sends a message
void switchLed(int bitstream) {
while (wire.available()) {
char c = wire.read();
switch (c) {
case 0x0:
digitalWrite(GreenLedPin, HIGH);
break;
case 0x1:
digitalWrite(GreenLedPin, LOW);
break;
case 0x2:
digitalWrite(RedLedPin, HIGH);
break;
case 0x3:
digitalWrite(RedLedPin, LOW);
}
}
}
void loop() {
delay(100);
}
Now press the play button to upload this program to the Arduino Uno. You may need to select a serial port first.
Unplug the Arduino Uno from the USB drive, and connect the Raspberry Pi’s SDA pin to the Arduino Uno’s A4 pin, and the Raspberry Pi’s SCL pin to the Arduino Uno’s A5 pin.
Then connect the ground pins together and connect the 5-volt pin on the Raspberry Pi to Vin on the Arduino Uno.
When you connect the power, the lights on the Arduino Uno should start blinking. Now run this command on the Raspberry Pi again:
i2cdetect -y 1
This time a device should be visible at 0x08, the address we assigned to the Arduino Uno.
That sketch we uploaded to the Arduino Uno doesn’t just connect it. It also tells it to switch LED lights on and off when it receives a message to do so. Right now, it’s just waiting to be told!
First, connect a ground pin from the Raspberry Pi to the negative power rail at the top of the breadboard.
Now put a green and a red LED on the breadboard. LEDs need to be wired the correct way around, so be sure the anode (the longer leg) is on the right.
LEDs should always be wired in series with some kind of resistor, otherwise they will pull too much current. So, connect a 680 Ohm resistor to the cathode (the shorter leg on the left) of each LED. If you don’t have 680 Ohm resistors, a similar value will do.
Now connect the anode of the green LED to pin 6 of the Arduino Uno and the anode of the red LED to pin 7. Connect the other leg of each resistor to the negative power rail to close the circuit.
Now we’re ready to start switching these LEDs on and off using I2C.
On the Raspberry Pi, open the Python interpreter by typing:
python3
To start interacting with the I2C bus, we want a class called SMBus from a module called smbus (without the capitals). Let’s import it.
from smbus import SMBus
Now let’s declare a variable with the Arduino Uno’s I2C address and declare an object from the SMBus class.
arduino = 0x8
i2cbus = SMBus(1)
We could just pass hex codes to the I2C bus and they would work, but that’s a rather awful way of keeping track of what they do. Let’s give them useful names.
greenOn = 0x0
greenOff = 0x1
redOn = 0x2
redOff = 0x3
Now we can use the write_byte method to switch the LEDs on and off, like this:
i2cbus.write_byte(arduino, greenOn)
i2cbus.write_byte(arduino, greenOff)
If you’ve wired everything correctly, the green LED should switch on and off.
Try it with the red LED too!
This is a trivial example. Both the Raspberry Pi and the Arduino Uno are perfectly capable of switching LEDs on and off on their own.
Where the Raspberry Pi really struggles is with interacting with analogue circuits. Coming up next, we’ll be exploring how to use the I2C protocol to get the Arduino Uno to both send and read analogue voltages for the Raspberry Pi.
Stay tuned!