Tutorial ESP8266: Menampilkan Grafik di OLED Display Menggunakan NodeMCU (REVISI GAMBAR)

Ingin mempercantik proyek ESP8266 Anda dengan grafis yang memukau atau menampilkan alamat IP perangkat tanpa perlu membuka Serial Monitor? Saatnya menyalakan layar OLED. Layar mungil ini super ringan, sangat tipis, dan menghasilkan gambar yang lebih tajam dan cerah, langsung terlihat di layar.

 

Dalam tutorial praktis ini, kami akan memandu Anda cara menghubungkan layar OLED ke ESP8266. Anda akan belajar cara menampilkan teks, menggambar bentuk dasar, dan bahkan menampilkan gambar kustom Anda sendiri. Dan untuk membuatnya lebih menyenangkan, kami telah menyertakan alat untuk membantu Anda mengonversi gambar apa pun menjadi kode siap pakai!

Mari selami dan wujudkan proyek Anda—piksel demi piksel!

Ikhtisar Modul Layar OLED

Layar OLED hadir dalam beragam pilihan, memberi Anda banyak pilihan tergantung kebutuhan proyek Anda. Layar ini tersedia dalam berbagai ukuran, seperti 128×64 piksel atau 128×32 piksel, dan Anda dapat memilih dari beragam warna seperti putih, biru, atau bahkan versi dua warna yang keren. Layar ini juga mendukung berbagai cara berkomunikasi dengan ESP8266 Anda—beberapa menggunakan I2C, sementara yang lain menggunakan SPI.

Dalam tutorial ini, kita akan menggunakan layar OLED I2C 0,96 inci 128×64. Namun, jika layar Anda memiliki ukuran atau warna yang berbeda, jangan khawatir. Konsep dasar yang akan kita bahas tetap berlaku, dan langkah-langkah untuk membuatnya berfungsi akan sangat mirip.

 


Apa pun ukuran, warna, atau metode komunikasi yang Anda pilih, semua layar OLED ini mengandalkan chip kecil namun tangguh yang sama, yang disebut driver OLED SSD1306. Chip ini bertindak sebagai "otak" layar. Chip ini menangani penggambaran semua yang Anda lihat di layar dengan menyimpan data gambar di memorinya sendiri (RAM buffering). Berkat desain cerdas ini, mikrokontroler Anda tidak perlu terus-menerus memperbarui layar—ia dapat fokus pada tugas-tugas lain.

Daya

Tidak seperti layar LCD tradisional, layar OLED tidak memerlukan lampu latar karena piksel OLED menghasilkan cahayanya sendiri. Hal ini menghasilkan kontras tinggi, sudut pandang yang sangat baik, dan warna hitam yang benar-benar pekat. Karena tidak memerlukan lampu latar, layar OLED menggunakan daya yang lebih rendah—rata-rata sekitar 20 mA, sehingga ideal untuk proyek bertenaga baterai.

Layar OLED beroperasi dengan tegangan antara 3,3 V dan 5 V. Ini berarti Anda dapat dengan mudah menghubungkan layar OLED ke mikrokontroler 3,3 V atau 5 V tanpa masalah.

Memahami Peta Memori OLED

Untuk mengontrol apa yang muncul di layar OLED Anda, Anda perlu memahami bagaimana memori layar diatur.

Berapa pun ukuran layar OLED Anda, chip driver SSD1306 di dalamnya memiliki memori sebesar 1 KB (kilobyte), yang dikenal sebagai Graphic Display Data RAM (GDDRAM). Memori ini menyimpan pola piksel yang ditampilkan di layar Anda. Setiap bit dalam memori ini mengendalikan satu piksel.

Beginilah cara memori 1 KB ini diatur:

1. Memori dibagi menjadi 8 halaman (bernomor 0 hingga 7)

2. Setiap halaman memiliki 128 kolom (juga disebut segmen)

3. Setiap kolom berisi 8 piksel vertikal di layar

Jadi rumusnya seperti ini:

8 halaman × 128 kolom × 8 bit = 8.192 bit = 1.024 byte = 1KB memori

Seluruh memori 1K, termasuk halaman, segmen, dan data, disorot di bawah.

 

Ingat, setiap modul OLED berisi 1 KB RAM, berapa pun ukurannya. Modul OLED 128×64 menampilkan semua yang ada dalam 1 KB RAM tersebut (8 halaman), sementara modul OLED 128×32 hanya menampilkan setengah dari RAM (hanya 4 halaman pertama).

Pinout

Sebelum kita membahas koneksi dan contoh kode, mari kita lihat lebih dekat pinout modul tampilan OLED I2C.


1. GND adalah pin ground.

2. VCC adalah pin catu daya untuk layar. Anda dapat menghubungkannya ke pin 3,3V atau 5V pada mikrokontroler Anda.

3. SCL adalah pin clock serial yang digunakan untuk antarmuka I2C.

