ESP32 Kesmeler (Interrupts) mekanizması; ana işlemciyi sürekli olarak pini okumak zorunda bırakmadan (polling), pinde elektriksel bir durum değişimi olduğunda ana kod akışını donanımsal düzeyde durdurup acil durum fonksiyonunu (ISR) devreye sokan güçlü bir altyapıdır.
Gömülü sistem tasarımında, mikrodenetleyicinin dış dünyada meydana gelen anlık fiziksel olaylara (örneğin bir butona basılması, bir sensörün eşik değerini aşması veya acil durum sinyali gelmesi) milisaniyeler hatta mikrosaniyeler düzeyinde tepki vermesi kritik önem taşır.
Bu rehberimizde, ESP32’nin donanımsal kesme mimarisini, kesme servis rutinlerinde (ISR) IRAM_ATTR özniteliğinin önemini, volatile değişken kullanımını, delay() yerine millis() ile engellemesiz (non-blocking) zamanlama fiziğini ve PIR hareket sensörlü kararlı bir kesme projesini en ince mühendislik detaylarıyla inceleyeceğiz.

ESP32 entegresini Arduino IDE kullanarak programlayacağız. Gerekli kütüphane paketleri ve kart yöneticisi ayarları için Arduino IDE’ye ESP32 Desteği Kurmak kılavuzumuza göz atabilirsiniz. Ayrıca, kesme servis fonksiyonlarının arka planında yer alan donanım yapısı için resmi ESP32 Arduino GitHub Core deposunu inceleyebilirsiniz.
ESP32 Kesmeler (Interrupts) Nedir ve Donanımsal Çalışma Fiziği?
Geleneksel mikrodenetleyici programlamasında, bir pindeki değişimleri algılamak için loop() fonksiyonu içerisinde sürekli olarak digitalRead() sorgulaması yapılır. Bu yönteme sorgulama (polling) adı verilir. Sorgulama yöntemi işlemciyi %100 yük altında çalıştırarak yüksek güç tüketimine neden olduğu gibi, kodun başka bir yerinde yapılan yoğun bir işlem (örn. Wi-Fi veri transferi) esnasında pindeki anlık değişimlerin kaçırılmasına (latency) yol açar.
Kesmeler (Interrupts) ise bu problemi tamamen ortadan kaldırır. ESP32 donanımında kesme kurulduğunda, işlemci pin durumunu takip etmeyi tamamen bırakır. İlgili pinde elektriksel bir durum değişimi gerçekleştiğinde, donanımsal kesme denetleyicisi (Interrupt Controller) Xtensa CPU çekirdeğine bir sinyal gönderir. CPU, o anda yürüttüğü ana kod satırını tamamen dondurarak kaydedicilerini (registers) yığına (stack) yedekler ve Kesme Servis Rutini (ISR – Interrupt Service Routine) adı verilen özel acil durum fonksiyonunu çalıştırır. ISR fonksiyonu tamamlandıktan sonra, işlemci yedeklediği kaydedici verilerini geri yükleyerek kaldığı ana kod satırından çalışmaya devam eder.
Kesme Atama Fonksiyonu: attachInterrupt()
Arduino IDE ortamında bir GPIO pinine donanımsal kesme atamak için attachInterrupt() fonksiyonu kullanılır. Bu fonksiyon üç temel argüman kabul eder:
attachInterrupt(digitalPinToInterrupt(GPIO), ISR_Fonksiyonu, mod);1. digitalPinToInterrupt(GPIO): Kesme atanacak fiziksel GPIO pininin donanımsal kesme kanal eşlemesini yapar. ESP32, dahili matrisi sayesinde tüm genel amaçlı giriş/çıkış (GPIO) pinlerinde kesme özelliğini destekler. Aşağıdaki diyagramda kesme pini olarak atanabilen tüm GPIO pinleri kırmızı ile çerçevelenmiştir:

2. ISR_Fonksiyonu: Kesme tetiklendiğinde çalıştırılacak olan geri çağırım (callback) fonksiyonudur. Kesme servis rutinlerinin son derece hızlı çalışması gerektiğinden, bu fonksiyon parametre alamaz ve değer döndüremez (void olmalıdır).
3. Mod (Tetikleme Koşulu): Pindeki hangi elektriksel değişim tipinde kesmenin tetikleneceğini belirler. ESP32 donanımında 5 farklı tetikleme modu mevcuttur:
- LOW: Pin voltajı mantıksal DÜŞÜK (
) seviyesinde olduğu sürece kesmeyi sürekli tetikler. - HIGH: Pin voltajı mantıksal YÜKSEK (
) seviyesinde olduğu sürece kesmeyi sürekli tetikler. - CHANGE: Pindeki her voltaj değişimi (düşükten yükseğe veya yüksekten düşüğe geçiş) anında kesmeyi tetikler.
- FALLING: Pindeki düşen kenar tetiklemesidir. Pin voltajı yüksekten (
) düşüğe (
) geçerken kesmeyi tetikler. - RISING: Pindeki yükselen kenar tetiklemesidir. Pin voltajı düşükten (
) yükseğe (
) geçerken kesmeyi tetikler. (PIR hareket sensörlü projelerde yükselen kenar tetiklemesi kullanılır).
Zamanlayıcılar ve millis() Fiziği (delay() Sorunu)
Kesme tetiklendikten sonra bir eylemin (örneğin bir motorun veya LED’in) belirli bir süre boyunca çalışıp ardından otomatik kapanmasını isteyebiliriz. Bu durumlarda geliştiriciler genellikle kodun akışını tamamen durduran delay() fonksiyonuna başvururlar.

