Gömülü sistemlerde LED parlaklığı ayarlamak (dimming), DC motorların dönüş hızını kontrol etmek veya buzzer üzerinden ses tonları üretmek için Darbe Genişlik Modülasyonu (PWM – Pulse Width Modulation) kullanılır. ESP32 mikrodenetleyicisinde yazılımsal gecikmelerle PWM üretmek yerine, doğrudan bağımsız donanım zamanlayıcılarıyla çalışan ESP-IDF LEDC PWM kullanımı (LED Control Peripheral) mimarisi tercih edilir. LEDC birimi CPU’ya sıfır ek yük bindirerek donanımsal solma (fade) efektleri ve yüksek frekanslı kararlı kare dalgalar üretir.
Bu rehberde; LEDC mimarisini (hız modları, zamanlayıcılar ve kanallar), PWM frekansı ve çözünürlüğü arasındaki matematiksel ilişkiyi, ledctimerconfig ve ledcchannelconfig fonksiyonlarını ve donanımsal solma (fading) kontrolünü adım adım inşa edeceğiz.
ESP32 LEDC Donanım Mimarisi
LEDC çevre birimi iki hız grubuna ayrılmıştır:
- High Speed Mode (Yüksek Hız): 8 bağımsız kanal sunar (Sadece orijinal ESP32 çipinde bulunur; donanımsal saat senkronizasyonu vardır).
- Low Speed Mode (Düşük Hız): 8 bağımsız kanal sunar (ESP32, ESP32-S2, ESP32-S3, ESP32-C3 serilerinin hepsinde bulunur).
Toplamda 4 bağımsız donanım zamanlayıcısı (Timer 0-3) ve 8 kanal (Channel 0-7) mevcuttur. Her kanal istediği zamanlayıcıya ve herhangi bir GPIO pinine bağlanabilir.
| Parametre | Açıklama | Tipik Değer |
|---|---|---|
Frekans (freq_hz) | 1 saniyedeki PWM periyodu | LED için: 5000 Hz (5 kHz), Motor için: 20 kHz |
| Görev Oranı (Duty Cycle) | Sinyalin HIGH kaldığı süre yüzdesi | %0 (Kapalı) ~ %100 (Tam Açık) |
Çözünürlük (duty_resolution) | Duty değerinin bit hassasiyeti | 13-bit (0 – 8191), 10-bit (0 – 1023), 8-bit (0 – 255) |
Matematiksel Kural: Frekans ve çözünürlük ters orantılıdır! Kaynak saat 80 MHz (APB Clock) olduğundan:
Maksimum Frekans = 80 MHz / (2^Çözünürlük). Örneğin 13-bit çözünürlükte maksimum frekans ~9.7 kHz olabilir.
Adım 1: Zamanlayıcı (Timer) Yapılandırması
İlk olarak frekansı ve çözünürlüğü belirleyen zamanlayıcıyı kuruyoruz:
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "esp_err.h"
#include "esp_log.h"
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO 18 // PWM çıkış pini (GPIO18)
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // 13 bit çözünürlük (0 - 8191)
#define LEDC_FREQUENCY 5000 // 5 kHz frekans (Titreşimsiz LED)
static const char *TAG = "LEDC_PWM";
void init_ledc_timer(void) {
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RES,
.freq_hz = LEDC_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
}
Adım 2: PWM Kanalı (Channel) Yapılandırması
Zamanlayıcıyı belirli bir GPIO pinine bağlamak için kanal konfigürasyonu yapılır:
void init_ledc_channel(void) {
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_OUTPUT_IO,
.duty = 0, // Başlangıçta %0 duty (Kapalı)
.hpoint = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
}
Adım 3: Duty Cycle ile Parlaklık / Hız Ayarlamak
Manuel olarak duty değerini değiştirmek için ledcsetduty ve ardından değişikliği donanıma aktaran ledcupdateduty çağrılır:
void set_pwm_duty(uint32_t duty_val) {
// 13-bit için duty_val 0 ile 8191 arasında olmalıdır
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty_val));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
}
Örneğin %50 güç vermek için:
// 8191 * 0.50 ≈ 4095
set_pwm_duty(4095);
Adım 4: Donanımsal Solma Efekti (Hardware Fading)
ESP32 LEDC modülünün en etkileyici özelliklerinden biri donanımsal fading (nefes alma / fade) motorudur. CPU hiçbir for döngüsüne girmeden, donanım belirlediğiniz süre boyunca parlaklığı kendisi kademeli olarak artırır veya azaltır!
Bunun için önce solma servisi kurulmalıdır:
void app_main(void) {
init_ledc_timer();
init_ledc_channel();
// Donanımsal fade sürücüsünü başlat
ESP_ERROR_CHECK(ledc_fade_func_install(0));
ESP_LOGI(TAG, "LEDC Başlatıldı. Donanımsal nefes alma döngüsü başlıyor...");
while (1) {
// 1. Parlaklığı 0'dan 8191'e (Maksimum) 2 saniyede (2000 ms) çıkar
ESP_LOGI(TAG, "LED Parlıyor...");
ESP_ERROR_CHECK(ledc_set_fade_with_time(LEDC_MODE, LEDC_CHANNEL, 8191, 2000));
ESP_ERROR_CHECK(ledc_fade_start(LEDC_MODE, LEDC_CHANNEL, LEDC_FADE_WAIT_DONE));
vTaskDelay(pdMS_TO_TICKS(500)); // En tepe noktada 500ms bekle
// 2. Parlaklığı 8191'den 0'a (Karanlık) 2 saniyede indir
ESP_LOGI(TAG, "LED Sönüyor...");
ESP_ERROR_CHECK(ledc_set_fade_with_time(LEDC_MODE, LEDC_CHANNEL, 0, 2000));
ESP_ERROR_CHECK(ledc_fade_start(LEDC_MODE, LEDC_CHANNEL, LEDC_FADE_WAIT_DONE));
vTaskDelay(pdMS_TO_TICKS(500));
}
}
Not:
LEDCFADEWAITDONEparametresi solma işlemi bitene kadar mevcut görevi bloklar. Eğer solmanın arka planda sessizce gerçekleşmesini ve kodunuzun hemen akmasını istiyorsanızLEDCFADENOWAITkullanabilirsiniz.
Motor Sürücüleri (H-Bridge) ve Servo Motorlar İçin Notlar
- DC Motor Kontrolü: L298N veya DRV8833 gibi motor sürücülerinde PWM frekansını 20 kHz üzerine çıkarmak insan kulağının duyduğu tiz motor uğultusunu (whine) tamamen keser.
- Servo Motor Kontrolü: Standart SG90 / MG996R servoları 50 Hz frekans (
LEDC_FREQUENCY = 50) ve 1 ms – 2 ms arası pulse süresi bekler. Çözünürlüğü 14-bit veya 15-bit seçerek 50 Hz üzerinde son derece hassas açı kontrolleri yapabilirsiniz.
Özet
ESP-IDF’in LEDC çevre birimi, donanımsal bağımsızlığı sayesinde pürüzsüz ve kararlı PWM üretimi sağlar. Zamanlayıcı ve kanal mimarisi ile aynı anda onlarca LED’i veya motoru CPU yükü oluşturmadan kontrol edebilir, yerleşik fading fonksiyonlarıyla profesyonel aydınlatma efektleri tasarlayabilirsiniz.