4. SDA adalah pin data serial untuk antarmuka I2C.

Menghubungkan Modul Layar OLED ke NodeMCU ESP8266

Mari kita hubungkan layar OLED ke NodeMCU ESP8266.

Koneksinya mudah. ​​Pertama, hubungkan pin VCC layar ke output 3.3V NodeMCU dan pin GND ke ground.

Selanjutnya, kita perlu menghubungkan pin yang digunakan untuk komunikasi I2C. Hubungkan pin SCL pada layar ke D1 pada ESP8266, dan pin SDA ke D2 pada ESP8266.

Diagram ini menunjukkan kepada Anda secara tepat cara menghubungkan semuanya:

 

Instalasi Pustaka

Pengontrol SSD1306 yang digunakan pada layar OLED sangat fleksibel, tetapi juga bisa cukup rumit untuk dioperasikan secara langsung. Untuk menggunakannya dengan benar, Anda biasanya perlu memahami cara kerja pengalamatan memori dengan baik, yang bisa jadi rumit—terutama bagi pemula.

Untungnya, kita tidak perlu khawatir tentang semua itu. Pustaka Adafruit SSD1306 diciptakan untuk mempermudah segalanya. Pustaka ini menangani semua hal rumit di balik layar, sehingga Anda dapat mengontrol layar OLED menggunakan perintah yang sederhana dan mudah dipahami.

Untuk menginstal pustaka,

1. Pertama, buka program Arduino IDE Anda. Kemudian klik ikon Pengelola Pustaka di bilah sisi kiri.

2. Ketik "adafruit ssd1306" di kotak pencarian untuk memfilter hasil pencarian.

3. Cari Pustaka Adafruit SSD1306 dari Adafruit.

4. Klik tombol Install untuk menambahkannya ke Arduino IDE Anda.

 


Karena Pustaka Adafruit SSD1306 bergantung pada pustaka lain agar berfungsi, Anda akan diminta untuk menginstal dependensinya, termasuk Pustaka Adafruit Bus IO dan Pustaka Adafruit GFX.

Saat pesan ini muncul, cukup klik PASANG SEMUA untuk memastikan semuanya telah diatur dengan benar.

Contoh Kode ESP8266 1 – Menampilkan Teks

Sekarang tiba bagian yang menyenangkan—mari kita mulai menampilkan beberapa hal keren di layar OLED!

Sketsa di bawah ini menunjukkan cara:

1. Menampilkan teks sederhana

2. Menampilkan teks terbalik

3. Menampilkan angka

4. Menampilkan angka dengan basis (Hex, Dec)

5. Menampilkan simbol ASCII

6. Menggulir teks secara horizontal dan vertikal

7. Menggulir sebagian tampilan

Setelah Anda memahami contoh ini, Anda akan siap membangun proyek yang lebih kreatif dan canggih dengan layar OLED Anda.

 

#include <SPI.h>

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>


#define SCREEN_WIDTH 128  // OLED display width, in pixels

#define SCREEN_HEIGHT 64  // OLED display height, in pixels


// Declaration for SSD1306 display connected using I2C

#define OLED_RESET -1  // Reset pin

#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


void setup() {

  Serial.begin(9600);


  // initialize the OLED object

  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {

    Serial.println(F("SSD1306 allocation failed"));

    for (;;)

      ;  // Don't proceed, loop forever

  }


  // Clear the buffer.

  display.clearDisplay();


  // Display Text

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 28);

  display.println("Hello world!");

  display.display();

  delay(2000);

  display.clearDisplay();


  // Display Inverted Text

  display.setTextColor(BLACK, WHITE);  // 'inverted' text

  display.setCursor(0, 28);

  display.println("Hello world!");

  display.display();

  delay(2000);

  display.clearDisplay();


  // Changing Font Size

  display.setTextColor(WHITE);

  display.setCursor(0, 24);

  display.setTextSize(2);

  display.println("Hello!");

  display.display();

  delay(2000);

  display.clearDisplay();


  // Display Numbers

  display.setTextSize(1);

  display.setCursor(0, 28);

  display.println(123456789);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Specifying Base For Numbers

  display.setCursor(0, 28);

  display.print("0x");

  display.print(0xFF, HEX);

  display.print("(HEX) = ");

  display.print(0xFF, DEC);

  display.println("(DEC)");

  display.display();

  delay(2000);

  display.clearDisplay();


  // Display ASCII Characters

  display.setCursor(0, 24);

  display.setTextSize(2);

  display.write(3);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Scroll full screen

  display.setCursor(0, 0);

  display.setTextSize(1);

  display.println("Full");

  display.println("screen");

  display.println("scrolling!");

  display.display();

  display.startscrollright(0x00, 0x07);

  delay(2000);

  display.stopscroll();

  delay(1000);

  display.startscrollleft(0x00, 0x07);

  delay(2000);

  display.stopscroll();

  delay(1000);

  display.startscrolldiagright(0x00, 0x07);

  delay(2000);

  display.startscrolldiagleft(0x00, 0x07);

  delay(2000);

  display.stopscroll();

  display.clearDisplay();


  // Scroll part of the screen

  display.setCursor(0, 0);

  display.setTextSize(1);

  display.println("Scroll");

  display.println("some part");

  display.println("of the screen.");

  display.display();

  display.startscrollright(0x00, 0x00);

}


