Bab 12 I2C Communication

1. I2C

Inter-Integrated Circuit (I2C) merupakan komunikasi serial synchronous yang biasa digunakan untuk jarak dekat. I2C biasa disebut juga I2C atau IIC atau Two-Wire Interface (TWI).

I2C mirip seperti SPI, banyak digunakan untuk menghubungkan mikrokontroler dengan sensor ataupun IC lainnya. Perbedaan utama I2C dan SPI yaitu jumlah sinyal yang diperlukannya. Pada I2C, kita hanya membutuhkan 2 sinyal (SCK dan SDA), sedangkan pada SPI diperlukan 4 sinyal (SCK, MOSI, MISO, SS). SPI memiliki arsitektur master-slave yang bisa terdiri dari beberapa master dan beberapa slave seperti pada Gambar 1.

Pada I2C, master dapat mengakses slave dengan menggunakan address yang dimiliki oleh masing-masing slave. Address tersebut memiliki panjang 7-bit. Secara teori jumlah maksimum alamat address-nya adalah 128, tetapi ada beberapa address yang di-reserved, sehingga total hanya ada 112 alamat address.

I2C merupakan bus multi-master dan multi-slave, sehingga bisa terdapat lebih dari satu master dalam bus tersebut. Walaupun demikian, hanya ada satu master yang boleh mengakses satu slave pada satu waktu. Pin SCL dan SDA merupakan pin open-drain. Pada Gambar 1, terdapat resisor pull-up RPRP yang akan men-drive sinyal yang terhubung dengan pin SCL dan SDA ke logika HIGH.

Pin SCL dan SDA dapat memberikan sinyal 0 dengan menghubungkannya ke GND, tetapi pin tersebut tidak dapat memberikan supply untuk logika HIGH. Logika HIGH merupakan nilai default dari pull-up resistor, ketika tidak ada master atau slave yang men-drive pin SCL dan SDA ke logic LOW.

Gambar 2 menampilkan contoh sinyal I2C. Pada kondisi idle, SCL dan SDA bernilai HIGH. Kondisi START terjadi ketika SDA bernilai LOW sebelum SCL bernilai LOW juga. Kondisi STOP terjadi ketika SDA bernilai HIGH setelah SCL bernilai HIGH juga.

Setelah master mengirim kondisi START, maka master akan mengirim address slave yang diikuti oleh R/W bit. Kemudian slave pemilik address tersebut harus memberikan ACK untuk memberikan feedback kepada master bahwa slave tersebut bisa merespon. Selanjutnya master atau slave dapat mengirim atau menerima data byte (MSB first) tergantung bit R/W yang sebelumnya dikirim. Setiap data yang dikirim atau diterima harus ada ACK yang mengindikasikan bahwa data tersebut telah berhasil diterima.

Gambar 3 menampilkan detail protocol I2C ketika master mengirim dan menerima data. Ketika master mengirim data ke slave, R/W bit bernilai 0. Setiap data byte yang berhasil diterima oleh slave akan ada ACK (bernilai 0) yang dikirim oleh slave. Ketika master menerima data dari slave, R/W bit bernilai 1. Setiap data byte yang berhasil diterima oleh master akan ada ACK (bernilai 0) yang dikirim oleh master. Jika data byte gagal diterima, maka akan ada NACK yang bernilai 1 baik dari slave maupun master.

Jika kita menggunakan library Arduino, maka sudah terdapat library untuk mempermudah penggunaan I2C. Biasanya sudah terdapat fungsi untuk mempermudah pengiriman dan penerimaan data. Walaupun demikian tetap penting untuk memahami terorinya agar dapat melakukan debugging ketika terjadi masalah.

2. OLED SSD1306

Organic light-emitting diode (OLED) merupakan tipe display yang banyak digunakan pada TV, smartphone, atau embedded device. OLED yang akan digunakan pada tutorial ini yaitu SSD1306 dengan ukuran 0.96-inch dan resolusi 128×64 pixels seperti pada Gambar 4.

Untuk menggunakan OLED tersebut sudah terdapat library Arduino-nya. Library untuk OLED SSD1306 dapat di-download di sini.

3. RTC DS1307

Real-time clock (RTC) merupakan IC yang digunakan untuk mengukur waktu dalam detik, menit, jam, sampai hari, bulan, dan tahun. Mirip seperti timer, tetapi clock yang digunakan biasanya memiliki frekuensi kecil yaitu 32.768kHz. IC ini dapat kita gunakan untuk membuat jam ataupun kalender. Pada tutorial ini, kita akan menggunakan modul RTC DS1307 seperti pada Gambar 5.

Untuk menggunakan RTC tersebut sudah terdapat library Arduino-nya. Library untuk RTC DS1307 dapat di-download di sini.