delay() Neden Tehlikelidir? (Engelleme / Blocking)
delay() fonksiyonu, mikrodenetleyici çekirdeğini parametre olarak iletilen süre boyunca boş bir döngüde kilitleyerek (busy-waiting) bekletir. Bu süre boyunca CPU hiçbir kodu yürütemez, veri paketlerini işleyemez ve diğer sensörleri okuyamaz. Özellikle Wi-Fi veya Bluetooth gibi kablosuz ağ yığınlarını koşturan ESP32 gibi çift çekirdekli sistemlerde, ana loop’un
saniyeden fazla kilitlenmesi, dahili bekçi köpeği zamanlayıcısının (Task Watchdog Timer) sistemi resetlemesine veya “Guru Meditation Error” ile kilitlenmesine neden olur. Bu yüzden profesyonel gömülü sistem yazılımlarında delay() asla kullanılmaz.
millis() ve İkiye Tamamlama Taşması (Rollover) Güvenliği
Engellemesiz (non-blocking) zamanlama gerçekleştirmek için dahili millis() fonksiyonu kullanılır. Bu fonksiyon, ESP32 boot ettiği andan itibaren geçen süreyi milisaniye cinsinden unsigned long (32-bit işaretsiz tam sayı) formatında döner.
32-bit işaretsiz bir sayı maksimum
değerini alabilir. Bu değer yaklaşık 49.7 gün eder. 49.7 günün sonunda milisaniye sayacı taşarak (rollover) sıfıra sıfırlanır. Geliştiriciler bu taşmanın zamanlama kontrol mantığında büyük hatalara yol açacağını düşünürler. Ancak ikiye tamamlama (two’s complement) matematiksel aritmetiği sayesinde, zamanlama karşılaştırması çıkarma işlemiyle yapıldığı sürece taşma hatası tamamen bypass edilir:
![]()
Eğer çıkarma işlemi işaretsiz tam sayılar (unsigned) arasında gerçekleştiriliyorsa,
değeri sıfırlanmış olsa bile, aritmetik otomatik olarak doğru farkı verecektir. Bu yüzden if (millis() - previousMillis >= interval) yapısı %100 taşma güvenlidir.
millis() ile Engellemesiz LED Blink Kod Yapısı
const int ledPin = 26;
int ledDurumu = LOW;
unsigned long previousMillis = 0;
const long aralik = 1000; // 1 saniye (1000 ms)
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
// Çıkarma işlemi ikiye tamamlama taşma korumasına sahiptir
if (currentMillis - previousMillis >= aralik) {
previousMillis = currentMillis;
// LED durumunu evir (toggle)
ledDurumu = (ledDurumu == LOW) ? HIGH : LOW;
digitalWrite(ledPin, ledDurumu);
}
// Buraya yazılacak diğer tüm kodlar, delay engellemesi olmadan normal şekilde çalışır.
}
Eğer ESP32 projelerinizde kod yükleme aşamalarında beklenmeyen donanımsal hatalarla karşılaşıyorsanız, kapsamlı çözüm önerilerimiz için ESP32 Hataları ve Çözümleri kılavuzumuza göz atabilirsiniz.
ESP32 PIR Hareket Sensörü ve Donanımsal Kesme Projesi
Zamanlayıcı ve kesme teorisini pratiğe dökmek amacıyla; bir PIR hareket sensörü hareket algıladığında donanımsal kesme tetikleyecek, bu tetikleme ile bir LED’i yakıp arka planda engellemesiz zamanlayıcı başlatacak ve süre dolduğunda LED’i otomatik kapatacak profesyonel projeyi kuracağız.
Devre Şeması
LED’i
koruma direnci ile GPIO 26 pinine bağlayın.
voltaj ile çalışan hassas PIR Hareket Sensörünün sinyal bacağını ise donanımsal kesme pini olan GPIO 27 pinine bağlayın:

