ESP32 projelerinde harici sensörler, butonlar veya göstergelerle iletişim kurmanın en temel yolu Genel Amaçlı Giriş/Çıkış (GPIO) pinlerini yönetmektir. Bu yazıda modern ESP-IDF (v5.x) standartlarında gpio_config_t yapısını kullanarak çıkış pini sürmeyi ve butona basıldığında işlemciyi meşgul etmeden çalışan donanımsal kesme (ISR) mekanizmasını inceleyeceğiz.
1. GPIO Yapılandırma Yaklaşımı (gpio_config)
Eski yöntemlerde her pin için tek tek gpio_set_direction veya gpio_set_pull_mode çağrılırken, ESP-IDF’in önerdiği modern yaklaşım tüm parametreleri tek bir gpio_config_t struct yapısında toplayıp gpio_config() fonksiyonuna iletmektir.
pin_bit_mask: Yapılandırılacak pinlerin 64-bitlik bit maskesi.mode: Pin yönü (GPIO_MODE_OUTPUT,GPIO_MODE_INPUTvb.).pull_up_en/pull_down_en: Dahili pull-up veya pull-down dirençlerinin durumu.intr_type: Kesme tetikleme türü (GPIO_INTR_NEGEDGE,GPIO_INTR_POSEDGE,GPIO_INTR_ANYEDGE).
2. Örnek Senaryo: Buton Kesmesi ile LED Kontrolü
Senaryomuzda GPIO 2 pinine bağlı dahili LED’i çıkış, GPIO 4 pinine bağlı butonu ise pull-up dirençli giriş olarak tanımlayacağız. Butona basıldığında (Düşen Kenar / Negative Edge) bir kesme tetiklenecek ve bu olay FreeRTOS kuyruğu (Queue) üzerinden ana göreve aktarılacaktır.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"
#define LED_PIN GPIO_NUM_2
#define BUTTON_PIN GPIO_NUM_4
#define ESP_INTR_FLAG_DEFAULT 0
static const char *TAG = "GPIO_INTR";
static QueueHandle_t gpio_evt_queue = NULL;
// Kesme Hizmet Rutini (ISR Handler)
// IRAM_ATTR: Fonksiyonun flash yerine hizli erisim icin dahili RAM'de tutulmasini saglar.
static void IRAM_ATTR gpio_isr_handler(void* arg) {
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
// Buton olaylarini isleyen FreeRTOS gorevi
static void button_task(void* arg) {
uint32_t io_num;
static int led_state = 0;
for (;;) {
if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
led_state = !led_state;
gpio_set_level(LED_PIN, led_state);
ESP_LOGI(TAG, "Buton tetiklendi (GPIO %lu). LED durumu: %d", io_num, led_state);
}
}
}
void app_main(void) {
// 1. Cikis Pini Yapilandirmasi (LED)
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LED_PIN),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&io_conf);
// 2. Giris Pini ve Kesme Yapilandirmasi (Buton)
io_conf.pin_bit_mask = (1ULL << BUTTON_PIN);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.intr_type = GPIO_INTR_NEGEDGE; // Butona basildiginda tetiklenir (Active-Low)
gpio_config(&io_conf);
// 3. Kesme kuyrugunu olustur
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
// 4. Olayi dinleyecek FreeRTOS gorevini baslat
xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);
// 5. ISR servisini kur ve pini bagla
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
gpio_isr_handler_add(BUTTON_PIN, gpio_isr_handler, (void*) BUTTON_PIN);
ESP_LOGI(TAG, "GPIO yapilandirmasi basariyla tamamlandi.");
}
3. Dikkat Edilmesi Gereken Noktalar
IRAM_ATTRÖnemi: Kesme anında flash belleğe erişim kısıtlı olabileceği için ISR fonksiyonu RAM’de tutulmalıdır.- ISR İçinde Ağır İşlemlerden Kaçınma: ISR fonksiyonu içinde
printfveya gecikme (vTaskDelay) kullanılmamalıdır; veriler daima FreeRTOS Queue veya EventGroup gibi yapılarla görevlere aktarılmalıdır. - Debounce (Buton Arkı): Mekanik butonlarda parazit sıçramalarını önlemek için donanımsal filtreleme (RC filtre) veya yazılımsal debounce süre sayacı eklenmesi önerilir.