4. Contoh Program

Pada contoh program ini, kita akan mempelajari tiga contoh program yang menggunakan I2C untuk berkomunikasi dengan OLED SSD1306 dan RTC DS1307. Pada contoh pertama, kita akan menampilkan text hello world pada OLED. Pada contoh kedua, kita akan membaca waktu pada RTC dan menampilkannya pada serial monitor. Pada contoh ketiga, kita akan membaca waktu pada RTC dan menampilkannya pada OLED.

4.1. Program OLED SSD1306

Pada contoh progam ini, kita akan menampilkan text hello world pada OLED.

Untuk dapat menjalankan contoh program ini diperlukan beberapa komponen:

  • Development board ESP32

  • OLED SSD1306

  • Breadboard

  • Kabel jumper

Ilustrasi koneksi dari komponen-komponen ke ESP32 ditampilkan pada Gambar 6. Pin yang digunakan untuk menghubungkan komponen-komponen ke ESP32 ditampilkan pada tabel berikut ini.

SSD1306 PinESP32 Pin

SCL

D32

SDA

D33

3.3V

3.3V

GND

GND

Kode berikut ini menampilkan contoh program hello world pada OLED. Berikut ini penjelasan cara kerja program tersebut:

  • Pada line 1-2, kita meng-import library untuk I2C dan OLED SSD1306. Library OLED SSD1306 dapat di-download dari sini.

  • Pada line 5-7, kita melakukan pengecekan setting library agar sesuai dengan ukuran display OLED yang digunakan.

  • Pada line 10-11, kita mendefinisikan pin SDA dan SCL.

  • Pada line 14, kita mendefinisikan address dari module OLED SSD1306 yaitu 0×3C.

  • Pada line 17, kita mendeklarasikan objek untuk OLED tersebut.

  • Pada line 22, kita melakukan inisialisasi I2C dengan frekuensi clock SCL sebesar 400kHz.

  • Pada line 25-27, kita melakukan inisialisasi OLED, kemudian membersihkan display OLED tersebut.

  • Pada line 30-33, kita melakukan pengaturan font, lokasi penulisan text, dan menulis “Hello, World!” ke memori buffer OLED.

  • Pada line 36, kita menampilkan isi memory buffer OLED ke display OLED.

i2c-oled-ssd1306.ino
#include <wire.h>
#include <adafruit_ssd1306.h>

// Pengecekan setting ukuran OLED pada library
#if (SSD1306_LCDHEIGHT != 64) // 128x64 pixel
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

// Pin I2C
#define I2C_SDA 33
#define I2C_SCL 32

// Address I2C OLED
#define OLED_ADDR 0x3C

// Deklarasi object untuk OLED display
Adafruit_SSD1306 oled;

void setup()
{
  // Inisialisasi pin I2C
  Wire.begin(I2C_SDA, I2C_SCL, 400000);
    
  // Inisialisasi OLED
  oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  // Membersihkan memory OLED
  oled.clearDisplay();

  // Menulis text ke memory OLED
  oled.setTextSize(1);
  oled.setTextColor(WHITE);
  oled.setCursor(27, 30);
  oled.print("Hello, world!");

  // Menampilkan isi memory OLED ke display OLED
  oled.display();
}

void loop()
{
}

Gambar 7 menampilkan hasil akhir dari program ini. Text “Hello, World!” akan tampil pada OLED tersebut.

4.2. Program RTC DS1307

Pada contoh program ini, kita akan membaca waktu pada RTC dan menampilkannya pada serial monitor.

Untuk dapat menjalankan contoh program ini diperlukan beberapa komponen:

  • Development board ESP32

  • RTC DS1307

  • Breadboard

  • Kabel jumper

Ilustrasi koneksi dari komponen-komponen ke ESP32 ditampilkan pada Gambar 8. Pin yang digunakan untuk menghubungkan komponen-komponen ke ESP32 ditampilkan pada tabel berikut ini.

DS1307 PinESP32 Pin

SCL

D32

SDA

D33

3.3V

3.3V

GND

GND

Kode berikut ini menampilkan contoh program DS1307. Berikut ini penjelasan cara kerja program tersebut:

  • Pada line 1-2, kita meng-import library untuk I2C dan RTC DS1307. Library RTC DS1307 dapat di-download dari sini.

  • Pada line 5-6, kita mendefinisikan pin SDA dan SCL.

  • Pada line 9, kita mendeklarasikan objek untuk RTC tersebut.

  • Pada line 14-17, kita melakukan inisialisasi serial dan I2C.

  • Pada line 20, kita melakukan inisialisasi RTC.

  • Pada line 22-24, kita melakukan pengaturan waktu RTC ke waktu compile kode tersebut, kemudian kita mulai menjalankan RTC tersebut.

  • Pada line 30-36, kita membaca waktu dari RTC tersebut setiap 1 detik, kemudian dikirim ke serial monitor.