Kritik Donanım Notu: Klasik HC-SR501 gibi bazı PIR modülleri varsayılan olarak
voltaj ile çalışır ve sinyal hattından
verir. Eğer elinizdeki modül
ise, besleme ucunu ESP32’nin
pini yerine doğrudan USB beslemesini taşıyan VIN / 5V pinine bağlamanız gerekir. Sinyal hattı
seviyesini aşmamalıdır, aksi takdirde ESP32 pinleri hasar görebilir.
Profesyonel Arduino Proje Kodu
Aşağıdaki kod bloğunda, kesme fonksiyonunun hızlı çalışması için gerekli IRAM_ATTR RAM özniteliği kullanılmış ve çoklu çekirdek optimizasyonu için veri kararlılığını garanti eden volatile anahtar kelimeleri yerleştirilmiştir:
// Hareket algılandıktan sonra LED'in açık kalacağı süre (Saniye cinsinden)
#define AKTIF_SURE_SANIYE 10
// Pin Tanımlamaları
const int ledPin = 26;
const int motionSensorPin = 27;
// volatile: Derleyicinin bu değişkenleri CPU kaydedicilerinde önbelleğe almasını engeller.
// Bu sayede değişkenler hem ana loop hem de ISR tarafından güvenle anlık güncellenir.
volatile unsigned long sonTetiklemeZamani = 0;
volatile boolean zamanlayiciAktif = false;
// IRAM_ATTR: Kesme Servis Rutinini (ISR) dahili hızlı RAM'e yerleştirir.
// Eğer kod flash bellekten çalıştırılsaydı, SPI flash okuma gecikmeleri ve önbellek kaçırmaları
// watchdog resetlerine (Guru Meditation) yol açabilirdi.
void IRAM_ATTR hareketTespitISR() {
// NOT: Geliştirme aşamasında Serial.println kullanılabilir fakat kararlı üretim (production)
// yazılımlarında kesme servis rutinleri içerisinde asla Serial veya delay fonksiyonları çağrılmamalıdır!
digitalWrite(ledPin, HIGH);
zamanlayiciAktif = true;
sonTetiklemeZamani = millis(); // Zamanlayıcıyı anlık sıfırla
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("ESP32 Kesme Projesi Yapılandırılıyor...");
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW); // LED varsayılan olarak kapalı
// Dahili gürültüleri engellemek için pull-up direncini aktif et
pinMode(motionSensorPin, INPUT_PULLUP);
// Yükselen kenar tetiklemesi ile kesmeyi ata (Düşükten Yükseğe Geçiş)
attachInterrupt(digitalPinToInterrupt(motionSensorPin), hareketTespitISR, RISING);
Serial.println("Kesme başarıyla atandı. Hareket bekleniyor...");
}
void loop() {
unsigned long simdi = millis();
// Eğer zamanlayıcı aktif edilmişse ve tanımlanan süre aşılmışsa LED'i söndür
if (zamanlayiciAktif && (simdi - sonTetiklemeZamani > (AKTIF_SURE_SANIYE * 1000))) {
Serial.println("Hareket durdu, zamanlayıcı doldu. LED Kapatılıyor.");
digitalWrite(ledPin, LOW);
zamanlayiciAktif = false;
}
// loop içindeki bu boş alana delay() içermeyen başka işlemlerinizi ekleyebilirsiniz.
}Mühendislik Detayları ve IRAM_ATTR Fiziği: ESP32 mimarisinde, IRAM_ATTR özniteliği ile işaretlenen fonksiyonlar derleme aşamasında mikrodenetleyicinin Instruction RAM (IRAM) adı verilen dahili hızlı önbellek bölgesine yüklenir. Eğer bu öznitelik kullanılmasaydı, kesme çağrıldığında CPU, flash bellekten kodu okumaya çalışacaktı. Flash bellek okumaları, işlemciye kıyasla son derece yavaş veri yolları üzerinden gerçekleştiğinden, kesme anında milisaniyeler seviyesinde gecikme (interrupt latency) oluşacak ve hatta eş zamanlı çalışan Wi-Fi/Bluetooth ağ yığınlarının kesintiye uğramasına yol açarak sistemin çökmesine neden olacaktı.
Özetlemek gerekirse; ESP32’de kesmeler (interrupts), donanım kaynaklarını en verimli şekilde kullanarak milisaniyeler seviyesinde gecikmesiz kararlı sistemler tasarlamanızı sağlar. Gecikmesiz zamanlayıcılar (millis) ve IRAM_ATTR gibi mühendislik pratiklerini kodlarınıza entegre ederek, endüstriyel kalitede kesintisiz gömülü yazılımlar geliştirebilirsiniz.
Yorum yapma özelliği, forum tarafından gelen istek sebebiyle kapatılmıştır. Lütfen tartışmalar ve sorularınız için topluluk forumumuza katılın.

