Works I2C with Arduino

The I.2C-bus


In embedded systems, sensors and actuators are often marked with the I.2C-bus connected. Linux on the Raspberry Pi supports this with its own subsystem. I.2C (pronunciation: "i-quadrat-c", sometimes also "i-two-c") is a serial master-slave data bus that was designed for communication over short distances, i.e. mainly within circuit boards or devices. The technology dates back to the early 1980s and was originally developed by Philips (now NXP Semiconductors) for use in consumer electronics. Data is transferred synchronously via two lines: a data line (SDA) and a clock line (SCL), on which a simple transfer protocol runs (see also serial interface, USB, SPI, I2C, 1-Wire).

Both lines are pulled to a positive potential by pull-up resistors, the I.2C chips have open collector outputs. A bus master specifies the cycle and operating mode and initiates the byte-by-byte communication. The I.2C-Master can address up to 112 devices (slaves) with a 7-bit address (an extension of the bus uses 10 bits for up to 1136 devices). A wide variety of devices exist on the market for the bus, including temperature sensors, real-time clocks, port expanders, A / D and D / A converters as well as entertainment electronics components.

A modification of I.2C is the SMBus, the System Management Bus. In terms of hardware, it is identical to I.2C, but defines a different transmission protocol on it. It can be found on almost all modern PC boards, for B. to measure the temperature of the CPU. Occasionally the I.2C-Bus as Two-wire interface or TWI designated.

The I2C-Devices (clients) receive data from the master and send back a response depending on the transmitted command. Commands, parameters and responses are different for each device - so there is no uniform programming scheme. The Arduino supports the I2C-Bus with his Wire library. This library allows an Arduino to communicate with chips that use the I.2Use C protocol. Usually the I.2C-Devices have numerous internal registers that are either written to (configuration, storage of values) or read from (measured values, memory content). A request to a device usually consists of a write operation in which the desired register is specified and a subsequent read operation for the register content.

You can not only get special I.2C devices, but also several Arduinos connected to the I2Connect the C-Bus and let them communicate with each other. Each device connected to the bus has its own address. Since the address is 7 bits wide, up to 112 devices can be connected to an I.2C-Bus (16 of the 128 possible addresses are reserved for special purposes).

The I.2C-Bus requires two data lines: SCL for the clock signal and SDA for the data signal. The earlier Arduinos used the lines A4 (SDA) and A5 (SCL) for the bus connection. On newer Uno boards, these two lines are led out to separate connections on the opposite socket strip. So these are not "new" I.2C connections! Therefore note:

SDA and SCL are simply continued A4 or A5 connections! When an Arduino is connected to an I2If the C-Bus is connected, the analog inputs A4 and A5 are no longer available.

The other Arduino boards use different pins for the I.2C-bus:

boardI.2C / TWI pins
Uno, ethernetA4 (SDA), A5 (SCL)
Mega256020 (SDA), 21 (SCL)
Leonardo2 (SDA), 3 (SCL)
Due20 (SDA), 21 (SCL), SDA1, SCL1

The bus lines are terminated with pull-up resistors against +5 V. The standard clock frequency on the bus is 100 kHz, but many components can also be operated with 400 kHz.

As already mentioned, there is a library for operating the bus components. In order to integrate this library in your own code, the following header file is listed in the program:


The Wire library provides the following commands:

  • Initializes the library and reports the Arduino with the specified slave address to the I.2C-bus on. If the Arduino is to be registered as bus master (normal case), the address is omitted.

  • Requests the specified number of bytes from the specified device. The third, optional parameter specifies whether the I2C-Bus is released again after the request has been sent. The value (default) enables the bus again, continues to occupy the bus. The value should be used if you want to query data several times and you want to prevent another bus participant from occupying the bus.

  • Preparing a data transfer to the device with the specified address. Then the data to be transferred is written to a buffer using one or more commands. The data is only transferred when you call.

  • Transfer of the buffered data to the device specified with and completion of the transfer.

  • With this command you fill the send buffer with the data to be sent when calling. Any data types and structures are possible as parameters, including strings, etc.

  • Returns the number of bytes that are in the receive buffer. You can use this command in a while loop to read the files, for example:

  • Reads a byte from the receive buffer.

  • Specifies which function is called when data has been received via the bus. The function has an int parameter that can be used to transfer the number of bytes that have arrived. The function has no return value. Definition:.

  • Determines which function is called when data is requested (see). This function has no parameters and does not return anything. Definition:.

  • Sets the clock frequency for the I.2C-bus. Typical values ​​are 10000L (100 kHz) and 400000 (400 kHz).