i2c-rtc-ds1307.ino
#include <wire.h>
#include <rtcds1307.h>

// Pin I2C
#define I2C_SDA 33
#define I2C_SCL 32

// Deklarasi object untuk RTC
RtcDS1307<twowire> rtc(Wire);

void setup()
{
  // Inisialisasi serial
  Serial.begin(9600);
    
  // Inisialisasi pin I2C
  Wire.begin(I2C_SDA, I2C_SCL, 400000);
    
  // Inisialisasi RTC
  rtc.Begin();  
  // Men-set waktu RTC ke waktu saat kode di-compile
  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
  rtc.SetDateTime(compiled);
  rtc.SetIsRunning(true);
}

void loop()
{
  // Membaca waktu RTC (date and time)
  RtcDateTime now = rtc.GetDateTime();
    
  // Print waktu RTC ke serial monitor 
  Serial.printf("%04d/%02d/%02d %02d:%02d:%02d\n",
      now.Year(), now.Month(), now.Day(),
      now.Hour(), now.Minute(), now.Second());
  delay(1000);
}

Gambar 9 menampilkan hasil program DS1307. Waktu yang terdiri dari tahun, bulan, tanggal, dan jam, menit, detik akan ditampilkan pada serial monitor setiap 1 detik.

4.3. Program OLED SSD1306 dan RTC DS1307

Pada program ini, kita akan membaca waktu pada RTC dan menampilkannya pada OLED. Program ini merupakan gabungan dari kedua program sebelumnya. Dua device I2C terhubung ke satu bus I2C yang sama dan dapat diakses oleh ESP32.

Untuk dapat menjalankan contoh program ini diperlukan beberapa komponen:

  • Development board ESP32

  • OLED SSD1306

  • RTC DS1307

  • Breadboard

  • Kabel jumper

Ilustrasi koneksi dari komponen-komponen ke ESP32 ditampilkan pada Gambar 10. Pin yang digunakan untuk menghubungkan komponen-komponen ke ESP32 ditampilkan pada kedua tabel sebelumnya.

Kode berikut ini menampilkan contoh program OLED SSD1306 dan RTC DS1307. Program tersebut merupakan gabungan dari kedua progam sebelumnya. Bagian pembacaan RTC sama seperti program DS1307. Perbedaan utamanya yaitu pada hasil pembacaan RTC yang ditampilkan pada OLED, bukan dikirim ke serial monitor.

rtc-ds1307-oled-ssd1306.ino
#include <wire.h>
#include <rtcds1307.h>
#include <adafruit_ssd1306.h>

// Pengecekan setting ukuran OLED pada library
#if (SSD1306_LCDHEIGHT != 64) // 128x64 pixel
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

// Pin I2C
#define I2C_SDA 33
#define I2C_SCL 32

// Address I2C OLED
#define OLED_ADDR 0x3C

// Deklarasi object untuk RTC
RtcDS1307<twowire> rtc(Wire);

// Deklarasi object untuk OLED display
Adafruit_SSD1306 oled;

void setup()
{
  // Inisialisasi pin I2C
  Wire.begin(I2C_SDA, I2C_SCL, 400000);
    
  // Inisialisasi RTC
  rtc.Begin();  
  // Men-set waktu RTC ke waktu saat kode di-compile
  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
  rtc.SetDateTime(compiled);
  rtc.SetIsRunning(true);

  // Inisialisasi OLED
  oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  // Membersihkan memory OLED
  oled.clearDisplay();
}

void loop()
{
  // Read RTC date and time
  RtcDateTime now = rtc.GetDateTime();
    
  // Menampilkan waktu RTC pada OLED
  oled.clearDisplay();
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
  oled.setCursor(4, 12);
  oled.printf("%04d/%02d/%02d",
      now.Year(), now.Month(), now.Day());
  oled.setCursor(16, 38);
  oled.printf("%02d:%02d:%02d",
      now.Hour(), now.Minute(), now.Second());
  oled.display();
  delay(1000);
}

Gambar 11 menampilkan hasil dari program OLED SSD1306 dan RTC DS1307. Pada OLED dapat terlihat tahun, bulan, tanggal, dan jam, menit, detik.

5. Repository Kode Program

Kode program untuk OLED SSD1306, RTC DS1307, serta OLED SSD1306 dan RTC DS1307 dapat didapatkan di repository ini: i2c-oled-ssd1306, i2c-rtc-ds1307, dan rtc-ds1307-oled-ssd1306.

Last updated