ESP32 ile akıllı akü şarj sistemi-Bluetooth Classic

👤 Yazar: ozcan 📅 Tarih: 01.06.2026 01:37 👁️ Görüntüleme: 17

Projemizin başından beri adım adım geliştirdiğimiz, tüm isteklerini ve senaryoları eksiksiz barındıran endüstriyel kalitedeki Akıllı Akü Yönetim ve Şarj Kontrol Cihazı (BMS) projesini tek bir çatı altında topluyoruz.

Bu nihai kod mimarisinde; röle yerine yüksek frekanslı kararlı PWM kontrolü, telefondan anlık olarak güncellenebilen hedef şarj akımı (Constant Current) ayarı, 3 farklı akıllı şarj senaryosu ve ESP32'nin analog pinlerindeki tüm elektriksel gürültüleri sıfırlayan Hareketli Ortalama (Moving Average) Yazılımsal Filtresi bir araya getirilmiştir. Wi-Fi kapatılarak sadece Bluetooth üzerinden telefon terminalinizle haberleşen bu sistemi, yenidir.com takipçileri ve kendi projelerini üreten hobiciler için eksiksiz bir ana kaynak olarak paylaşıyoruz.

Projenin Donanım Anatomisi ve Bağlantı Şeması

ESP32 Akıllı Şarj Kontrol ve Filtreleme Kod Bloğu (Tek Parça)

Aşağıdaki kodu doğrudan Arduino IDE programınıza yapıştırıp ESP32 kartınıza yükleyebilirsiniz. Herhangi bir harici kütüphane kurmanıza gerek yoktur.

#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

// Donanim Pin Tanimlamalari
const int voltajPin = 34; 
const int akimPin   = 35; 
const int pwmPin    = 25; 

// PWM Ayarlari
const int pwmFrekans = 5000;
const int pwmCozunurluk = 8; 
int pwmDuty = 0;

// Hareketli Ortalama Filtre Degiskenleri
const int filtreKatsayisi = 10;
float voltajDizi[filtreKatsayisi] = {0};
float akimDizi[filtreKatsayisi] = {0};
int filtreIndex = 0;

// Sistem ve Sarj Limitleri
int aktifMod = 1;              
float hedonSarjAkimi = 3.0;    
float limitUstVolt = 14.4;     
float limitAltVolt = 12.3;     
float limitDevamVolt = 13.8;   

// Durum Bayraklari
bool mod1DolduMu = false;
bool mod2BeklemedeMi = false;
bool sistemErisimi = false; // Güvenlik için kilitli başlıyoruz!

String gelenVeri = "";

float gercekVoltajOku() {
  int hamDeger = analogRead(voltajPin);
  float analogVolt = (hamDeger * 3.3) / 4095.0;
  return analogVolt * 5.0; 
}

float gercekAkimOku() {
  int hamDeger = analogRead(akimPin);
  float analogVolt = (hamDeger * 3.3) / 4095.0;
  return (analogVolt - 2.5) / 0.066; 
}

void setup() {
  Serial.begin(115200);
  
  // Standart Bluetooth başlatma (Windows geçsin ama yazılım duvarına çarpsın)
  SerialBT.begin("Yenidir_BMS_Serial"); 
  Serial.println("Yenidir BMS Baslatildi. Yazilamsal Guvenlik Duvari Aktif!");

  ledcAttach(pwmPin, pwmFrekans, pwmCozunurluk);
}