void loop() {

}

 

Seperti inilah tampilan outputnya.

 


Penjelasan Kode:

Sketsa dimulai dengan menyertakan empat pustaka: SPI.h, Wire.h, Adafruit_GFX.h, dan Adafruit_SSD1306.h. Pustaka-pustaka ini memungkinkan ESP8266 untuk berkomunikasi dengan layar OLED. Meskipun kami menggunakan I2C (yang tidak memerlukan pustaka SPI), kami tetap menyertakan SPI.h untuk memastikan kode dikompilasi tanpa kesalahan.

 

#include <SPI.h>

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

 

Selanjutnya, kita tentukan lebar dan tinggi layar dalam piksel. Layar OLED yang paling umum memiliki lebar 128 piksel dan tinggi 64 piksel, jadi kita tetapkan SCREEN_WIDTH ke 128 dan SCREEN_HEIGHT ke 64.

Kemudian, kita membuat objek tampilan menggunakan pustaka Adafruit_SSD1306. Kita tentukan ukuran layar kita—lebar 128 piksel dan tinggi 64 piksel—dan kita beri tahu bahwa kita menggunakan I2C. Karena modul OLED kita tidak memiliki pin reset, kita berikan nilai -1 untuk menunjukkan bahwa kita tidak menggunakannya.

 

#define SCREEN_WIDTH 128 // OLED display width, in pixels

#define SCREEN_HEIGHT 64 // OLED display height, in pixels


// Declaration for SSD1306 display connected using I2C

#define OLED_RESET     -1 // Reset pin

#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

 

Di dalam fungsi setup(), pertama-tama kita memulai komunikasi serial untuk mencetak pesan ke Serial Monitor untuk debugging.

Kemudian kita memanggil display.begin() untuk memulai komunikasi dengan layar OLED. Argumen pertama mengaktifkan sirkuit pompa muatan internal, yang membantu memberi daya pada layar, dan argumen kedua menetapkan alamat I2C (alamat I2C layar biasanya 0x3C, tetapi beberapa layar menggunakan 0x3D, jadi Anda perlu mengubahnya jika perlu). Jika layar tidak memulai dengan benar, kita akan menampilkan pesan kesalahan dan menghentikan program.

 

Serial.begin(9600);


// initialize the OLED object

if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {

  Serial.println(F("SSD1306 allocation failed"));

  for (;;)

    ;  // Don't proceed, loop forever

}

 

Setelah tampilan siap, kita bersihkan layar menggunakan display.clearDisplay(). Ini memastikan kita bekerja dengan layar kosong.

 

// Clear the buffer.

display.clearDisplay();


Displaying simple Text (Hello World)


// Display Text

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,28);

display.println("Hello world!");

display.display();

delay(2000);

 

Untuk menampilkan teks di layar OLED, pertama-tama kita atur ukuran teks menggunakan fungsi setTextSize(). Fungsi ini mengambil angka di mana 1 adalah ukuran terkecil, dan angka yang lebih tinggi akan memperbesar teks.

Selanjutnya, kita pilih warna teks menggunakan setTextColor(). Gunakan PUTIH untuk latar belakang gelap, dan HITAM untuk latar belakang terang. Karena layar OLED kita memiliki latar belakang gelap, kita gunakan PUTIH agar teks terlihat jelas.

Sebelum mencetak apa pun, kita memberi tahu layar di mana harus mulai menulis dengan mengatur posisi kursor menggunakan setCursor(x, y). Nilai x mengontrol seberapa jauh dari kiri teks dimulai, dan y mengontrol seberapa jauh dari atas. Sudut kiri atas adalah posisi (0, 0).

Untuk benar-benar menampilkan pesan di layar, kita menggunakan fungsi print(" ") atau println(" "). Fungsi ini bekerja seperti mencetak ke Serial Monitor. Ingat, println() memindahkan kursor ke baris berikutnya setelah mencetak, sementara print() mempertahankannya di baris yang sama.

Terakhir, kita menggunakan display() untuk memperbarui layar dan menampilkan semua yang telah kita siapkan dalam kode. Layar tidak akan diperbarui hingga Anda memanggil fungsi ini.

Displaying Inverted Text

 


// Display Inverted Text

display.clearDisplay();

display.setTextColor(BLACK, WHITE); // 'inverted' text

display.setCursor(0,28);

display.println("Hello world!");

display.display();

delay(2000);

 

