Arduino Microcontroller: How to Use I2C, SPI, and UART

The Arduino microcontroller is a versatile microcontroller, a true workhorse for many do it yourself projects. It has enough pins to connect several sensors and actuators. When building more complex system, you need to have a means for communicating with other microcontrollers or even single board computers.

In the last article, I explained the main protocols that are available on the Arduino and the Raspberry Pi: 1-Wire, I2C, SIP, UART. In this article, we will explore the libraries that are used to establish the connection with these protocols. Each library will be presented with its name, short description of its function, and a code example to get you up and running in minutes.

This article originally appeared at my blog.

I2C

The I2C protocol is the preferred protocol for interacting with other MCUs (for brevity I will use MCU to refer to both microcontrollers and single board computers). The Arduino IDE comes bundled with the Wire.h library.

Lets see an example. The following program starts an IC2 master node.

#include <Arduino.h>
#include <Wire.h>
#define IC2_CLIENT 0x23void setup() {
Wire.begin();
Serial.begin(9600);
}
void loop() {
Wire.beginTransmission(IC2_CLIENT);
Wire.write("Server Request");
Wire.endTransmission();
delay(3000);
}

The I2C client node will listen for incoming messages, and print them on the serial output.

#include <Arduino.h>
#include <Wire.h>
#define MY_I2C_ADDRESS 0x23void setup() {
Wire.begin(MY_I2C_ADDRESS);
Serial.begin(9600);
}
void loop() {
if (Wire.available()) {
char c = Wire.read();
Serial.print(c);
}
}

This is just a basic example. The library also provides a mean to define non-blocking handler methods that are executed when data is available. And there are also methods to govern how the server requests to read data from its connected clients.

SPI

SPI connections can be made with the official SPI library Spi.h. This library provides extensive configuration options that reflect the complexity of the SPI protocol. It starts with configuring the maximum connection speed for all devices, whether messages will be exchanged with MSB or LSB, and how the voltage levels of the Clock and Data Channels are set.

Let’s take a look at an example, inspired by the official example.

#include <Arduino.h>
#include <SPI.h>
#define CLIENT_SELECT_PIN = 10
#define CLIENT_REGISTER_ADDRESS = 0x10;
void setup() {
pinMode(CLIENT_SELECT_PIN, OUTPUT);
SPI.begin();
}
void loop() {
delay(1000);
writeToSpiClient(0x10, millis());
}
void writeToSpiClient(char& buffer, int value) {
delay(100);
SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));
SPI.transfer(buffer,value);
SPI.endTransaction();
digitalWrite(CLIENT_SELECT_PIN, HIGH);
delay(100);
}

The basic steps are:

  • Define the pin layout
  • Start the SPI server with SPI.begin()
  • Wrap any transaction in SPI.beginTransaction() and SPI.endTransaction()
  • Use SPI.transfer to send and receive data at the same time

UART

The final protocol is basic UART. Serial communication over the USB port always uses this protocol, and in addition, you can also wire another device using the RX TX Pins of the Arduino.

To open the UART connection, you need to define the baud rate, a technical term for the number of characters that can be send. Once established, you can read and write any character-based data.

The following program sends configures the baud rate to 9600. It will then send the "Hello UART" exactly one time to any connected client. Then, it will listen for any incoming data, and store it in a variable called msg.

#include <Arduino.h>
#include <stdbool.h>
string msg;
bool only_once = true;
void setup() {
Serial.begin(9600);
}
void loop() {
(if only_once) {
only_once = false;
Serial.send("Hello Client");
}
if (Serial.available()) {
char c;
while (c = Serial.read()) {
msg += c;
}
}
}

Conclusion

Connecting your Arduino to other MCUs can be done with three different protocols: I2C, SPI and UART. These protocols are implemented as libraries to handle the details of the individual protocols. To my surprise, each protocol is handled by a built-in library. Using them follows the same schema: Opening a connection, then begin the transmission (direct, or select the receiver first), and closing the connection. Which method you use depends on the available protocols of the connected device, and also which transmission speeds you need.

--

--

--

IT Project Manager & Developer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Sitecore 9 — Your new Business Ally

Cross-platform Mobile Development: Advantages and Risks

What is the Golden Ratio?

César de La Vega Rodríguez on Culture, Collaboration, and Constant Growth

All you need to be a software developer!!

Functional Programming is the ‘New Normal’

Reduce Cost and Increase Productivity with Value Added IT Services from buzinessware — {link} -

Game Logic -React/NodeJS/PostgreSQL

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sebastian

Sebastian

IT Project Manager & Developer

More from Medium

ESP32 : How to Use 16x2 LCD Display without I2C

CNC The Future

LIST OF POPULAR E-PAPER DISPLAY SUPPLIERS (MANUFACTURERS)

IS THERE A DAMN VIRUS ON YOUR COMPUTER?