A few comments on this.
  • The and functions are primarily used for communication between two Arduinos (or an Arduino with another controller).
  • When calling, the number of bytes requested is specified, but the callback function for is called for each byte received. The background to this is communication over the bus: the addressee is asked to start sending and when enough bytes have been received, the connection is terminated.
  • With the Arduino, the master and slave can send a maximum of 32 bytes at once.


I.2C scanner

Sometimes the problem arises that you can get an I.2C device, but unfortunately does not know which address it has. Or you want to check whether there is a fault in the wiring. The following I.2C-Scanner is an Arduino program that scans all addresses and the connected I.2Shows C Defices in the Serial Monitor. To do this, the connection is started with and immediately terminated with. If a device could be addressed, the function returns a zero, otherwise an error code. The program first checks the address range from 0x01 to 0x7F on ICs in normal mode (100 kHz). The same area is then scanned with the higher bus clock rate of 400 kHz. The I2C addresses and the number of addressable components are output for each mode. The function remains empty because it is only to be scanned once.

#include void setup () {int count = 0; / * Number of found I2C devices * / Serial.begin (9600); Wire.begin (); Serial.println ("I2C bus scanner"); Wire.setClock (100000L); Serial.println ("Scan with 100 kHz"); scan(); Wire.setClock (400000L); Serial.println ("Scan with 400 kHz"); scan(); } void scan (void) {int count = 0; / * scan all possible IDs * / for (int i = 0; i <128; i="" ++)="" {wire.begintransmission="" (i);="" *="" test="" communication="" with="" device="" (i)="" *="" if="" (wire.endtransmission="" ()="=" 0)="" {/="" *="" found="" *="" serial.print="" ("id="); Serial.print (" 0x");="" serial.println="" (i,="" hex);="" count="" ++;="" }="" delay="" (20);="" }="" serial.print="" (count);="" serial.println="" ("devices="" found="" \="" n");="" }="" void="" loop="" ()="" {//="" nothing}="">

Master-slave communication

A master switches the light-emitting diode D13 on the slave, a second Arduino, via the bus. To do this, the master simply sends any byte to the slave every second. When a byte arrives at the slave, it reverses the status of the line. The master has no bus address. The slave, on the other hand, needs an address in order to be identified on the bus. In the example, 0x55 is used here. The master is quite easy to program. The bus is initialized in and the transmission is initiated in each case.

Since the master cannot send to several slaves in parallel, a block of, interaction and is necessary for each slave. The actual transfer does not take place until you call up; the data is previously stored in a 32-byte buffer. The return value of can be used to check whether the slave has accepted the data. However, it cannot be determined whether all data has arrived without errors.

#include void setup () {Wire.begin (); Serial.begin (9600); } void loop () {boolean OK; / * Switch off the LED on the slave * / Wire.beginTransmission (0x55); Wire.write (0); OK = Wire.endTransmission (); Serial.println ("off"); delay (1000); / * Switch on the LED on the slave * / Wire.beginTransmission (0x55); Wire.write (1); OK = Wire.endTransmission (); Serial.println ("a"); delay (1000); }

In the case of the slave, the program is a little longer because one of the event-oriented methods listed above is used. You no longer have to worry about calling the receive routine; the receive routine is activated as soon as data is available. A callback function is assigned to the event in the setup; the function is then declared below. It is important that the data type of the transfer parameter is of the type. If data arrives, the callback routine is called, in which the data is read and responded accordingly.