Jika Anda ingin menampilkan teks dengan warna terbalik (teks hitam di latar belakang putih), Anda dapat melakukannya dengan menggunakan fungsi setTextColor() lagi, tetapi kali ini dengan dua nilai. Ketika kita menggunakan setTextColor(BLACK, WHITE), kita memberi tahu tampilan untuk menggambar huruf hitam di atas persegi panjang putih. Alasan kita dapat memberikan dua nilai sekarang adalah karena sesuatu yang disebut "function overloading"—artinya fungsi yang sama dapat berperilaku berbeda tergantung pada berapa banyak nilai yang kita berikan.

Menskalakan Ukuran Font


// Changing Font Size

display.clearDisplay();

display.setTextColor(WHITE);

display.setCursor(0,24);

display.setTextSize(2);

display.println("Hello!");

display.display();

delay(2000);

 

Sebelumnya dalam sketsa ini, kita menggunakan fungsi setTextSize() dan meneruskan angka 1 untuk mengatur ukuran font default. Namun, Anda tidak terbatas pada itu saja—Anda dapat memperbesar teks dengan meneruskan angka yang lebih besar.

Misalnya, memanggil setTextSize(2) akan membuat teks dua kali lebih besar dari ukuran 1. Anda dapat menggunakan bilangan bulat apa pun (seperti 2, 3, 4, dll.) tergantung seberapa besar teks yang Anda inginkan.

Perhatikan bahwa setiap karakter pada layar OLED digambar dalam kotak persegi panjang dengan rasio lebar dan tinggi 7:10. Jadi:

Ukuran font 1 menggambar setiap karakter dengan ukuran 7×10 piksel

Ukuran font 2 menggambar setiap karakter dengan ukuran 14×20 piksel

Ukuran font 3 akan menjadi 21×30 piksel, dan seterusnya

Menampilkan Angka


// Display Numbers

display.clearDisplay();

display.setTextSize(1);

display.setCursor(0,28);

display.println(123456789);

display.display();

delay(2000);

 

Sama seperti teks, Anda dapat menggunakan print() atau println() untuk menampilkan angka di layar. Fungsi-fungsi ini menerima nilai integer 32-bit tanpa tanda, yang berarti Anda dapat menampilkan angka mulai dari 0 hingga 4.294.967.295.

Menentukan Basis untuk Angka



// Specifying Base For Numbers

display.clearDisplay();

display.setCursor(0,28);

display.print("0x"); display.print(0xFF, HEX); 

display.print("(HEX) = ");

display.print(0xFF, DEC);

display.println("(DEC)"); 

display.display();

delay(2000);

 

Terkadang, Anda mungkin ingin menampilkan angka dalam format yang berbeda, seperti biner (basis 2), oktal (basis 8), desimal (basis 10), atau heksadesimal (basis 16). Fungsi print() dan println() memungkinkan Anda melakukannya dengan menambahkan parameter kedua yang menentukan format yang akan digunakan. Misalnya, print(78, BIN) menampilkan 1001110, sementara print(78, HEX) menampilkan 4E.

Parameter kedua ini juga dapat digunakan untuk angka desimal guna mengontrol jumlah digit yang muncul setelah desimal. Misalnya, print(1.23456, 2) akan menampilkan 1.23, dan print(1.23456, 4) akan menampilkan 1.2346.

Menampilkan Simbol ASCII



// Display ASCII Characters

display.clearDisplay();

display.setCursor(0,24);

display.setTextSize(2);

display.write(3);

display.display();

delay(2000);

 

Anda juga dapat menampilkan simbol khusus menggunakan fungsi write(). Cara kerjanya sedikit berbeda dari print()—alih-alih teks biasa, fungsi ini mengirimkan angka yang mewakili simbol ASCII langsung ke layar. Misalnya, write(3) akan menampilkan simbol hati. Ini cara yang menyenangkan untuk menambahkan ikon ke layar Anda!

Pengguliran Layar Penuh

Video

// Scroll full screen

display.clearDisplay();

display.setCursor(0,0);

display.setTextSize(1);

display.println("Full");

display.println("screen");

display.println("scrolling!");

display.display();

display.startscrollright(0x00, 0x07);

delay(2000);

display.stopscroll();

delay(1000);

display.startscrollleft(0x00, 0x07);

delay(2000);

display.stopscroll();

delay(1000);    

display.startscrolldiagright(0x00, 0x07);

delay(2000);

display.startscrolldiagleft(0x00, 0x07);

delay(2000);

display.stopscroll();

 

Jika Anda ingin pesan Anda bergerak melintasi layar, Anda dapat membuatnya bergulir. Pertama, Anda menampilkan pesan secara normal menggunakan langkah-langkah yang telah kita pelajari. Kemudian, Anda menggunakan startscrollright() atau startscrollleft() untuk membuat teks bergerak ke arah tersebut. Anda juga dapat menggunakan startscrolldiagright() atau startscrolldiagleft() untuk menggulir secara diagonal.

