ESP8266 NodeMCU & HC-SR04 Kalibrasyonlu Sıvı Seviye Ölçümü

👤 Yazar: ozcan 📅 Tarih: 30.07.2026 16:19 👁️ Görüntüleme: 14

ESP8266 NodeMCU & HC-SR04 Kalibrasyonlu Sıvı Seviye Ölçümü

Bu projede, NodeMCU V3 (ESP8266) ve HC-SR04 ultrasonik mesafe sensörü kullanarak bir depodaki sıvı seviyesini yüzde (%) ve mesafe (cm) cinsinden ölçüyoruz. Web arayüzü üzerinden Boş Seviye ve Dolu Seviye mesafelerini dinamik olarak kalibre edip EEPROM (kalıcı hafıza) üzerine kaydedebilirsiniz. Ayrıca anlık veriler Seri Port Ekranı üzerinden de takip edilebilir.

ESP8266 HC-SR04 Sıvı Seviye Ölçer Bağlantı Şeması

Devre Bağlantı Şeması

Şemadaki pin eşleşmeleri şu şekildedir:

  • HC-SR04 VCC: NodeMCU VIN (5V) pinine.
  • HC-SR04 GND: NodeMCU GND pinine.
  • HC-SR04 Trig: NodeMCU D1 (GPIO5) pinine.
  • HC-SR04 Echo: NodeMCU D2 (GPIO4) pinine.
  • Uyarı LED'i Anot (+): NodeMCU D4 (GPIO2) pinine (Depo %10 altına düştüğünde uyarı verir).
  • Uyarı LED'i Katot (-): NodeMCU GND pinine.
Mesafe vs. Sıvı Seviyesi Mantığı:
Ultrasonik sensör hizada yukarıda durur. Depo BOŞ iken sıvı uzaktadır (ölçülen mesafe büyük cm). Depo DOLU iken sıvı sensöre yakındır (ölçülen mesafe küçük cm). Kalibrasyon mantığı kod içerisinde buna göre ölçeklendirilmiştir (map fonksiyonu ile).

Örnek Arduino IDE Kodu

Aşağıdaki kodu NodeMCU'nuza yükleyerek web arayüzünden kalibrasyon yapabilir ve Seri Port üzerinden anlık çıktı alabilirsiniz:

// ESP8266 HC-SR04 Kalibrasyonlu Sıvı Seviye Ölçer ve Web Server

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>

// Wi-Fi Ağ Bilgileriniz
const char* ssid = "WIFI_ADINIZ";
const char* password = "WIFI_SIFRENIZ";

// Pin Tanımlamaları
#define TRIG_PIN D1
#define ECHO_PIN D2
#define LED_PIN  D4

ESP8266WebServer server(80);

// Kalibrasyon Değişkenleri (EEPROM Adresleri: 0 ve 4)
float bosMesafe = 100.0; // cm (Sıvı en uzaktayken)
float doluMesafe = 10.0;  // cm (Sıvı sensöre en yakınken)

// Zamanlayıcı
unsigned long lastMeasureTime = 0;
float mevcutMesafe = 0.0;
int mevcutYuzde = 0;

// EEPROM'dan Kalibrasyon Değerlerini Oku
void readEEPROM() {
  EEPROM.get(0, bosMesafe);
  EEPROM.get(4, doluMesafe);

  // İlk açılışta mantıksız değer gelirse varsayılan atansın
  if (isnan(bosMesafe) || bosMesafe <= 0) bosMesafe = 100.0;
  if (isnan(doluMesafe) || doluMesafe <= 0) doluMesafe = 10.0;
}

// Sensörden Mesafe Okuma (cm)
float getMesafe() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout
  if (duration == 0) return -1; // Hatalı okuma

  return (duration * 0.0343) / 2.0;
}

// Ana Web Arayüzü
void handleRoot() {
  String html = "<!DOCTYPE html><html lang='tr'><head><meta charset='UTF-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  html += "<meta http-equiv='refresh' content='3'>"; // 3 saniyede bir otomatik yenile
  html += "<title>Sıvı Seviye Kontrolü</title>";
  html += "<style>";
  html += "body { font-family: Arial, sans-serif; text-align: center; background: #f0f2f5; margin-top: 20px; }";
  html += ".card { background: white; max-width: 480px; margin: 0 auto; padding: 20px; border-radius: 12px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); }";
  html += ".progress-bg { background: #e0e0e0; border-radius: 20px; height: 30px; width: 100%; overflow: hidden; margin: 15px 0; }";
  html += ".progress-bar { background: #2196F3; height: 100%; width: " + String(mevcutYuzde) + "%; text-align: center; color: white; line-height: 30px; font-weight: bold; transition: width 0.5s; }";
  html += "input[type='number'] { width: 80px; padding: 6px; margin: 5px; border: 1px solid #ccc; border-radius: 4px; }";
  html += ".btn { background: #28a745; color: white; padding: 8px 15px; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; margin-top: 10px; }";
  html += "</style></head><body>";

  html += "<div class='card'>";
  html += "<h2 style='color:#007acc;'>Sıvı Seviye Takibi</h2><hr>";
  html += "<h3>Seviye: %" + String(mevcutYuzde) + "</h3>";
  
  html += "<div class='progress-bg'>";
  html += "<div class='progress-bar'>%" + String(mevcutYuzde) + "</div>";
  html += "</div>";

  html += "<p><strong>Ölçülen Mesafe:</strong> " + String(mevcutMesafe, 1) + " cm</p><hr>";

  html += "<h4>Kalibrasyon Ayarları</h4>";
  html += "<form action='/kalibre' method='GET'>";
  html += "Boş Depo Mesafesi (cm): <input type='number' step='0.1' name='bos' value='" + String(bosMesafe, 1) + "'><br>";
  html += "Dolu Depo Mesafesi (cm): <input type='number' step='0.1' name='dolu' value='" + String(doluMesafe, 1) + "'><br>";
  html += "<input class='btn' type='submit' value='Kalibrasyon Kaydet'>";
  html += "</form>";

  html += "</div></body></html>";

  server.send(200, "text/html", html);
}

