This article was revised on 2021/11/18 by Karl Sƶderby.
The I2C protocol involves using two lines to send and receive data: a serial clock pin (SCL) that the Arduino Controller board pulses at a regular interval, and a serial data pin (SDA) over which data is sent between the two devices. As the clock line changes from low to high (known as the rising edge of the clock pulse), a single bit of information - that will form in sequence the address of a specific device and a command or data - is transferred from the board to the I2C device over the SDA line. When this information is sent - bit after bit -, the called upon device executes the request and transmits it's data back - if required - to the board over the same line using the clock signal still generated by the Controller on SCL as timing.
Because the I2C protocol allows for each enabled device to have it's own unique address, and as both controller and peripheral devices to take turns communicating over a single line, it is possible for your Arduino board to communicate (in turn) with many devices, or other boards, while using just two pins of your microcontroller.
Please note that the I2C bus is attached to different pins depending on the board you are using. For example, the pins used for MKR WiFi 1010 are D11, D12, while the pins for UNO are D18, D19. See the image below to understand how to locate the correct pins on your board.
Check out the following tutorials to get a more detailed step-by-step on how to use I2C on Arduino boards:
While the above tutorials were written specifically for the Nano Family boards, they can be adopted to any Arduino board.
In some situations, it can be helpful to set up two (or more!) Arduino boards to share information with each other. In this example, two boards are programmed to communicate with one another in a Controller Reader/Peripheral Sender configuration via the I2C synchronous serial protocol. Several functions of Arduino's Wire Library are used to accomplish this. Arduino 1, the Controller, is programmed to request, and then read, 6 bytes of data sent from the uniquely addressed Peripheral Arduino. Once that message is received, it can then be viewed in the Arduino Software (IDE) serial monitor window.
1// Wire Controller Reader2// by Nicholas Zambetti <http://www.zambetti.com>3
4// Demonstrates use of the Wire library5// Reads data from an I2C/TWI peripheral device6// Refer to the "Wire Peripheral Sender" example for use with this7
8// Created 29 March 20069
10// This example code is in the public domain.11
12
13#include <Wire.h>14
15void setup() {16 Wire.begin(); // join i2c bus (address optional for master)17 Serial.begin(9600); // start serial for output18}19
20void loop() {21 Wire.requestFrom(8, 6); // request 6 bytes from peripheral device #822
23 while (Wire.available()) { // peripheral may send less than requested24 char c = Wire.read(); // receive a byte as character25 Serial.print(c); // print the character26 }27
28 delay(500);29}
1// Wire Peripheral Sender2// by Nicholas Zambetti <http://www.zambetti.com>3
4// Demonstrates use of the Wire library5// Sends data as an I2C/TWI peripheral device6// Refer to the "Wire Master Reader" example for use with this7
8// Created 29 March 20069
10// This example code is in the public domain.11
12
13#include <Wire.h>14
15void setup() {16 Wire.begin(8); // join i2c bus with address #817 Wire.onRequest(requestEvent); // register event18}19
20void loop() {21 delay(100);22}23
24// function that executes whenever data is requested by master25// this function is registered as an event, see setup()26void requestEvent() {27 Wire.write("hello "); // respond with message of 6 bytes28 // as expected by master29}
In some situations, it can be helpful to set up two (or more!) Arduino boards to share information with each other. In this example, two boards are programmed to communicate with one another in a Controller Writer/Peripheral Receiver configuration via the I2C synchronous serial protocol. Several functions of Arduino's Wire Library are used to accomplish this. Arduino 1, the Controller, is programmed to send 6 bytes of data every half second to a uniquely addressed Peripheral. Once that message is received, it can then be viewed in the Peripheral board's serial monitor window opened on the USB connected computer running the Arduino Software (IDE).
1// Wire Master Writer2// by Nicholas Zambetti <http://www.zambetti.com>3
4// Demonstrates use of the Wire library5// Writes data to an I2C/TWI Peripheral device6// Refer to the "Wire Peripheral Receiver" example for use with this7
8// Created 29 March 20069
10// This example code is in the public domain.11
12
13#include <Wire.h>14
15void setup()16{17 Wire.begin(); // join i2c bus (address optional for master)18}19
20byte x = 0;21
22void loop()23{24 Wire.beginTransmission(4); // transmit to device #425 Wire.write("x is "); // sends five bytes26 Wire.write(x); // sends one byte 27 Wire.endTransmission(); // stop transmitting28
29 x++;30 delay(500);31}
1// Wire Peripheral Receiver2// by Nicholas Zambetti <http://www.zambetti.com>3
4// Demonstrates use of the Wire library5// Receives data as an I2C/TWI Peripheral device6// Refer to the "Wire Master Writer" example for use with this7
8// Created 29 March 20069
10// This example code is in the public domain.11
12
13#include <Wire.h>14
15void setup()16{17 Wire.begin(4); // join i2c bus with address #418 Wire.onReceive(receiveEvent); // register event19 Serial.begin(9600); // start serial for output20}21
22void loop()23{24 delay(100);25}26
27// function that executes whenever data is received from master28// this function is registered as an event, see setup()29void receiveEvent(int howMany)30{31 while(1 < Wire.available()) // loop through all but the last32 {33 char c = Wire.read(); // receive byte as a character34 Serial.print(c); // print the character35 }36 int x = Wire.read(); // receive byte as an integer37 Serial.println(x); // print the integer38}
This example shows how to read a Devantech SRFxx , an ultra-sonic range finder which communicates via the I2C synchronous serial protocol.
Attach the SDA pin of your SRFxx to analog pin 4 of your board, and the SCL pin to analog pin 5. Power your SRFxx from 5V, with the addition of a 100uf capacitor in parallel with the range finder to smooth it's power supply.
If using two SRFxxs on the same line, you must ensure that they do not share the same address. Instructions for re-addressing the range finders can be found at the bottom of the code below.
1// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder2// by Nicholas Zambetti <http://www.zambetti.com>3// and James Tichenor <http://www.jamestichenor.net>4
5// Demonstrates use of the Wire library reading data from the6// Devantech Utrasonic Rangers SFR08 and SFR107
8// Created 29 April 20069
10// This example code is in the public domain.11
12#include <Wire.h>13
14void setup() {15
16 Wire.begin(); // join i2c bus (address optional for master)17
18 Serial.begin(9600); // start serial communication at 9600bps19}20
21int reading = 0;22
23void loop() {24
25 // step 1: instruct sensor to read echoes26
27 Wire.beginTransmission(112); // transmit to device #112 (0x70)28
29 // the address specified in the datasheet is 224 (0xE0)30
31 // but i2c addressing uses the high 7 bits so it's 11232
33 Wire.write(byte(0x00)); // sets register pointer to the command register (0x00)34
35 Wire.write(byte(0x50)); // command sensor to measure in "inches" (0x50)36
37 // use 0x51 for centimeters38
39 // use 0x52 for ping microseconds40
41 Wire.endTransmission(); // stop transmitting42
43 // step 2: wait for readings to happen44
45 delay(70); // datasheet suggests at least 65 milliseconds46
47 // step 3: instruct sensor to return a particular echo reading48
49 Wire.beginTransmission(112); // transmit to device #11250
51 Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02)52
53 Wire.endTransmission(); // stop transmitting54
55 // step 4: request reading from sensor56
57 Wire.requestFrom(112, 2); // request 2 bytes from peripheral device #11258
59 // step 5: receive reading from sensor60
61 if (2 <= Wire.available()) { // if two bytes were received62
63 reading = Wire.read(); // receive high byte (overwrites previous reading)64
65 reading = reading << 8; // shift high byte to be high 8 bits66
67 reading |= Wire.read(); // receive low byte as lower 8 bits68
69 Serial.println(reading); // print the reading70
71 }72
73 delay(250); // wait a bit since people have to read the output :)74}75
76/*77
78// The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08)79
80// usage: changeAddress(0x70, 0xE6);81
82void changeAddress(byte oldAddress, byte newAddress)83
84{85
86 Wire.beginTransmission(oldAddress);87
88 Wire.write(byte(0x00));89
90 Wire.write(byte(0xA0));91
92 Wire.endTransmission();93
94 Wire.beginTransmission(oldAddress);95
96 Wire.write(byte(0x00));97
98 Wire.write(byte(0xAA));99
100 Wire.endTransmission();101
102 Wire.beginTransmission(oldAddress);103
104 Wire.write(byte(0x00));105
106 Wire.write(byte(0xA5));107
108 Wire.endTransmission();109
110 Wire.beginTransmission(oldAddress);111
112 Wire.write(byte(0x00));113
114 Wire.write(newAddress);115
116 Wire.endTransmission();117
118}119
120*/
Connect pins 3, 6, and 7 of the AD5171 to GND, and pins 2 and 8 to +5V.
Connect pin 4, the digital pot's clock pin (SCL), to analog pin 5 on the Arduino, and pin 5, the data line (SDA), to analog pin 4. On both the SCL and SDA lines, add 4.7K ohm pull up resistors, connecting both lines to +5 V.
Finally, wire an LED to pin 1, the AD5171's "wiper", with a 680 ohm LED in series.
When the AD5171's pin 6, ADO, is connected to ground, it's address is is 44. To add another digital pot to the same SDA bus, connect the second pot's ADO pin to +5V, changing it's address to 45.
You can only use two of these digital potentiometers simultaneously.
1// I2C Digital Potentiometer2// by Nicholas Zambetti <http://www.zambetti.com>3// and Shawn Bonkowski <http://people.interaction-ivrea.it/s.bonkowski/>4
5// Demonstrates use of the Wire library6// Controls AD5171 digital potentiometer via I2C/TWI7
8// Created 31 March 20069
10// This example code is in the public domain.11
12// This example code is in the public domain.13
14
15#include <Wire.h>16
17void setup()18{19 Wire.begin(); // join i2c bus (address optional for master)20}21
22byte val = 0;23
24void loop()25{26 Wire.beginTransmission(44); // transmit to device #44 (0x2c)27 // device address is specified in datasheet28 Wire.write(byte(0x00)); // sends instruction byte 29 Wire.write(val); // sends potentiometer value byte 30 Wire.endTransmission(); // stop transmitting31
32 val++; // increment value33 if(val == 64) // if reached 64th position (max)34 {35 val = 0; // start over from lowest value36 }37 delay(500);38}