void loop() {
  if (SerialBT.available() > 0) {
    gelenVeri = SerialBT.readString();
    gelenVeri.trim();
  }
  else if (Serial.available() > 0) {
    gelenVeri = Serial.readString();
    gelenVeri.trim();
  }

  if (gelenVeri != "") {
    // 1. Gelen komut şifre çözme komutu mu?
    if (gelenVeri.startsWith("SIFRE:")) {
      String girilenSifre = gelenVeri.substring(6);
      if (girilenSifre == "1234") { 
        sistemErisimi = true;
        SerialBT.println("Sistem: Sifre Dogru. Erisim Onaylandi!");
        Serial.println("Sistem: Bluetooth erisimi onaylandi.");
      } else {
        sistemErisimi = false;
        SerialBT.println("Sistem: HATALI SIFRE! Erisim Engellendi.");
      }
    }
    // 2. Eğer şifre doğru girildiyse diğer komutları çalıştır
    else if (sistemErisimi) {
      if (gelenVeri.startsWith("MOD:")) {
        aktifMod = gelenVeri.substring(4).toInt();
        mod1DolduMu = false; mod2BeklemedeMi = false; pwmDuty = 0;
        SerialBT.print("Sistem: MOD DEGISTI -> "); SerialBT.println(aktifMod);
        Serial.print("Sistem: MOD DEGISTI -> "); Serial.println(aktifMod);
      }
      else if (gelenVeri.startsWith("AKIM:")) {
        hedonSarjAkimi = gelenVeri.substring(5).toFloat();
        SerialBT.print("Sistem: HEDEF AKIM -> "); SerialBT.println(hedonSarjAkimi);
      }
      else if (gelenVeri.startsWith("UST:")) {
        limitUstVolt = gelenVeri.substring(4).toFloat();
        SerialBT.print("Sistem: UST LIMIT -> "); SerialBT.println(limitUstVolt);
      }
      else if (gelenVeri.startsWith("ALT:")) {
        limitAltVolt = gelenVeri.substring(4).toFloat();
        SerialBT.print("Sistem: ALT LIMIT -> "); SerialBT.println(limitAltVolt);
      }
      else if (gelenVeri.startsWith("DEVAM:")) {
        limitDevamVolt = gelenVeri.substring(6).toFloat();
        SerialBT.print("Sistem: DEVAM LIMIT -> "); SerialBT.println(limitDevamVolt);
      }
    } 
    // 3. Şifre girmeden başka komut basarsa uyar ve reddet
    else {
      SerialBT.println("Sistem: ERISIM ENGELLENDI! Lutfen once SIFRE:1234 gonderin.");
    }
    gelenVeri = ""; 
  }

  // Filtre ve Şarj Algoritması arka planda güvenle çalışmaya devam eder...
  voltajDizi[filtreIndex] = gercekVoltajOku();
  akimDizi[filtreIndex] = gercekAkimOku();
  filtreIndex = (filtreIndex + 1) % filtreKatsayisi;

  float filtreliVolt = 0; float filtreliAkim = 0;
  for (int i = 0; i < filtreKatsayisi; i++) {
    filtreliVolt += voltajDizi[i]; filtreliAkim += akimDizi[i];
  }
  filtreliVolt /= filtreKatsayisi; filtreliAkim /= filtreKatsayisi;

  if (aktifMod == 1) {
    if (!mod1DolduMu) {
      if (filtreliVolt >= limitUstVolt) mod1DolduMu = true; 
      else {
        if (filtreliAkim < hedonSarjAkimi && pwmDuty < 255) pwmDuty++;
        if (filtreliAkim > hedonSarjAkimi && pwmDuty > 0)   pwmDuty--;
      }
    } else {
      if (filtreliVolt < limitDevamVolt && pwmDuty < 255) pwmDuty++;
      if (filtreliVolt > limitDevamVolt && pwmDuty > 0)   pwmDuty--;
    }
  }
  else if (aktifMod == 2) {
    if (!mod2BeklemedeMi) {
      if (filtreliVolt >= limitUstVolt) { mod2BeklemedeMi = true; pwmDuty = 0; } 
      else {
        if (filtreliAkim < hedonSarjAkimi && pwmDuty < 255) pwmDuty++;
        if (filtreliAkim > hedonSarjAkimi && pwmDuty > 0)   pwmDuty--;
      }
    } else {
      pwmDuty = 0; 
      if (filtreliVolt <= limitAltVolt) mod2BeklemedeMi = false; 
    }
  }
  else if (aktifMod == 3) {
    if (filtreliVolt < limitDevamVolt && pwmDuty < 255) pwmDuty++;
    if (filtreliVolt > limitDevamVolt && pwmDuty > 0)   pwmDuty--;
  }

  ledcWrite(pwmPin, pwmDuty);

  // Periyodik Raporlama (Sadece Şifre Doğruysa Bluetooth'a basar)
  static unsigned long sonRaporZamani = 0;
  if (millis() - sonRaporZamani >= 2000) {
    sonRaporZamani = millis();
    String rapor = "V:" + String(filtreliVolt, 2) + " A:" + String(filtreliAkim, 2) + " M:" + String(aktifMod) + " P:" + String(pwmDuty);
    
    Serial.println(rapor); // Kabloda hep akar
    
    if (sistemErisimi) {
      SerialBT.println(rapor); // Bluetooth terminalinde sadece giriş yapılınca akar!
    }
  }
  delay(10); 
}

Telefon Üzerinden Sistemi Yönetme Rehberi

Sistem açıldığında telefonunuzdan herhangi bir Bluetooth seri terminal uygulaması ile "Yenidir_BMS_Perfect" cihazına bağlanın. Ardından aşağıdaki komut şablonlarıyla cihazın çalışma mantığını anlık olarak uzaktan manipüle edebilirsiniz:

Yazılımsal ortalama filtresinin entegre edilmesiyle birlikte, MOSFET'in hızlı anahtarlamasından doğan gürültüler tamamen sönümlenmiş ve cihazın kararlılığı endüstriyel standartlara ulaştırılmıştır. Keyifli ve güvenli testler dileriz!

Not:

Bluetooth Classic de yazılımsal güvenlik kullandık ESP32 de Arduino'da yapabileceğimiz en fazla güvenlik bu. Yani bağlantıyı engelleyemiyoruz ama veri alış verişine engel koyabiliyoruz. Bir sonraki yazıda BLE ile projeye devam edeceğiz.

💬 Yorumlar

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

Bir Yorum Bırakın

Güvenlik Kontrolü:

Yenidir.com
Sayfa Başı
Yenidir CMS V0.1