// Kalibrasyon Değerlerini Kaydetme Endpoint'i
void handleKalibre() {
  if (server.hasArg("bos") && server.hasArg("dolu")) {
    bosMesafe = server.arg("bos").toFloat();
    doluMesafe = server.arg("dolu").toFloat();

    // EEPROM'a Yaz
    EEPROM.put(0, bosMesafe);
    EEPROM.put(4, doluMesafe);
    EEPROM.commit();

    Serial.println("\n[KALİBRASYON GÜNCELLENDİ]");
    Serial.print("Yeni Boş Mesafe: "); Serial.print(bosMesafe); Serial.println(" cm");
    Serial.print("Yeni Dolu Mesafe: "); Serial.print(doluMesafe); Serial.println(" cm");
  }
  
  // Ana sayfaya yönlendir
  server.sendHeader("Location", "/");
  server.send(302, "text/plain", "Yönlendiriliyor...");
}

void setup() {
  Serial.begin(115200);
  EEPROM.begin(512);

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);

  readEEPROM();

  // Wi-Fi Bağlantısı
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("\nWi-Fi Ağına Bağlanılıyor");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\n[BAĞLANDI]");
  Serial.print("Web Server IP Adresi: ");
  Serial.println(WiFi.localIP());

  // Server Yönlendirmeleri
  server.on("/", handleRoot);
  server.on("/kalibre", handleKalibre);
  server.begin();
  Serial.println("HTTP Sunucusu Başlatıldı.");
}

void loop() {
  server.handleClient();

  // Her 1 saniyede bir ölçüm ve Seri Port çıktısı yap
  if (millis() - lastMeasureTime >= 1000) {
    lastMeasureTime = millis();

    float m = getMesafe();
    if (m > 0) {
      mevcutMesafe = m;

      // Mesafeyi % Yüzdeye Dönüştür
      // bosMesafe (uzak) = %0, doluMesafe (yakın) = %100
      float yuzde = map(mevcutMesafe * 10, bosMesafe * 10, doluMesafe * 10, 0, 100);
      mevcutYuzde = constrain((int)yuzde, 0, 100);

      // Uyarı LED'i (%10 altındaysa yansın)
      digitalWrite(LED_PIN, (mevcutYuzde <= 10) ? HIGH : LOW);

      // Seri Port Çıktısı
      Serial.print("Mesafe: ");
      Serial.print(mevcutMesafe, 1);
      Serial.print(" cm | Doluluk: %");
      Serial.print(mevcutYuzde);
      Serial.print(" | [Ayar - Boş: ");
      Serial.print(bosMesafe, 1);
      Serial.print(" cm, Dolu: ");
      Serial.print(doluMesafe, 1);
      Serial.println(" cm]");
    } else {
      Serial.println("[HATA] Sensör okuma yapamadı!");
    }
  }
}

Kalibrasyon ve Kullanım Adımları

  1. Kodu Yükleyin: Kendi Wi-Fi bilgilerinizi yazıp kodu kartınıza yükleyin.
  2. Seri Portu Takip Edin: 115200 baud hızında Seri Port Ekranını açın. Kartın aldığı IP adresini ve anlık ölçülen mesafeleri oradan takip edebilirsiniz.
  3. Web Arayüzüne Girin: Tarayıcıya NodeMCU'nun IP adresini yazın.
  4. Kalibrasyon Yapın:
    • Depo tamamen boşken sensör ile depo tabanı arasındaki mesafeyi (örneğin 45 cm) Boş Depo Mesafesi kutusuna girin.
    • Depo tamamen dolduğunda sıvının sensöre olan mesafesini (örneğin 5 cm) Dolu Depo Mesafesi kutusuna girin.
    • Kalibrasyon Kaydet butonuna basın. Bu değerler EEPROM'a yazılır ve cihaz kapansa bile silinmez.

💬 Yorumlar

Henüz yorum yapılmamış. İlk yorumu siz yapın!

Bir Yorum Bırakın

Güvenlik Kontrolü:

Yenidir.com
↑ Sayfa Başı
📞 İletişim ✉ E-Posta Gönder 🟥 YouTube
© 2026 Yenidir.com
Yenidir CMS V0.1