Masing-masing fungsi ini memerlukan dua parameter: halaman awal dan halaman akhir. Untuk informasi lebih lanjut tentang halaman-halaman tersebut, lihat bagian Peta Memori OLED. Karena layar memiliki delapan halaman, diberi nomor dari 0 hingga 7, Anda dapat menggulir seluruh layar dengan menggulir semua halaman. Untuk melakukannya, cukup berikan parameter 0x00 (untuk halaman awal) dan 0x07 (untuk halaman akhir).

Jika Anda ingin pengguliran berhenti, cukup gunakan stopscroll().

Pengguliran Bagian Tertentu



// Scroll part of the screen

display.setCursor(0,0);

display.setTextSize(1);

display.println("Scroll");

display.println("some part");

display.println("of the screen.");

display.display();

display.startscrollright(0x00, 0x00);

 

Terkadang, Anda mungkin tidak ingin menggulir seluruh layar, melainkan hanya sebagian saja. Anda dapat melakukannya dengan memberikan nilai halaman awal dan akhir yang tepat ke fungsi pengguliran. Misalnya, jika Anda memberikan nilai 0x00 untuk halaman awal dan akhir, fungsi tersebut hanya akan menggulir halaman pertama layar.

Kode Contoh ESP8266 2 – Gambar Dasar

Sketsa contoh ini menunjukkan cara menggambar bentuk sederhana seperti persegi panjang, lingkaran, dan segitiga pada layar OLED.

Silakan unggah sketsa ke Arduino Anda untuk melihat cara kerjanya sebelum kami menjelaskannya secara detail.

 

#include <SPI.h>

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>


#define SCREEN_WIDTH 128  // OLED display width, in pixels

#define SCREEN_HEIGHT 64  // OLED display height, in pixels


// Declaration for SSD1306 display connected using I2C

#define OLED_RESET -1  // Reset pin

#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


void setup() {

  Serial.begin(9600);


  // initialize the OLED object

  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {

    Serial.println(F("SSD1306 allocation failed"));

    for (;;)

      ;  // Don't proceed, loop forever

  }


  // Clear the buffer.

  display.clearDisplay();


  // Draw Rectangle

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 0);

  display.println("Rectangle");

  display.drawRect(0, 15, 60, 40, WHITE);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Draw Filled Rectangle

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 0);

  display.println("Filled Rectangle");

  display.fillRect(0, 15, 60, 40, WHITE);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Draw Round Rectangle

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 0);

  display.println("Round Rectangle");

  display.drawRoundRect(0, 15, 60, 40, 8, WHITE);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Draw Filled Round Rectangle

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 0);

  display.println("Filled Round Rectangl");

  display.fillRoundRect(0, 15, 60, 40, 8, WHITE);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Draw Circle

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 0);

  display.println("Circle");

  display.drawCircle(20, 35, 20, WHITE);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Draw Filled Circle

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 0);

  display.println("Filled Circle");

  display.fillCircle(20, 35, 20, WHITE);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Draw Triangle

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 0);

  display.println("Triangle");

  display.drawTriangle(30, 15, 0, 60, 60, 60, WHITE);

  display.display();

  delay(2000);

  display.clearDisplay();


  // Draw Filled Triangle

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0, 0);

  display.println("Filled Triangle");

  display.fillTriangle(30, 15, 0, 60, 60, 60, WHITE);

  display.display();

  delay(2000);

  display.clearDisplay();

}


void loop() {

}

 

Seperti inilah tampilan outputnya.


Anda akan melihat bahwa kode untuk mengatur tampilan sama persis dengan contoh sebelumnya. Perbedaannya di sini adalah kita menggunakan fungsi baru yang memungkinkan kita menggambar bentuk, alih-alih hanya menampilkan teks.

 

Menggambar Persegi Panjang


display.clearDisplay();

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.println("Rectangle");

display.drawRect(0, 15, 60, 40, WHITE);

display.display();

delay(2000);


display.clearDisplay();  

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.println("Filled Rectangle");

display.fillRect(0, 15, 60, 40, WHITE);

display.display();

delay(2000);

 

Untuk menggambar persegi panjang, kita menggunakan fungsi drawRect(). Fungsi ini membutuhkan lima nilai: titik awal menggambar di layar (koordinat X dan Y), lebar dan tinggi persegi panjang, dan warna yang akan digunakan. Fungsi ini hanya menggambar garis luar persegi panjang dengan batas setebal 1 piksel.

Jika Anda ingin persegi panjang terisi penuh, Anda dapat menggunakan fillRect() sebagai gantinya.

Menggambar Persegi Panjang Bulat


display.clearDisplay();

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.println("Round Rectangle");

display.drawRoundRect(0, 15, 60, 40, 8, WHITE);

display.display();

delay(2000);


display.clearDisplay();  

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.println("Filled Round Rectangl");

display.fillRoundRect(0, 15, 60, 40, 8, WHITE);

display.display();

delay(2000);

 

Untuk persegi panjang dengan sudut melengkung, gunakan drawRoundRect(). Sama seperti drawRect(), Anda memberikan koordinat X dan Y, lebar dan tinggi, serta warna. Namun, untuk persegi panjang ini, Anda juga memerlukan angka tambahan yang memberi tahu tampilan seberapa bulat sudutnya (radius sudut).

Sekali lagi, jika Anda ingin persegi panjang melengkung tersebut diisi, Anda dapat menggunakan fillRoundRect().

Menggambar Lingkaran


display.clearDisplay();

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.println("Circle");

display.drawCircle(20, 35, 20, WHITE);

display.display();

delay(2000);


display.clearDisplay();

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.println("Filled Circle");

display.fillCircle(20, 35, 20, WHITE);

display.display();

delay(2000);

 

Untuk menggambar lingkaran, gunakan fungsi drawCircle(). Di sini, alih-alih memberikan sudut kiri atas seperti yang kita lakukan pada persegi panjang, kita memberikan posisi X dan Y dari pusat lingkaran, beserta jari-jarinya, dan warnanya. Fungsi ini hanya menggambar garis luar lingkaran.

Jika Anda ingin menggambar lingkaran padat, gunakan fillCircle() dengan nilai yang sama.

Menggambar Segitiga

display.clearDisplay();

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.println("Triangle");

display.drawTriangle(30, 15, 0, 60, 60, 60, WHITE);

display.display();

delay(2000);


display.clearDisplay();

display.setTextSize(1);

display.setTextColor(WHITE);

display.setCursor(0,0);

display.println("Filled Triangle");

display.fillTriangle(30, 15, 0, 60, 60, 60, WHITE);

display.display();

delay(2000);

 

Untuk menggambar segitiga, kita menggunakan fungsi drawTriangle(). Fungsi ini sedikit berbeda karena kita perlu menyediakan tiga titik—setiap titik terdiri dari koordinat X dan Y. Ketiga titik ini mewakili titik sudut segitiga. Titik pertama adalah titik puncak, dan dua lainnya adalah titik sudut kiri dan kanan, sesuai urutan tersebut. Fungsi ini menggambar garis luar segitiga dengan menghubungkan ketiga titik tersebut dengan garis lurus. Anda juga memasukkan warna seperti sebelumnya.

Jika Anda menginginkan segitiga yang terisi, gunakan fillTriangle() dan berikan koordinat serta warna yang sama.

Contoh Kode ESP8266 3 – Menampilkan Gambar

Dalam contoh terakhir ini, kita akan mempelajari cara menampilkan gambar di layar OLED. Ini bisa sangat berguna ketika Anda ingin menampilkan hal-hal seperti logo, ikon, sprite game, atau bahkan infografis sederhana.

Untuk menampilkan gambar di OLED, pertama-tama Anda perlu mengonversi gambar tersebut menjadi sesuatu yang dapat dipahami OLED—array byte khusus. Array ini terdiri dari angka-angka yang mewakili setiap piksel dalam gambar.

Untuk memudahkan, kami telah mengembangkan alat sederhana yang membantu Anda mengubah gambar menjadi array yang dapat digunakan oleh layar OLED.

Pengonversi Gambar OLED



Bagaimana Cara Menggunakan Konverter?

Untuk memulai, unggah gambar yang ingin Anda tampilkan di layar OLED Anda.

 


Untuk contoh ini, kami memilih gambar Marilyn Monroe.

 


Setelah gambar Anda diunggah, isi kolom Identifier dengan nama yang sesuai dengan gambar Anda. Nama ini akan digunakan sebagai judul array dalam kode Arduino akhir Anda.

Karena gambar kita adalah Marilyn Monroe, kita memasukkan "MarilynMonroe" sebagai pengenal.

Sebelum melanjutkan, sangat penting untuk memastikan gambar Anda sesuai dengan resolusi layar OLED 128×64 piksel. Jika gambar Anda lebih besar dari itu, gambar mungkin tidak ditampilkan dengan benar di layar.

Anda akan melihat ukuran gambar Anda saat ini di bagian "Ukuran gambar" di Pengaturan Gambar. Untuk mengubah ukurannya, masukkan 128 untuk lebar dan 64 untuk tinggi. Kemudian, pilih opsi penskalaan yang tepat agar sesuai dengan gambar Anda. Anda juga dapat memilih untuk memusatkan gambar secara vertikal atau horizontal, dan bahkan membaliknya jika diinginkan. Semua perubahan Anda akan langsung muncul di bagian Pratinjau.

Dalam kasus kami, gambar Marilyn Monroe asli berukuran 400×300 piksel. Jadi, kami memasukkan 128 untuk lebar dan 64 untuk tinggi, memilih "skala agar pas", dan memusatkan gambar secara horizontal untuk memastikan posisinya tepat.

 


Salah satu pengaturan terpenting di sini adalah ambang batas kecerahan. Pengaturan ini menentukan piksel mana yang akan menjadi hitam atau putih. Piksel yang lebih terang dari ambang batas akan tampak putih, dan piksel yang lebih gelap akan berubah menjadi hitam. Ada juga pengaturan yang memungkinkan Anda membalikkan warna gambar, yang dapat berguna tergantung pada bagaimana Anda ingin gambar tersebut ditampilkan di layar.

Untuk gambar kita, kita atur ambang batas kecerahan ke 171 untuk menangkap lebih banyak detail dan membuat gambar lebih jernih.

Saat Anda menyesuaikan pengaturan ini, perhatikan bagian Pratinjau—bagian ini diperbarui secara real-time sehingga Anda dapat melihat dengan tepat bagaimana gambar akan muncul di OLED.

 

Setelah Anda puas dengan tampilannya, klik tombol "Buat Kode".

Selesai! Gambar Anda akan dikonversi menjadi array siap pakai yang dapat Anda salin dan tempel ke sketsa Arduino Anda.

Kode Arduino

Untuk menampilkan gambar Anda di layar OLED, masukkan array byte yang dihasilkan ke dalam sketsa Arduino di bawah ini.

 

#include <SPI.h>

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>


#define SCREEN_WIDTH 128  // OLED display width, in pixels

#define SCREEN_HEIGHT 64  // OLED display height, in pixels


// Declaration for SSD1306 display connected using I2C

#define OLED_RESET -1  // Reset pin

#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


// Bitmap of MarilynMonroe Image

const unsigned char MarilynMonroe[] PROGMEM = {

  0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xf1, 0xff, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xfc, 0x02, 0x78, 0x7f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfe, 0x03, 0x7c, 0x1f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xfe, 0x01, 0xfe, 0x1f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xfd, 0xe0, 0x03, 0xff, 0xff, 0xfc, 0x00, 0xfe, 0x0f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xfe, 0x87, 0xe0, 0xff, 0xff, 0xfc, 0x00, 0x06, 0x07, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xf9, 0xff, 0xff, 0xfc, 0x00, 0x02, 0x07, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xc3, 0xc3, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xe0, 0x0c, 0x00, 0xe7, 0x81, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x02, 0x00, 0x02, 0x00, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1e, 0x3f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0x3f, 0xf8, 0x00, 0x18, 0x7f, 0x1f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x03, 0xfc, 0x3f, 0xfc, 0x00, 0x70, 0xfe, 0x1f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xf0, 0x43, 0xff, 0xff, 0xf8, 0x7f, 0xf8, 0x00, 0x00, 0x7e, 0x1f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xf0, 0xff, 0xfc, 0x00, 0x00, 0x7c, 0x3f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf1, 0xef, 0xf8, 0x00, 0x01, 0xfc, 0x3f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xe4, 0xff, 0xff, 0xff, 0xf3, 0x80, 0xa0, 0x00, 0x07, 0xfc, 0xaf, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xec, 0x5f, 0xff, 0xff, 0xe7, 0xf0, 0x00, 0x00, 0x03, 0xfe, 0xdf, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xee, 0x7f, 0xff, 0xff, 0xc7, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xdf, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xf7, 0xc7, 0xff, 0x06, 0x00, 0x03, 0xff, 0xbf, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xfe, 0x5f, 0xff, 0xc7, 0x07, 0xff, 0x80, 0x00, 0x07, 0xdb, 0xbf, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0x80, 0x03, 0xff, 0xc0, 0x00, 0x03, 0xc3, 0x0f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x98, 0x03, 0xff, 0xf8, 0x00, 0x07, 0xe0, 0x0f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xfc, 0x01, 0x07, 0xfc, 0x1f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xcf, 0xef, 0xff, 0xff, 0xe1, 0xff, 0xfc, 0x01, 0x07, 0xf8, 0x1f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0xf8, 0x02, 0x07, 0x88, 0x3f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xcf, 0xef, 0xf8, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x07, 0x84, 0x3f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xe7, 0xef, 0xf0, 0x04, 0x7f, 0xff, 0xc0, 0x00, 0x07, 0x84, 0x7f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x3f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x06, 0x04, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x3f, 0x7f, 0xe1, 0xf0, 0x07, 0xff, 0x80, 0x00, 0x07, 0x06, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xfe, 0x03, 0xff, 0x00, 0x00, 0x03, 0x80, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xf2, 0x3f, 0xc6, 0x7f, 0x81, 0xce, 0x00, 0x00, 0x01, 0xc1, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, 0x07, 0xc1, 0xfe, 0x00, 0x00, 0x0d, 0xc0, 0x7f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, 0x01, 0xe0, 0xfc, 0x00, 0x00, 0x0f, 0xc0, 0x7f, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x50, 0xfc, 0x00, 0x00, 0x0e, 0xc0, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x18, 0xf8, 0x00, 0x00, 0x0e, 0xc1, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x66, 0x81, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xc0, 0x1f, 0xc7, 0x80, 0x00, 0xf8, 0x00, 0x01, 0xe0, 0x00, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xc0, 0x1f, 0xc1, 0xe0, 0x01, 0xf8, 0x00, 0x03, 0xf0, 0x01, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x80, 0x1f, 0xc0, 0x3e, 0x03, 0xf0, 0x00, 0x00, 0xe0, 0x03, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0xe0, 0x03, 0xf2, 0x00, 0x00, 0xc0, 0x03, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x80, 0x1f, 0xf0, 0x00, 0x07, 0xe6, 0x00, 0x00, 0xc0, 0x03, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0x00, 0x1f, 0xee, 0x00, 0x00, 0x80, 0x07, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xb8, 0x0f, 0xff, 0xf0, 0x3f, 0xdc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xbc, 0x0f, 0xff, 0xff, 0xff, 0xdc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x9e, 0x0f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x08, 0x0f, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x00, 0x0b, 0xff, 0xff, 0xfe, 0xe0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x00, 0x0b, 0xff, 0xff, 0xf9, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x3c, 0x09, 0xff, 0xff, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x1e, 0x08, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x1f, 0x08, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xce, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xfe, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff,

  0xff, 0xff, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff

};


void setup() {

  Serial.begin(9600);


  // initialize the OLED object

  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {

    Serial.println(F("SSD1306 allocation failed"));

    for (;;)

      ;  // Don't proceed, loop forever

  }


  // Clear the buffer.

  display.clearDisplay();


  // Display bitmap

  display.drawBitmap(0, 0, MarilynMonroe, 128, 64, WHITE);

  display.display();


  // Invert Display

  //display.invertDisplay(1);

}


void loop() {

}

 

Setelah Anda mengunggah sketsa ini ke Arduino Anda, gambar Anda akan muncul di layar OLED seperti di Pratinjau dari alat konverter.

 


Cobalah, dan bersenang-senanglah bereksperimen dengan gambar favorit Anda!

Penjelasan Kode

Sketsa ini dimulai sama seperti contoh sebelumnya, di mana kita pertama kali menyiapkan layar OLED. Kita menyertakan pustaka yang diperlukan dan menginisialisasi layar menggunakan fungsi begin(). Setelah pengaturan selesai, kita sekarang menambahkan gambar kustom ke layar.

Untuk melakukannya, pertama-tama kita menempatkan data gambar—array byte—di bagian global kode, di atas fungsi setup(). Array ini dihasilkan menggunakan alat konverter gambar kita, yang mengubah gambar ke dalam format yang dapat dipahami oleh layar OLED. Dalam contoh kita, array tersebut bernama MarilynMonroe.

Di dalam fungsi setup(), setelah membersihkan layar, kita menggunakan fungsi baru bernama drawBitmap() untuk menggambar gambar ke layar. Fungsi ini adalah kunci untuk menampilkan gambar dan membutuhkan enam masukan.

Dua nilai pertama adalah koordinat X dan Y, yang menentukan di mana gambar akan dimulai di layar. Dalam kasus kami, kami menetapkan keduanya ke 0, yang berarti gambar dimulai dari sudut kiri atas layar. Nilai ketiga adalah nama larik gambar yang ingin kami gambar, yang dalam contoh kami adalah Marilyn Monroe. Dua nilai berikutnya adalah lebar dan tinggi gambar—dalam piksel. Layar OLED kami memiliki lebar 128 piksel dan tinggi 64 piksel, dan gambar kami berukuran persis seperti itu, jadi kami meneruskan 128 dan 64. Parameter terakhir adalah warna. Karena kami bekerja dengan layar monokrom, kami menggunakan WHITE untuk menampilkan gambar dalam piksel putih dengan latar belakang gelap.

Jadi, baris lengkapnya terlihat seperti ini:

 

// Display bitmap

display.drawBitmap(0, 0,  MarilynMonroe, 128, 64, WHITE);

 

Namun, meskipun fungsi ini menyiapkan gambar untuk ditampilkan, gambar tersebut tidak akan benar-benar muncul di layar hingga kita memanggil display.display();. Baris ini mengirimkan semua yang telah kita siapkan di memori ke layar OLED yang sebenarnya, sehingga dapat dilihat.

 

display.display();

 

Karena gambar tidak perlu diubah atau diulang dalam contoh ini, kami membiarkan fungsi loop() kosong.




 

 

 

 

 

 

Siap Untuk Membuat Proyek Impianmu Menjadi Kenyataan?

Klik di sini untuk chat langsung via WhatsApp dan dapatkan dukungan langsung dari tim ahli kami! 

 

Posting Komentar

0 Komentar