Bir cümlelik özet
Uzun ve karışık bir loop() fonksiyonunu küçük, adı anlamlı fonksiyonlara bölerek kodu daha okunabilir, tekrar kullanılabilir ve test edilebilir hâle getiririz.
Neden önemli?
Bir Arduino projesi büyüdükçe loop() fonksiyonu şişer. Sensör okuma, hesaplama, LED yakma, buzzer çaldırma ve seri porta yazma; hepsi alt alta dizilir. Bir süre sonra kendi kodunu okumak bile zorlaşır. "Bu satır ne yapıyordu?" diye üstünde dakikalarca düşünürsün.
Python dersinde fonksiyon fikrini görmüştük: bir işi bir kez tanımlar, sonra adıyla çağırırdık. Arduino'nun dili (C/C++) de tam olarak aynı fikri kullanır. readDistance() yazdığında, o işin nasıl yapıldığını bilmene gerek kalmaz; adına bakıp ne yaptığını anlarsın.
Bunu günlük hayattan iki örnekle düşünebilirsin:
- Yemek tarifi: "Hamuru hazırla", "fırını ısıt", "üzerini süsle" başlıklarına bölünmüş bir tarif, tek paragraf hâlinde yazılmış tariften çok daha kolay takip edilir.
- Okul çantası: Kalemler bir bölmede, kitaplar başka bölmede durur. Her şey tek bir gözde olsaydı aradığını bulmak zaman alırdı.
Fonksiyonlara bölmek de kodun için tam olarak bu bölmeleri açmaktır.
Fonksiyon nedir, nasıl yazılır?
Bir fonksiyon, bir işi yapan ve ona bir ad verdiğimiz kod parçasıdır. Onu bir kez yazar, istediğimiz kadar çağırırız.
Arduino'da zaten iki fonksiyon kullanıyorsun: setup() bir kez çalışır, loop() sürekli tekrar eder. Şimdi kendi fonksiyonlarımızı ekleyeceğiz.
En basit fonksiyon
Aşağıdaki fonksiyon bir iş yapar ama geriye bir değer döndürmez. Bu yüzden başına void yazarız (Türkçesi "boş", yani "geri dönen değer yok").
void beepOnce() {
tone(4, 1000); // 4 numaralı pime 1000 Hz ses ver
delay(200);
noTone(4); // sesi durdur
}
Bu fonksiyonu loop() içinde tek satırla çağırırsın: beepOnce();. Kod okunurken "burada bir kez bip çalıyor" demek yeter; detaylar fonksiyonun içinde saklı kalır.
return: geriye değer döndürmek
Bazı fonksiyonlar bir iş yapıp sonucu geri verir. Python'da return kullanıyorduk; C/C++ de aynı kelimeyi kullanır. Geri dönen değerin türünü fonksiyonun başına yazarız. Tam sayı döndüren bir fonksiyonun başına int, uzun tam sayı için long yazarız.
int readTemperature() {
int raw = analogRead(A0); // sensörü oku
int celsius = raw / 4; // basit bir dönüşüm örneği
return celsius; // sonucu geri döndür
}
Artık int t = readTemperature(); yazarak sıcaklığı bir değişkene alabilirsin. Fonksiyonun içindeki return, "işim bitti, işte cevabım" demektir.
Önce: her şey loop içinde
Şimdi gerçek bir örneğe bakalım. Bir mesafe sensörü (HC-SR04), bir LED ve bir buzzer var. Amaç: bir nesne 10 santimetreden yakına gelince LED yansın ve buzzer ötsün. Bir sonraki dersteki park sensörünün tam kalbi budur.
İlk denemede çoğu kişi her şeyi loop() içine yazar:
const int trigPin = 9;
const int echoPin = 10;
const int ledPin = 3;
const int buzzerPin = 4;
void setup() {
Serial.begin(9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
}
loop() ise şöyle uzar:
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
int distance = duration / 58; // mikrosaniyeyi cm'ye çevir
Serial.println(distance);
if (distance < 10) {
digitalWrite(ledPin, HIGH);
tone(buzzerPin, 1000);
} else {
digitalWrite(ledPin, LOW);
noTone(buzzerPin);
}
delay(100);
}
Bu kod çalışır. Ama loop() iki ayrı işi birbirine karıştırıyor: sensörü *okumak* ve uyarıyı *göstermek*. İkisi tek yığın hâlinde duruyor.
Sonra: işleri fonksiyonlara ayırmak
Şimdi aynı işi ikiye bölelim. Bir fonksiyon sadece sensörü okuyup mesafeyi döndürsün; bir fonksiyon da sadece uyarıyı göstersin. setup() aynı kalır.
Önce okuma işi. Bu fonksiyon bir int değer döndürür:
int readDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
return duration / 58; // cm cinsinden mesafeyi döndür
}
Sonra uyarı işi. Bu fonksiyon dışarıdan bir mesafe alır (parametre) ve geriye değer döndürmediği için void'dur:
void showAlert(int distance) {
if (distance < 10) {
digitalWrite(ledPin, HIGH);
tone(buzzerPin, 1000);
} else {
digitalWrite(ledPin, LOW);
noTone(buzzerPin);
}
}
Artık loop() inanılmaz sadeleşir. Tek bakışta ne yaptığını okuyabilirsin:
void loop() {
int distance = readDistance(); // oku
Serial.println(distance);
showAlert(distance); // uyar
delay(100);
}
Mantık birebir aynı; hiçbir satır kayboldu değil. Sadece iki iş iki kutuya girdi. Yarın buzzer yerine ekran eklemek istersen, sadece showAlert() içini değiştirirsin; okuma kısmına dokunmazsın.
Mini uygulama
Yukarıdaki "sonra" örneğini kendi projene uyarla. Bu kez uyarı mantığını üç kademeye ayır ve showAlert() fonksiyonunu geliştir.
Hedef davranış:
- Mesafe 20 cm'den büyükse: LED sönük, ses yok (güvenli).
- Mesafe 10–20 cm arasıysa: LED yanık, ses yok (dikkat).
- Mesafe 10 cm'den küçükse: LED yanık ve buzzer ötüyor (tehlike).
readDistance() fonksiyonuna hiç dokunma. Sadece showAlert() içindeki if yapısını genişlet. Test etmek için elini sensöre yavaşça yaklaştır ve seri ekrandaki (Serial Monitor) sayıya bakarak üç durumun da doğru çalıştığını gör.
İpucu: else if kullanarak orta kademeyi ekleyebilirsin.
Uygulama laboratuvarı: Kod Yapısını Fonksiyonlara Bölmek
Kod Yapısını Fonksiyonlara Bölmek konusunu kalıcı hâle getirmenin en iyi yolu, kavramı küçük ve ölçülebilir bir göreve dönüştürmektir. Bu çalışmada Fonksiyon nedir, nasıl yazılır? ile return: geriye değer döndürmek arasındaki ilişkiyi kullanarak bağlantı şeması, derlenebilen Arduino kodu, seri monitör kaydı ve test sonucu hazırlayacaksın. Amaç yalnız sonucun çalışması değil; hangi kararı neden verdiğini, neyi test ettiğini ve hangi durumda tasarımı değiştireceğini açıklayabilmektir.
Görev senaryosu
Şu senaryoyu ele al: çizgiyi algılayan iki sensörün değerlerini seri monitörde karşılaştırma. Dersin ana hedefi “Uzun loop'u okunabilir fonksiyonlara bölerek düzenli ve test edilebilir kod yazmayı öğren” olduğuna göre önce problemi tek cümleyle tanımla. Ardından sistemin alacağı girdiyi, uygulayacağı işlemi ve üreteceği çıktıyı ayrı ayrı yaz. Bilmediğin bir ayrıntı varsa onu varsayım olarak işaretle; varsayımı gerçek bilgi gibi kullanma.
- Planla: Başlangıç durumunu, beklenen sonucu ve kullanacağın kavramları yaz.
- En küçük sürümü kur: Yalnız temel davranışı çalıştır; süsleme ve ek özellikleri sonraya bırak.
- Üç test hazırla: Normal bir durum, sınırda bir durum ve hatalı ya da beklenmeyen bir durum seç.
- Sonucu kaydet: Beklenen ile gerçekleşeni yan yana yaz; fark varsa olası nedeni belirt.
- Tek değişiklik yap: Aynı anda birçok şeyi değiştirmek yerine bir kararı düzeltip testi yeniden çalıştır.
Başarı ölçütleri
- Kartın 5 V veya 3,3 V çalışma sınırı doğru mu?
- Pin numaraları kod ve devrede eşleşiyor mu?
- Seri monitör ölçümü beklenen aralıkta mı?
- Motor veya servo karttan doğrudan aşırı akım çekiyor mu?
- Güç kesildiğinde sistem güvenli duruma dönüyor mu?
“Kod Yapısını Fonksiyonlara Bölmek” çalışmasını bitirdiğinde ürünü bir arkadaşına yalnız bölüm başlıklarıyla anlat. Arkadaşın çizgiyi algılayan iki sensörün değerlerini seri monitörde karşılaştırma senaryosundaki adımları ve karar nedenlerini takip edebiliyorsa anlatım yeterince açıktır. Anlaşılmayan noktayı daha fazla terim ekleyerek değil, Fonksiyon nedir, nasıl yazılır? ve return: geriye değer döndürmek ilişkisini daha küçük adımlara bölerek düzelt.
Sık yapılan hatalar
Fonksiyon türünü yanlış yazmak
readDistance() bir sayı döndürüyorsa başına void yazarsan derleyici (compiler) hata verir. Değer döndüren fonksiyonun türü int, long gibi olmalı; döndürmeyen fonksiyon void olur.
return'ü unutmak
Başına int yazıp içine return koymazsan fonksiyon söz verdiği değeri geri vermez. "Bir cevap döndüreceğim" dedin ama döndürmedin.
pinMode'u setup dışına koymak
pinMode() çağrılarını fonksiyonların içine dağıtma. Kurulum bir kez yapılır; yeri setup()'tır. Aksi hâlde loop() her turda gereksiz yere pinleri yeniden ayarlar.
Fonksiyona kötü ad vermek
sensor2() veya yap() gibi adlar hiçbir şey anlatmaz. readDistance() ve showAlert() gibi, işi anlatan adlar seç. İyi ad, yorum satırına olan ihtiyacı azaltır.
Güvenlik notu
Bu ders yalnızca düşük gerilimli parçalar kullanır: Arduino'yu USB kablosuyla ya da uygun bir pil paketiyle besle. Şebeke (priz) elektriğiyle çalışma.
- LED'i her zaman bir akım sınırlayıcı direnç (örneğin 220 Ω) ile bağla; doğrudan bağlarsan LED zarar görür.
- Buzzer ve LED gibi küçük parçalar Arduino piniyle doğrudan sürülebilir. Ama bir sonraki adımda motor eklersen, motoru asla doğrudan Arduino pininden besleme: motor çok akım çeker ve kartı bozar. Motor için ayrı bir güç kaynağı ve bir motor sürücü kartı gerekir.
- Devrede değişiklik yaparken kartın gücünü kes. Yeni bir bağlantıyı ilk denerken bir yetişkinden yardım iste ve düşük değerlerle başla.
Ders özeti
- Fonksiyon, bir işe ad veren ve tekrar tekrar çağırabildiğimiz kod parçasıdır.
- Değer döndürmeyen fonksiyon
void, değer döndüren fonksiyonint/longgibi bir tür ile yazılır;returnsonucu geri verir. - Uzun
loop()fonksiyonunureadDistance()veshowAlert()gibi anlamlı parçalara bölmek kodu okunabilir yapar. - Bölünmüş kodda her fonksiyon tek bir işten sorumludur; birini değiştirmek diğerini bozmaz.
- Bu yapı Python'daki fonksiyon fikrinin aynısıdır; sadece söz dizimi biraz farklıdır.
Kontrol soruları
voidile başlayan bir fonksiyon ileintile başlayan bir fonksiyon arasındaki fark nedir?return duration / 58;satırındakireturnne işe yarar?- Uzun bir
loop()fonksiyonunu neden küçük fonksiyonlara böleriz? Bir sebep yaz. showAlert(int distance)yazarken parantez içindekiint distanceneyi ifade eder?pinMode()çağrılarının doğru yerisetup()mı yoksaloop()mu? Neden?
Cevaplar
voidfonksiyon bir iş yapar ama geriye değer döndürmez;intfonksiyon bir tam sayı hesaplayıpreturnile geri verir.- Fonksiyonun işini bitirdiğini belirtir ve hesaplanan mesafeyi (santimetre olarak) çağıran yere geri gönderir.
- Kodun okunması ve test edilmesi kolaylaşır; her iş ayrı bir kutuda durduğu için birini değiştirmek diğerini etkilemez. (Tekrar kullanım da geçerli bir cevaptır.)
- Fonksiyona dışarıdan verilen bir parametredir; çağıran kişi bir mesafe değeri gönderir ve fonksiyon o değeri
distanceadıyla kullanır. setup(). Pin ayarları kurulum işidir ve bir kez yapılması yeterlidir;loop()'a koymak her turda gereksiz tekrar demektir.
Kaynak ve doğrulama notu
“Kod Yapısını Fonksiyonlara Bölmek” dersi için doğrulama odağı Fonksiyon nedir, nasıl yazılır? ile return: geriye değer döndürmek arasındaki ilişkinin örnekler üzerinde tutarlı çalışmasıdır. Arduino uyumlu kartlarda pin, gerilim ve akım sınırları modele göre değişebilir. Kod derlense bile devre güvenli olmayabileceğinden, motor ve servo gibi yükler uygun sürücü ve harici besleme ile kullanılmalıdır.
Sonraki ders
Proje: Akıllı Park Sensörü — Bu derste yazdığın readDistance() ve showAlert() fonksiyonlarını bir araya getirip, yaklaştıkça hızlanan gerçek bir park sensörü kuracağız.