Bir GPIO pini, CPU'nun fiziksel dünyayla konuştuğu tek noktadır. Bir bit register'a yazarak bir transistörü açarsınız — o transistör 20 mA akım çeker, LED yanar. Aynı bit giriş olarak yapılandırıldığında bir butona bağlı voltaj seviyesini okur. Her GPIO işleminde yanıtlamanız gereken üç soru vardır: Yön (giriş mi, çıkış mı?), seviye (HIGH mi, LOW mu, pull-up mı?) ve reset durumu (açılışta pinin durumu ne olacak?).
Bu dersin sonunda şunları yapabileceksiniz: AVR'de DDRx/PORTx/PINx register'larını kullanarak GPIO'yu yapılandırmak ve okumak; STM32'de MODER/ODR/IDR register'larıyla aynı işlemleri yapmak; buton debounce mantığı uygulamak.
Her port için 3 kaydedici vardır:
| Kaydedici | Görevi |
|---|---|
DDRx |
Pin yönü: 1 = çıkış, 0 = giriş |
PORTx |
Çıkış değeri veya pull-up kontrolü |
PINx |
Giriş değerini okuma (salt okunur) |
{diagram:gpio-pin-states}
{diagram:gpio-control}
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
// PB5 pinini çıkış yap
DDRB |= (1 << DDB5);
while(1) {
PORTB |= (1 << PORTB5); // LED aç
_delay_ms(500);
PORTB &= ~(1 << PORTB5); // LED kapat
_delay_ms(500);
}
}
#include <avr/io.h>
int main(void) {
DDRB &= ~(1 << DDB0); // PB0 giriş
PORTB |= (1 << PORTB0); // Pull-up direnci aktif
DDRB |= (1 << DDB5); // PB5 çıkış (LED)
while(1) {
// Buton basılı mı? (aktif low — basınca GND'ye çeker)
if (!(PINB & (1 << PINB0))) {
PORTB |= (1 << PORTB5); // LED aç
} else {
PORTB &= ~(1 << PORTB5); // LED kapat
}
}
}
İpucu:
PORTB |= (1 << PORTB0)ile bir giriş pininde dahili pull-up direncini etkinleştirirsiniz. Bu sayede harici direnç kullanmanıza gerek kalmaz.
Mekanik butonlar basıldığında birkaç milisaniye boyunca titreşir (bounce). Bu durumu yazılımla çözmek gerekir:
#include <avr/io.h>
#include <util/delay.h>
uint8_t button_read(void) {
if (!(PINB & (1 << PINB0))) { // Basılı mı?
_delay_ms(20); // 20ms bekle
if (!(PINB & (1 << PINB0))) { // Hâlâ basılı?
return 1;
}
}
return 0;
}
int main(void) {
DDRB &= ~(1 << DDB0);
PORTB |= (1 << PORTB0); // Pull-up
DDRB |= (1 << DDB5); // LED çıkış
uint8_t led_state = 0;
while(1) {
if (button_read()) {
led_state ^= 1; // Toggle
PORTB ^= (1 << PORTB5);
while (!(PINB & (1 << PINB0))); // Bırakılana kadar bekle
}
}
}
STM32'de bir GPIO pinini kullanmadan önce üç adım gerekir: clock aç, mod ayarla, yaz/oku.
#include "stm32f4xx.h"
void GPIO_Init(void) {
// Adım 1 — Saat kaynaklarını aç (clock açılmadan register yazma etkisizdir)
RCC->AHB1ENR |= (1 << 0); // GPIOA clock etkinleştir
RCC->AHB1ENR |= (1 << 2); // GPIOC clock etkinleştir
// Adım 2 — PA5: çıkış modu (MODER bitler 11:10 = 01)
GPIOA->MODER &= ~(0x3 << 10); // önce temizle
GPIOA->MODER |= (0x1 << 10); // 01 = genel amaçlı çıkış
// Adım 3 — PC13: giriş modu (MODER bitler 27:26 = 00, varsayılan)
GPIOC->MODER &= ~(0x3 << 26); // 00 = giriş modu
// Dahili pull-up etkinleştir: PC13 (PUPDR bitler 27:26 = 01)
GPIOC->PUPDR &= ~(0x3 << 26);
GPIOC->PUPDR |= (0x1 << 26); // 01 = pull-up
}
int main(void) {
GPIO_Init();
while (1) {
if (!(GPIOC->IDR & (1 << 13))) { // buton basılı mı? (aktif low)
GPIOA->ODR |= (1 << 5); // PA5 HIGH — LED aç
} else {
GPIOA->ODR &= ~(1 << 5); // PA5 LOW — LED kapat
}
}
}
| Register | Görevi |
|---|---|
MODER |
Pin yönü: 00=giriş, 01=çıkış, 10=AF, 11=analog |
ODR |
Çıkış veri registerı — bit yazarak pin HIGH/LOW yapılır |
IDR |
Giriş veri registerı — salt okunur, pinin anlık durumunu verir |
PUPDR |
Pull-up/down: 00=yok, 01=pull-up, 10=pull-down |