/*
* STM32 Akıllı Şebeke İzleme ve Arıza Tespit Sistemi
* Wokwi Simülasyonu - v4 (SD kütüphanesiz, sade)
*/
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>
#define V_SENSE_PIN PA0
#define I_SENSE_PIN PA1
#define LED_ALARM PB0
#define BUZZER_PIN PB1
#define RELAY_PIN PB10
#define OLED_ADDR 0x3C
#define BUFFER_SIZE 50
#define V_PEAK_MAX 330.0f
#define I_PEAK_MAX 15.0f
#define AC_FREQ 50.0f
#define ADC_RES 4095.0f
#define V_HIGH_TH 250.0f
#define V_LOW_TH 180.0f
#define I_HIGH_TH 10.0f
#define SENSOR_PERIOD 50
#define FAULT_PERIOD 100
#define COMM_PERIOD 1000
#define DISPLAY_PERIOD 500
typedef struct {
float vrms;
float irms;
float power_active;
float frequency;
bool fault_ov;
bool fault_uv;
bool fault_oi;
uint32_t cycle_count;
} SystemData_t;
SystemData_t gData = {0};
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
bool g_oled_ok = false;
unsigned long lastSensor = 0;
unsigned long lastFault = 0;
unsigned long lastComm = 0;
unsigned long lastDisplay = 0;
float v_buf[BUFFER_SIZE];
float i_buf[BUFFER_SIZE];
void SensorAndProcessingTask() {
uint16_t v_pot = analogRead(V_SENSE_PIN);
uint16_t i_pot = analogRead(I_SENSE_PIN);
float v_peak = ((float)v_pot / ADC_RES) * V_PEAK_MAX;
float i_peak = ((float)i_pot / ADC_RES) * I_PEAK_MAX;
for (int i = 0; i < BUFFER_SIZE; i++) {
float t = (float)i * 0.001f;
float wave = sinf(2.0f * (float)PI * AC_FREQ * t);
v_buf[i] = v_peak * wave;
i_buf[i] = i_peak * wave;
}
float v_sum_sq = 0.0f, i_sum_sq = 0.0f, p_sum = 0.0f;
for (int i = 0; i < BUFFER_SIZE; i++) {
v_sum_sq += v_buf[i] * v_buf[i];
i_sum_sq += i_buf[i] * i_buf[i];
p_sum += v_buf[i] * i_buf[i];
}
gData.vrms = sqrtf(v_sum_sq / BUFFER_SIZE);
gData.irms = sqrtf(i_sum_sq / BUFFER_SIZE);
gData.power_active = p_sum / BUFFER_SIZE;
int zc = 0;
for (int i = 1; i < BUFFER_SIZE; i++) {
if ((v_buf[i-1] <= 0.0f && v_buf[i] > 0.0f) ||
(v_buf[i-1] >= 0.0f && v_buf[i] < 0.0f)) {
zc++;
}
}
float freq = (zc / 2.0f) / ((float)BUFFER_SIZE * 0.001f);
gData.frequency = (freq < 1.0f) ? AC_FREQ : freq;
gData.cycle_count++;
}
void FaultDetectionTask() {
gData.fault_ov = (gData.vrms > V_HIGH_TH);
gData.fault_uv = (gData.vrms < V_LOW_TH);
gData.fault_oi = (gData.irms > I_HIGH_TH);
bool any_fault = gData.fault_ov || gData.fault_uv || gData.fault_oi;
if (any_fault) {
digitalWrite(LED_ALARM, HIGH);
digitalWrite(RELAY_PIN, HIGH);
tone(BUZZER_PIN, 2000, 80);
} else {
digitalWrite(LED_ALARM, LOW);
digitalWrite(RELAY_PIN, LOW);
}
}
void CommunicationTask() {
Serial.print("{\"v\":"); Serial.print(gData.vrms, 2);
Serial.print(",\"i\":"); Serial.print(gData.irms, 3);
Serial.print(",\"p\":"); Serial.print(gData.power_active, 2);
Serial.print(",\"f\":"); Serial.print(gData.frequency, 2);
Serial.print(",\"ov\":"); Serial.print(gData.fault_ov ? 1 : 0);
Serial.print(",\"uv\":"); Serial.print(gData.fault_uv ? 1 : 0);
Serial.print(",\"oi\":"); Serial.print(gData.fault_oi ? 1 : 0);
Serial.print(",\"n\":"); Serial.print(gData.cycle_count);
Serial.print(",\"t\":"); Serial.print(millis());
Serial.println("}");
}
void DisplayTask() {
if (!g_oled_ok) return;
oled.clearDisplay();
oled.setTextSize(1);
oled.setTextColor(SSD1306_WHITE);
oled.setCursor(0, 0);
oled.println("STM32 Sebeke Izleme");
oled.drawLine(0, 9, 127, 9, SSD1306_WHITE);
oled.setCursor(0, 13);
oled.print("V: "); oled.print(gData.vrms, 1); oled.println(" V");
oled.print("I: "); oled.print(gData.irms, 2); oled.println(" A");
oled.print("P: "); oled.print(gData.power_active, 1); oled.println(" W");
oled.print("F: "); oled.print(gData.frequency, 1); oled.println(" Hz");
oled.drawLine(0, 53, 127, 53, SSD1306_WHITE);
oled.setCursor(0, 56);
if (gData.fault_ov || gData.fault_uv || gData.fault_oi) {
oled.print("ALARM:");
if (gData.fault_ov) oled.print(" OV");
if (gData.fault_uv) oled.print(" UV");
if (gData.fault_oi) oled.print(" OI");
} else {
oled.print("Durum: NORMAL");
}
oled.display();
}
void setup() {
Serial.begin(115200);
delay(500);
Serial.println();
Serial.println("==============================================");
Serial.println(" STM32 Akilli Sebeke Izleme Sistemi");
Serial.println(" Final Proje - Wokwi Simulasyonu");
Serial.println("==============================================");
pinMode(LED_ALARM, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(LED_ALARM, LOW);
digitalWrite(RELAY_PIN, LOW);
analogReadResolution(12);
Wire.begin();
Wire.setClock(400000);
if (oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
g_oled_ok = true;
oled.clearDisplay();
oled.setTextSize(1);
oled.setTextColor(SSD1306_WHITE);
oled.setCursor(0, 20);
oled.println(" STM32 Sebeke");
oled.println(" Izleme Sistemi");
oled.println("");
oled.println(" Baslatiliyor...");
oled.display();
Serial.println("[OK] OLED hazir");
} else {
Serial.println("[UYARI] OLED bulunamadi");
}
Serial.println("[OK] Sistem hazir");
Serial.println("----------------------------------------------");
delay(1500);
}
void loop() {
unsigned long now = millis();
if (now - lastSensor >= SENSOR_PERIOD) { lastSensor = now; SensorAndProcessingTask(); }
if (now - lastFault >= FAULT_PERIOD) { lastFault = now; FaultDetectionTask(); }
if (now - lastComm >= COMM_PERIOD) { lastComm = now; CommunicationTask(); }
if (now - lastDisplay >= DISPLAY_PERIOD) { lastDisplay = now; DisplayTask(); }
}