I2C Inarduino
I2C Inarduino
I2C Inarduino
1|Page
Objectives
Study the serial communication between devices.
2|Page
Introduction
Part 1.1: I2C protocol overview
A typical embedded system consists of one or more microcontrollers and peripheral
devices like memories, converters, I/O expanders, LCD drivers, sensors, matrix switches, etc. The
complexity and the cost of connecting all those devices together must be kept to a minimum.
The system must be designed in such a way that slower devices can communicate with the
system without slowing down faster ones.
To satisfy these requirements a serial bus is needed. A bus means specification for the
connections, protocol, formats, addresses and procedures that define the rules on the bus. This
is exactly what I2C bus specifications define.
I2C combines the best features of other serial communication protocols like SPI and UARTs. With
I2C, you can connect multiple slaves to a single master and you can have multiple masters
controlling single, or multiple slaves. This is really useful when you want to have more than one
microcontroller logging data to a single memory card or displaying text to a single LCD.
Like UART communication, I2C only uses two wires to transmit data between devices (see Figure
1).
3|Page
Both signals (SCL and SDA) are bidirectional. They are connected via resistors to a positive power
supply voltage. This means that when the bus is free, both lines are high.
I2C is a serial communication protocol, so data is transferred bit by bit along a single wire (the
SDA line).
I2C is synchronous, so the output of bits is synchronized to the sampling of bits by a clock signal
shared between the master and the slave. The clock signal is always controlled by the master.
4|Page
Figure 2: I2C bit transfer
After the Start condition the bus is considered as busy and can be used by another master only
after a Stop condition is detected. After the Start condition the master can generate a repeated
Start. This is equivalent to a normal Start and is usually followed by the slave I2C address.
Microcontrollers that have dedicated I2C hardware can easily detect bus changes and behave
also as I2C slave devices. However, if the I2C communication is implemented in software, the bus
signals must be sampled at least two times per clock cycle in order to detect necessary changes.
5|Page
Figure 4: I2C data transfer
Figure 4 shows the data flow for the I2C on both SDA and SCL. Data on the I2C bus is
transferred in 8-bit packets (bytes). There is no limitation on the number of bytes, however, each
byte must be followed by an Acknowledge bit. This bit signals whether the device is ready to
proceed with the next byte. For all data bits including the Acknowledge bit, the master must
generate clock pulses. If the slave device does not acknowledge transfer this means that there is
no more data or the device is not ready for the transfer yet. The master device must either
generate Stop or Repeated Start condition. (see figure 5 for the timing of the acknowledgment
bit).
Each master must generate its own clock signal and the data can change only when the clock is
low. For successful bus arbitration a synchronized clock is needed. Once a master pulls the clock
6|Page
low it stays low until all masters put the clock into high state. Similarly, the clock is in the high
state until the first master pulls it low. This way by observing the SCL signal, master devices can
synchronize their clocks.
5. ARBITRATION:
For normal data transfer on the I2C bus only one master can be active. If for some reason two
masters initiate I2C command at the same time, the arbitration procedure determines which
master wins and can continue with the command. Arbitration is performed on the SDA signal
while the SCL signal is high. Each master checks if the SDA signal on the bus corresponds to the
generated SDA signal. If the SDA signal on the bus is low but it should be high, then this master
has lost arbitration. Master I2C device that has lost arbitration can generate SCL pulses until the
byte ends and must then release the bus and go into slave mode. The arbitration procedure can
continue until all the data is transferred. This means that in multi-master system each I2C master
must monitor the I2C bus for collisions and act accordingly.
7|Page
Figure 6: Full timing for the I2C data flow
If the master only writes to the slave device then the data transfer direction is not changed. (see
figure 7).
If the master only needs to read from the slave device then it simply sends the I2C address with
the R/W bit set to read. After this the master device starts reading the data. (see figure 8).
Sometimes the master needs to write some data and then read from the slave device. In such
cases it must first write to the slave device, change the data transfer direction and then read the
device. This means sending the I2C address with the R/W bit set to write and then sending some
additional data like register address. After writing is finished the master device generates
repeated start condition and sends the I2C address with the R/W bit set to read. After this the
data transfer direction is changed and the master device starts reading the data. (See figure 9).
8|Page
Figure 9: Master reads and writes to the slave device
9|Page
Figure 10: LM75B Config
Address (A2, A1, A0) Inputs. Sets the three least significant bits of the LM758–bit address. A match between the LM75’s
address and the address specified in the serial bit stream must be made to initiate communication with the LM75.
10 | P a g e
Procedure
Part 2.1: Writing the LCD to Arduino and I2C scanning
This display uses I2C communication, which makes wiring really simple.
Wire your LCD to the Arduino by following the schematic diagram in figure 11. We’re using the
Arduino default I2C pins (SCL and SDL).
11 | P a g e
Figure 11: I2c module connection between Arduino and LCD
GND GND
VCC VCC
SDA SDA
SCL SCL
Before proceeding with the project, you need to install the Arduino add-on in the Arduino IDE.
Follow one of the next guides to prepare your Arduino to use the LCD functions:
Installing the LiquidCrystal_I2C Library
12 | P a g e
There are several libraries that work with the I2C LCD. We’re using this library by Marco
Schwartz. Follow the next steps to install the library:
1. Click here to download the LiquidCrystal_I2C library. You should have a .zip folder in your
Downloads
2. Unzip the .zip folder and you should get LiquidCrystal_I2C-master folder
3. Rename your folder from LiquidCrystal_I2C-master to LiquidCrystal_I2C
4. Move the LiquidCrystal_I2C folder to your Arduino IDE installation libraries folder
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("\nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
nDevices++;
}
else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16) {
13 | P a g e
Serial.print("0");
}
Serial.println(address,HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
delay(5000);
}
After uploading the code, open the Serial Monitor at a baud rate of 9600. Press the Arduino
reset button. The I2C address should be displayed in the Serial Monitor. (like in figure 12).
In this case the address is 0x27, but it could be any other address. Write down the address of
your I2C module.
14 | P a g e
Part 2.2: Display static text on the LCD
Displaying static text on the LCD is very simple. All you have to do is select where you want the
characters to be displayed on the screen, and then send the message to the display.
Here’s a very simple sketch example that displays “Welcome TO BZU “.
#include <LiquidCrystal_I2C.h>
void setup(){
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
}
void loop(){
// set cursor to first column, first row
lcd.setCursor(0, 0);
// print message
lcd.print("Welcome TO");
delay(1000);
// clears the display to print new message
lcd.clear();
// set cursor to first column, second row
lcd.setCursor(0,1);
lcd.print("BZU”);
delay(1000);
lcd.clear();
}
It displays the message in the first row, and then in the second row.
In this simple code we show you the most useful and important functions from
the LiquidCrystal_I2C library. So, let’s take a quick look at how the code works.
15 | P a g e
How the code works
First, you need to include theLiquidCrystal_I2C library.
#include <LiquidCrystal_I2C.h>
The next two lines set the number of columns and rows of your LCD display. If you’re
using a display with another size, you should modify those variables.
Then, you need to set the display address, the number of columns and number of
rows. You should use the display address you’ve found in the previous step.
lcd.backlight();
To display a message on the screen, first you need to set the cursor to where you
want your message to be written. The following line sets the cursor to the first
column, first row.
lcd.setCursor(0, 0);
Note: 0 corresponds to the first column, 1 to the second column, and so on…
Then, you can finally print your message on the display using the print() method.
lcd.print("Welcome TO ");
Wait one second, and then clean the display with the clear() method.
lcd.clear();
After that, set the cursor to a new position: first column, second row.
lcd.setCursor(0,1);
Then, the process is repeated.
So, here’s a summary of the functions to manipulate and write on the display:
16 | P a g e
lcd.setCursor(intcolumn, int row): sets the cursor to the specified column and
row
lcd.print(message): displays the message or variable on the display
lcd.clear(): clears the display
This example works well to display static text no longer than 16 characters.
Our example will send data from slave to master. The data is characters starting from ‘0’ and
ending with ‘z’.
To run the codes:
1. Do the schematic in figure 13. (make sure to make the GND common).
2. Compile and upload the master code to the first Arduino.
3. Compile and upload the slave code to the second Arduino.
4. Open the serial monitor for the master (make sure to change it since the monitor could
be on the slave Arduino).
17 | P a g e
Master code:
// master side code
#include <Wire.h>
void setup()
void loop()
while(Wire.available())
delay(100);
Slave code:
// slave side code
#include <Wire.h
void setup()
void loop()
delay(100);
18 | P a g e
static char c = '0';
Wire.write(c++);
if (c > 'z')
c = '0';
}
Master code:
// master side code
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
void setup()
{
Wire.begin(); // join i2c bus (address optional formaster)
Serial.begin(9600); // start serial for output
Serial.print("master sleeping...");
delay(2000);
Serial.println("go");
19 | P a g e
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
}
void loop()
{
Wire.requestFrom(50, 2); // request data from slave device
#2
int res;//result from I2c reading
byte MSB = Wire.read(); /* receive a byte MSB(NOTE: the
function is blocking, so it would not continue the code until a
byte reach)*/
byte LSB = Wire.read(); /* receive a byte LSB(NOTE: the
function is blocking, so it would not continue the code until a
byte reach)*/
res = ((MSB << 8) | LSB);
Serial.print("MSB = ");
Serial.print(MSB);
Serial.print(" , LSB = ");
Serial.print(LSB);
Serial.print(" , analog value = ");
Serial.println(res); // print the analog value
// print message
lcd.print("Reading = ");
lcd.print(res);
delay(1000);
lcd.clear();
20 | P a g e
Slave code:
// slave side code
#include <Wire.h>
void setup()
{
Wire.begin(50); // join i2c bus with address #2
Wire.onRequest(requestEvent); // register event
Serial.begin(9600); // start serial for output
}
void loop()
{
delay(100);
}
Part 2.5. I2C communication between Arduino and Temperature sensor (LM75B)
In this part, we will see how we can make the communication between Arduino and LM75B sensor using I2C.
You have to test the following example for the LM75B temperature sensor. Note that the LM75B Address not
given and you have to find it using the theory information.
21 | P a g e