#include void setup () {pinMode (13, OUTPUT); Wire.begin (55); Wire.onReceive (receiveEvent); } void loop () {// nothing} void receiveEvent (int number) {byte State; while (Wire.available ()) {State = (); } digitalWrite (13, State); }

Reading of the temperature and humidity sensor HDC1008

The HDC1008 from Texas Instruments is a digital humidity sensor with an integrated temperature sensor, which offers excellent measurement accuracy with very low power consumption (a few microamps). The air humidity is measured using a new type of capacitive sensor. The humidity and temperature sensors are calibrated at the factory. With its ultra-compact housing, the innovative WLCSP design (wafer-level CSP housing) enables a simpler design. The sensor element of the HDC1008 is located in the lower part of the component, which means that the HDC1008 is better protected from dirt, dust and other environmental pollutants. The HDC1008 is specified for temperature ranges from -40 ° C to +125 ° C. He will have an I.2C-Interface connected. The sensor can be used on 3.3 V or 5 V systems.

Structure of the HDC1008

Watterott or Adafruit offer a so-called breakout board on which the sensor is soldered and which enables connection via a pin header or the like. The 2-bit address of the sensor can be set in the range from 0x40 to 0x43 via jumpers. Without I.2C multiplexers or disconnection of individual sensors can therefore operate up to four sensors in parallel. For the Arduino, Adafruit offers a library that only needs to be downloaded and installed - but it is not absolutely necessary because the chip only has three registers.

The conversion of the 14-bit values ​​of the sensor into temperature and humidity is done with the following equations, where the [15:00] nothing more than that it is a 16-bit value (bits 15 to 0):

Only two functions are required to access the measured values:

  • public the connection to the bus and writes a configuration word in the control register of the HDC1008.
  • reads a 16-bit value from the specified register of the HDC1008. The delay values ​​used are taken from the data sheet.
In the program loop, the temperature and humidity values ​​are called up every three seconds and displayed on the serial console. #include #define HDC1008_I2CADDR 0x43 // HDC1008 register #define HDC1008_TEMP 0x00 #define HDC1008_HUMID 0x01 #define HDC1008_CONFIG 0x02 // configuration word #define HDC1008_CONFIG_RST 0x9000; float humid; uint16_t data; void hdc_begin (uint8_t i2caddr, uint16_t config) {Wire.begin (); Wire.beginTransmission (i2caddr); Wire.write (config >> 8); Wire.write (config & 0xFF); Wire.endTransmission (); delay (15); } uint16_t hdc_read16 (uint8_t i2caddr, uint8_t reg) {uint16_t res; Wire.beginTransmission (i2caddr); Wire.write (reg); Wire.endTransmission (); delay (65); Wire.requestFrom ((uint8_t) i2caddr, (uint8_t) 2); res = (); res < =="" 8;="" res="" |="" ();="" delay="" (15);="" return="" res;="" }="" void="" setup="" ()="" {serial.begin="" (9600);="" serial.println="" ("ti="" hdc1008="" sensor");="" hdc_begin="" (hdc1008_i2caddr,="" hdc1008_config_rst);="" }="" void="" loop="" ()="" {data="hdc_read16" (hdc1008_i2caddr,="" hdc1008_temp);="" temp="((float)" data="" 65536.0)="" *="" 165.0="" -="" 40.0;="" data="hdc_read16" (hdc1008_i2caddr,="" hdc1008_humid);="" humid="((float)" data="" 65536)="" *="" 100;="" serial.print="" ("temperature="" [°="" c]:");="" serial.println="" (temp);="" serial.print="" ("humidity="" [%]:");="" serial.println="" (humid);="" delay="" (3000);="" }="">

More examples can be found under the links at the bottom of the page, e.g. B. the control of a real-time clock chip and an LCD.


Copyright © Munich University of Applied Sciences, FK 04, Prof. Jürgen Plate
Last update :, website: