Belajar ESP32: PWM (Pulse Width Modulation)

Pada artikel sebelumnya, kita sudah berhasil menampilkan data di layar OLED SSD1306. Sekarang kita akan membahas salah satu fitur penting ESP32 yang sering digunakan dalam proyek IoT, yaitu PWM (Pulse Width Modulation).

Dengan PWM, kita bisa “menipu” perangkat elektronik agar seolah-olah mendapatkan sinyal analog, padahal ESP32 hanya menghasilkan sinyal digital. Ini berguna untuk mengatur kecerahan LED, kecepatan motor DC, sudut servo, dan berbagai aplikasi lainnya.

Apa Itu PWM?

PWM (Pulse Width Modulation) adalah teknik memodulasi sinyal digital dengan cara mengubah lebar pulsa (durasi HIGH) dalam setiap periode sinyal. Meskipun sinyalnya tetap digital (hanya bernilai HIGH atau LOW), efek rata-ratanya bisa menyerupai sinyal analog.

Ada dua konsep utama dalam PWM:

  • Frekuensi — seberapa cepat sinyal berosilasi antara HIGH dan LOW, diukur dalam Hz
  • Duty Cycle — persentase waktu sinyal berada pada kondisi HIGH dalam satu periode

Contoh Duty Cycle

Duty CycleKondisiEfek pada LED
0%Selalu LOWLED mati
25%HIGH 1/4 waktuLED redup
50%HIGH setengah waktuLED setengah terang
75%HIGH 3/4 waktuLED cukup terang
100%Selalu HIGHLED penuh

LED PWM Controller pada ESP32

ESP32 memiliki LED PWM Controller (LEDC) yang dirancang khusus untuk menghasilkan sinyal PWM. Bergantung pada model ESP32, tersedia 6 hingga 16 channel PWM independen yang dapat dikonfigurasi secara terpisah.

Terdapat dua cara menggunakan PWM pada ESP32 dengan Arduino IDE:

  1. analogWrite() — cara paling sederhana, mirip dengan Arduino
  2. LEDC API — cara yang lebih lengkap dengan kontrol frekuensi dan resolusi penuh

Wiring: LED dengan Resistor

Untuk semua latihan di artikel ini, kita akan menggunakan satu LED yang dihubungkan ke GPIO 16 melalui resistor.

KomponenKoneksi
LED (anoda / kaki panjang)GPIO 16 (RX2) melalui resistor 330Ω
LED (katoda / kaki pendek)GND

Catatan: Hampir semua pin GPIO ESP32 yang bisa berfungsi sebagai output dapat digunakan sebagai pin PWM. Tidak ada pin khusus yang harus digunakan.

Metode 1: Menggunakan analogWrite()

image

Cara paling mudah menggunakan PWM di ESP32 adalah dengan fungsi analogWrite(), sama seperti pada Arduino.

void analogWrite(uint8_t pin, int value);

Parameter value bernilai antara 0 (mati) hingga 255 (terang penuh).

Contoh: LED Fade dengan analogWrite

const int ledPin = 16;

void setup() {
pinMode(ledPin, OUTPUT);
}

void loop() {
// Tingkatkan kecerahan dari 0 ke 255
for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {
analogWrite(ledPin, dutyCycle);
delay(15);
}

// Kurangi kecerahan dari 255 ke 0
for (int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {
analogWrite(ledPin, dutyCycle);
delay(15);
}
}

Penjelasan Program

Di setup(), kita cukup mendefinisikan pin sebagai OUTPUT. Tidak ada konfigurasi tambahan yang diperlukan.

pinMode(ledPin, OUTPUT);

Di loop(), dua buah for-loop menaikkan dan menurunkan nilai duty cycle secara bertahap dari 0 ke 255 dan sebaliknya. Setiap perubahan diberi jeda 15ms agar transisi terlihat halus.

analogWrite(ledPin, dutyCycle);

Upload kode ini ke ESP32. Anda akan melihat LED menyala secara perlahan kemudian meredup, berulang terus menerus.

Mengatur Frekuensi dan Resolusi

Jika diperlukan, kita juga bisa mengatur frekuensi dan resolusi PWM pada pin tertentu:

// Mengatur resolusi (bit): semakin tinggi, semakin halus gradasi
analogWriteResolution(ledPin, 10); // resolusi 10-bit (0-1023)

// Mengatur frekuensi (Hz)
analogWriteFrequency(ledPin, 5000); // frekuensi 5 kHz

Metode 2: Menggunakan LEDC API

LEDC API memberikan kontrol yang lebih lengkap dan eksplisit atas sinyal PWM. Ini adalah cara yang direkomendasikan jika kita perlu mengatur frekuensi, resolusi, dan channel secara manual.

Fungsi-fungsi Utama LEDC

ledcAttach() — mengatur pin PWM dengan frekuensi dan resolusi, channel dipilih otomatis:

bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution);

ledcAttachChannel() — seperti ledcAttach() tetapi dengan pemilihan channel manual:

bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel);

ledcWrite() — mengatur duty cycle pada pin yang sudah di-attach:

void ledcWrite(uint8_t pin, uint32_t duty);

Contoh: LED Fade dengan LEDC API

const int ledPin      = 16;
const int freq = 5000; // 5 kHz
const int resolution = 8; // 8-bit: nilai 0-255

void setup() {
// Attach pin ke LEDC dengan frekuensi dan resolusi yang ditentukan
ledcAttach(ledPin, freq, resolution);
}

void loop() {
// Tingkatkan kecerahan
for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {
ledcWrite(ledPin, dutyCycle);
delay(15);
}

// Kurangi kecerahan
for (int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {
ledcWrite(ledPin, dutyCycle);
delay(15);
}
}

Perbandingan analogWrite vs LEDC API

AspekanalogWrite()LEDC API
Kemudahan✅ Sangat mudah⚙️ Perlu setup
Kontrol frekuensiTerbatas✅ Penuh
Kontrol resolusiTerbatas✅ Penuh
Channel manual✅ Bisa
Cocok untukProyek sederhanaProyek kompleks

Eksperimen Tambahan 1: Tiga LED dengan Kecerahan Berbeda

Kita bisa menjalankan beberapa channel PWM secara bersamaan untuk mengontrol beberapa LED secara independen.

const int ledPins[]    = {16, 17, 18};
const int freq = 5000;
const int resolution = 8;

void setup() {
for (int i = 0; i < 3; i++) {
ledcAttach(ledPins[i], freq, resolution);
}
}

void loop() {
// LED pertama: kecerahan penuh
ledcWrite(ledPins[0], 255);

// LED kedua: kecerahan setengah
ledcWrite(ledPins[1], 127);

// LED ketiga: kecerahan sangat rendah
ledcWrite(ledPins[2], 30);

delay(2000);

// Matikan semua
for (int i = 0; i < 3; i++) {
ledcWrite(ledPins[i], 0);
}

delay(1000);
}

Tambahkan tiga LED ke GPIO 16, 17, dan 18 masing-masing dengan resistor 330Ω. Anda akan melihat perbedaan kecerahan yang jelas di antara ketiganya.

Eksperimen Tambahan 2: Kontrol Kecerahan Berdasarkan Input Potentiometer

ADC Pin

Disini kita akan menggunakan Potentiometer (Pot) yakni B50K. Maka dari itu kita perlu memahami pin mana saja yang bisa digunakan oleh Pot ini sebagai outputnya.

image
https://lastminuteengineers.com/esp32-pinout-reference/#esp32-adc-pins

PWM menjadi lebih interaktif ketika kita menggabungkannya dengan pembacaan sensor analog. Berikut contoh mengatur kecerahan LED menggunakan potensiometer.

const int ledPin  = 16;
const int potPin = 15; // GPIO 15 adalah ADC input

void setup() {
Serial.begin(115200);
ledcAttach(ledPin, 5000, 8); // frekuensi 5kHz, resolusi 8-bit
}

void loop() {
// Baca nilai potentiometer (0 - 4095, ADC 12-bit)
int potValue = analogRead(potPin);

// Peta nilai ADC (0-4095) ke duty cycle PWM (0-255)
int dutyCycle = map(potValue, 0, 4095, 0, 255);

ledcWrite(ledPin, dutyCycle);

Serial.print("Pot: ");
Serial.print(potValue);
Serial.print(" | Duty Cycle: ");
Serial.println(dutyCycle);

delay(50);
}

Hubungkan potensiometer ke 3.3V, GND, dan GPIO 15. Putar potensiometer dan kecerahan LED akan berubah secara real-time. Fungsi map() sangat berguna untuk mengonversi rentang nilai ADC (0–4095) ke rentang duty cycle PWM (0–255).

Eksperimen Tambahan 3: PWM + OLED — Tampilkan Duty Cycle di Layar

image

Menggabungkan PWM dengan OLED yang sudah kita pelajari sebelumnya menghasilkan perangkat yang interaktif sekaligus informatif.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C

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

const int ledPin = 16;
const int potPin = 15;

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

if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println("OLED gagal!");
for (;;);
}

ledcAttach(ledPin, 5000, 8);
}

void loop() {
int potValue = 0;

// Smoothing
for (int i = 0; i < 10; i++) {
potValue += analogRead(potPin);
}
potValue /= 10;

int dutyCycle = map(potValue, 0, 4095, 0, 255);
int persen = map(dutyCycle, 0, 255, 0, 100);

// Filter perubahan kecil
static int lastPersen = -1;
if (abs(persen - lastPersen) > 2) {
lastPersen = persen;

ledcWrite(ledPin, dutyCycle);

// Update OLED
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);

display.setTextSize(1);
display.setCursor(8, 0);
display.println("== PWM Controller ==");

display.setTextSize(3);
display.setCursor(40, 20);
display.print(persen);
display.println("%");

// Progress bar sederhana
int barWidth = map(persen, 0, 100, 0, 120);
display.drawRect(4, 52, 120, 10, SSD1306_WHITE);
display.fillRect(4, 52, barWidth, 10, SSD1306_WHITE);

display.display();
}

delay(100);
}

Hasilnya adalah layar OLED yang menampilkan persentase duty cycle secara real-time beserta progress bar visual, sementara LED berubah kecerahan mengikuti putaran potensiometer.

Kesimpulan

PWM adalah teknik fundamental dalam pemrograman mikrokontroler yang memungkinkan kita menghasilkan output “analog” dari pin digital. ESP32 menyediakan dua cara untuk menggunakannya: analogWrite() yang sederhana, dan LEDC API yang lebih lengkap.

Poin-poin penting yang sudah kita pelajari:

  • PWM bekerja dengan mengubah duty cycle — persentase waktu sinyal berada pada kondisi HIGH
  • ESP32 memiliki LEDC dengan hingga 16 channel PWM independen
  • analogWrite() cocok untuk penggunaan cepat dan sederhana
  • LEDC API (ledcAttach + ledcWrite) memberikan kontrol penuh atas frekuensi dan resolusi
  • PWM dapat dikombinasikan dengan ADC (potensiometer) dan OLED untuk membuat sistem kontrol yang interaktif

Dengan memahami PWM, kita sudah selangkah lebih maju menuju proyek IoT yang lebih kompleks, seperti sistem kontrol lampu pintar, kendali motor, atau sistem otomasi berbasis sensor.

Referensi

Tinggalkan Komentar

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Scroll to Top