Skip to main content

I2C Functions Library

I2C Functions is a lightweight helper library I wrote to simplify I2C communication on AVR-based boards (Arduino etc.). The main goal is to abstract repetitive tasks such as register read/write, multi read/write, and I2C multiplexer management, so sensor/driver libraries become more readable.

You can use this library when working with a single I2C sensor, multiple devices on the same bus, or complex topologies connected through an I2C multiplexer (e.g., TCA9548).

Library Source

GitHub repository of the library: akkoyun/I2C_Functions

Key Features

  • Simplified I2C API Single-byte / multi-byte register read-write functions.
  • I2C Multiplexer Support Define multiplexer address and channel when creating the object and leave the rest to the library.
  • Predefined Address Definitions Predefined I2C addresses for some commonly used sensors and ICs.
  • Cleaner Driver Code Focus on business logic instead of dealing with I2C for each IC.

Object Creation

The core of the library is the I2C_Functions class. You can set it up in two different ways depending on whether you use an I2C multiplexer.

#include <I2C_Functions.h>

// Direct usage on the I2C bus without a multiplexer
I2C_Functions HDC2010(0x40);

Library Functions

Single Register Read

Reading 1 byte from a register on a sensor connected to the I2C bus:

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// Read single byte from register at address 0x01
uint8_t result = HDC2010.Read_Register(0x01);

Multiple Register Read

To get multiple bytes from a starting address:

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

uint8_t data[4];

// Read 4 bytes starting from address 0x00
HDC2010.Read_Multiple_Register(0x00, data, 4);

For 16-bit addressed register maps, there is also a multiple read function:

uint8_t data16[4];

// Read 4 bytes starting from address 0x0001
HDC2010.Read_Multiple_Register_u16(0x0001, data16, 4, true);

Register Write

To write a single byte:

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// Write value 0x22 to register at address 0x10
HDC2010.Write_Register(0x10, 0x22, true); // last parameter is for debug output

Multiple Register Write

To write multiple bytes from a starting address:

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

uint8_t config[4] = {0x22, 0x33, 0x44, 0x55};

// Write 4 bytes starting from register at address 0x10
HDC2010.Write_Multiple_Register(0x10, config, 4);

Command Write

Some ICs expect commands directly instead of registers. Single command or multi-byte command:

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// Single-byte command
HDC2010.Write_Command(0x22);

// Multi-byte command
uint8_t command[3] = {0xAA, 0xBB, 0xCC};
HDC2010.Write_Multiple_Command(command, 3);

Register Word Read (16-bit)

To read 16-bit (2 bytes) from a single register:

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// Read 16-bit from register at address 0x02
uint16_t word = HDC2010.Read_Register_Word(0x02);

16-bit Multi Read (Without Sending Command)

Some devices allow sequential data reading without requiring a preceding command/register write.

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

uint8_t data[4];
// Read 4 bytes without sending a prior command
HDC2010.Read_Multiple_Register_u16_NoCMD(data, 4);

Register Bit Operations

Bit Set

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// Set bit 2 in register 0x10
HDC2010.Set_Register_Bit(0x10, 2, true);

Bit Clear

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// Clear bit 2 in register 0x10
HDC2010.Clear_Register_Bit(0x10, 2, true);

Bit Read

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// Read the value of bit 2 in register 0x10
bool bit = HDC2010.Read_Register_Bit(0x10, 2);

Device Detection (Detect)

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// Device detection
bool ok = HDC2010.Detect();

Address and MUX Info

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library (behind MUX on channel 0x03)
I2C_Functions HDC2010(0x40, true, 3);

// Initialize the sensor
HDC2010.Begin();

uint8_t addr = HDC2010.Address(); // Device address
bool muxOn = HDC2010.Mux_Enable(); // Is MUX used?
uint8_t ch = HDC2010.Mux_Channel(); // MUX channel

MUX Channel Setting (Set_Mux_Channel)

If MUX is not used, channel setting is not necessary.

// Load the library
#include <I2C_Functions.h>

// Introduce the sensor to the library
I2C_Functions HDC2010(0x40);

// Initialize the sensor
HDC2010.Begin();

// No-op when there is no MUX
HDC2010.Set_Mux_Channel();

With these structures, the I2C multiplexer detail stays in the background in driver libraries, and you can focus only on business logic.

Predefined Address Definitions

The library includes predefined address macros for some ICs (examples: TCA9548, RV3028, DS28C, MAX17055, etc.). You can use these macros in your own code or add new device addresses following the same pattern:

#define __I2C_Addr_HDC2010__   (uint8_t)0x40
#define __I2C_Addr_MAX17055__ (uint8_t)0x36
// ...

This helps address types become more consistent and readable across projects.

Sample Usage Scenario

A simple sensor driver using I2C Functions could look like this:

#include <I2C_Functions.h>

I2C_Functions Sensor(__I2C_Addr_HDC2010__);

void setup() {
Wire.begin();
Serial.begin(115200);

if (!Sensor.Detect()) {
Serial.println("Sensor not found!");
while (1);
}

Serial.println("Sensor found, initializing...");
// Do initialize register settings here
}

void loop() {
uint8_t temp_raw = Sensor.Read_Register(0x00);
// Convert raw data to actual temperature, etc...
}

In this way, on the driver side, you focus only on the sensor's logic and leave the I2C traffic and multiplexer details to the library.

Bu kütüphane, gerçek sahada kullanılan projelerden gelen ihtiyaçlara göre sürekli gelişen bir açık kaynak projedir. Kullanıcı geri bildirimleri, yeni fonksiyonların eklenmesi ve mevcut yapının iyileştirilmesi açısından kritik öneme sahiptir.

Bu kütüphaneyi hem kişisel hem de ticari projelerinde özgürce kullanabilirsin. Herhangi bir lisans kısıtı uygulanmamaktadır; amacım, bu kütüphanenin mümkün olduğunca fazla gerçek dünya projesinde yer almasıdır. Özel bir entegrasyon ihtiyacın, ticari bir planın veya teknik bir sorunun varsa bana e‑posta üzerinden her zaman ulaşabilirsin: akkoyun@me.com Geri bildirimlerini veya kullanım senaryolarını paylaşman, projeyi geliştirmem açısından büyük katkı sağlar.