// --- Kutuphane dahil etme ---
#include <Arduino_FreeRTOS.h> // FreeRTOS gorev yonetimi icin ana kutuphane
#include <Wire.h> // I2C haberlesme protokolu (MPU6050 ve OLED icin)
#include <Adafruit_GFX.h> // OLED icin grafik kutuphanesi
#include <Adafruit_SSD1306.h> // SSD1306 OLED surucu kutuphanesi
#include <Adafruit_MPU6050.h> // MPU6050 ivmeolcer/jiroskop/sicaklik sensor kutuphanesi
#include <Adafruit_Sensor.h> // Adafruit unified sensor katmani
#include <Keypad.h> // Membran keypad okuma kutuphanesi
#include <Servo.h> // Servo motor kontrol kutuphanesi
// --- OLED ekran boyut tanimlari ---
#define SCREEN_WIDTH 128 // OLED ekranin piksel genisligi
#define SCREEN_HEIGHT 64 // OLED ekranin piksel yuksekligi
#define OLED_RESET -1 // Reset pini yok (-1)
// --- HC-SR04 Pin Tanimlari ---
#define TRIG_PIN 3 // Ultrasonik sensor tetikleme pini
#define ECHO_PIN 2 // Ultrasonik sensor yanki pini
// --- Servo Motor Pin Tanimi ---
#define SERVO_PIN 9 // Servo motorun sinyal pini
// --- Ogrenci Numarasina Ozel Parametreler ---
#define RESET_PASSWORD "1828" // Sifre: son 4 hane (24100011828)
#define DISTANCE_THRESHOLD 43 // Mesafe esigi: 28 + 15 = 43 cm
#define TEMP_LIMIT 58.0 // Sicaklik siniri: 8 + 50 = 58 C
// --- Keypad Tanimlari ---
const byte ROWS = 4; // Keypad 4 satir
const byte COLS = 4; // Keypad 4 sutun
char keys[ROWS][COLS] = {
{'1','2','3','A'}, // 1. satir tuslari
{'4','5','6','B'}, // 2. satir tuslari
{'7','8','9','C'}, // 3. satir tuslari
{'*','0','#','D'} // 4. satir tuslari
};
byte rowPins[ROWS] = {23, 25, 27, 29}; // Keypad satir pinleri
byte colPins[COLS] = {31, 33, 35, 37}; // Keypad sutun pinleri
// --- Nesne Tanimlari ---
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // OLED nesnesi
Adafruit_MPU6050 mpu; // MPU6050 nesnesi
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); // Keypad nesnesi
Servo servo; // Servo nesnesi
// --- Global Durum Bayraklari ---
volatile bool isLocked = false; // Guvenlik kilidi aktif mi?
volatile bool isEmergency = false; // Ariza modu aktif mi?
volatile bool manualUnlock = false; // Yetkili personel sifreyle acti mi?
// --- Global Olcum Degiskenleri ---
volatile float currentTemp = 0.0; // Anlık sicaklik (C)
volatile float currentDistance = 0.0; // Anlık mesafe (cm)
// --- Servo Pozisyon Degiskenleri ---
int servoAngle = 0; // Servo anlık acisi
int servoDir = 1; // Servo yonu: +1 ileri, -1 geri
// --- Sifre Tamponu ---
char passwordBuffer[10]; // Kullanicinin girdigi karakterler
int bufferIndex = 0; // Tampondaki karakter sayisi
// ============================================================
// HC-SR04 mesafe olcum fonksiyonu
// Formul: mesafe = sure * 0.034 / 2
// ============================================================
float readDistance() {
digitalWrite(TRIG_PIN, LOW); // Trigger pini temizle
delayMicroseconds(2); // 2us bekle
digitalWrite(TRIG_PIN, HIGH); // Ses dalgasi gonder
delayMicroseconds(10); // 10us HIGH tut
digitalWrite(TRIG_PIN, LOW); // Trigger kapat
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // Yanki suresini olc
float distance = duration * 0.034 / 2.0; // cm'ye donustur
if (distance == 0) distance = 999.0; // Sinyal yoksa uzak say
return distance;
}
// ============================================================
// TASK 1: Task_Safety (Oncelik: 4 - Kritik)
// Periyot: 50ms
// HC-SR04 mesafe okur, esik altindaysa isLocked = true yapar
// manualUnlock aktifse Task_Safety tekrar kilitlemez
// ============================================================
void Task_Safety(void *pvParameters) {
pinMode(TRIG_PIN, OUTPUT); // TRIG cikis
pinMode(ECHO_PIN, INPUT); // ECHO giris
for (;;) {
float dist = readDistance(); // Mesafeyi oku
currentDistance = dist; // Global degiskene yaz
if (dist >= DISTANCE_THRESHOLD) {
// Mesafe guvenli bolgeye cikti: manuel acma bayragi sifirlanir
manualUnlock = false; // Artik yeni ihlalde tekrar kilitleyebilir
}
if (dist < DISTANCE_THRESHOLD) {
if (!manualUnlock) {
isLocked = true;
Serial.print("[SAFETY] IHLAL! Mesafe: ");
Serial.print(dist);
Serial.println(" cm");
}
}
vTaskDelay(50 / portTICK_PERIOD_MS); // 50ms bekle
}
}
// ============================================================
// TASK 2: Task_Health (Oncelik: 3 - Yuksek)
// Periyot: 200ms
// MPU6050 sicaklik okur, limit asilirsa isEmergency = true
// ============================================================
void Task_Health(void *pvParameters) {
for (;;) {
sensors_event_t a, g, temp; // Sensor olay yapilari
mpu.getEvent(&a, &g, &temp); // Veriyi al
float t = temp.temperature; // Sicakligi al
currentTemp = t; // Global degiskene yaz
Serial.print("[HEALTH] Sicaklik: ");
Serial.print(t);
Serial.println(" C");
if (t >= TEMP_LIMIT) {
isEmergency = true; // Limit asildi: ariza modu
Serial.println("[HEALTH] ARIZA: Motor asiri isinik!");
} else {
isEmergency = false; // Sicaklik normale dondu: ariza kaldir
}
vTaskDelay(200 / portTICK_PERIOD_MS); // 200ms bekle
}
}
// ============================================================
// TASK 3: Task_Motion (Oncelik: 2 - Orta)
// Periyot: 30ms
// Servo 0-180 derece yumusak supur hareketi yapar
// isLocked veya isEmergency aktifse durur
// ============================================================
void Task_Motion(void *pvParameters) {
servo.attach(SERVO_PIN); // Servo pin 9'a bagla
servo.write(0); // Baslangic pozisyonu 0 derece
for (;;) {
if (!isLocked && !isEmergency) { // Kilitli veya arizali degilse calis
servo.write(servoAngle); // Servo'yu anlık aciya yaz
Serial.print("[MOTION] Servo Aci: ");
Serial.println(servoAngle);
servoAngle += (5 * servoDir); // 5 derece ilerle
if (servoAngle >= 180) { // 180'e ulastiysa geri don
servoAngle = 180;
servoDir = -1;
}
if (servoAngle <= 0) { // 0'a ulastiysa ileri git
servoAngle = 0;
servoDir = 1;
}
}
// Kilitliyse servo.write cagrisi yapilmaz, motor durur
vTaskDelay(30 / portTICK_PERIOD_MS); // 30ms bekle
}
}
// ============================================================
// TASK 4: Task_HMI (Oncelik: 1 - Dusuk)
// Periyot: 100ms
// Keypad tara, OLED guncelle, sifre dogrula
// ============================================================
void Task_HMI(void *pvParameters) {
static bool blinkState = false; // Yanip sonme efekti degiskeni
for (;;) {
// --- Keypad Okuma ---
char key = keypad.getKey(); // Tus oku
if (key) {
if (key == '*') {
// Yildiz: tamponu temizle
bufferIndex = 0;
memset(passwordBuffer, 0, sizeof(passwordBuffer));
Serial.println("[HMI] Tampon silindi.");
} else if (key == '#') {
// Kare: sifre onayla
passwordBuffer[bufferIndex] = '\0'; // Dizeyi sonlandir
if (strcmp(passwordBuffer, RESET_PASSWORD) == 0) {
// Sifre dogru
isLocked = false; // Kilidi kaldir
isEmergency = false; // Ariza modunu kaldir
manualUnlock = true; // Manuel acma bayragi set et (Task_Safety tekrar kilitlemesin)
bufferIndex = 0;
memset(passwordBuffer, 0, sizeof(passwordBuffer));
Serial.println("[HMI] Sifre DOGRU. Sistem aktif.");
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.println("SIFRE DOGRU!"); // Dogru sifre mesaji
display.println("Sistem Aktif...");
display.display();
vTaskDelay(2000 / portTICK_PERIOD_MS); // 2 saniye goster
} else {
// Sifre yanlis
Serial.println("[HMI] HATALI SIFRE!");
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.println("HATALI SIFRE!"); // Hatali sifre uyarisi
display.display();
vTaskDelay(2000 / portTICK_PERIOD_MS); // 2 saniye goster
bufferIndex = 0;
memset(passwordBuffer, 0, sizeof(passwordBuffer));
}
} else if (bufferIndex < 9) {
// Rakam tusu: tampona ekle
passwordBuffer[bufferIndex++] = key;
passwordBuffer[bufferIndex] = '\0';
Serial.print("[HMI] Tampon: ");
Serial.println(passwordBuffer);
}
}
// --- OLED Ekran Guncelleme ---
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
if (isEmergency) {
// ARIZA MODU
display.setCursor(0, 0);
display.println("!!! ARIZA: MOTOR SICAK !!!"); // 1. satir
display.setCursor(0, 20);
display.println("Soguma Bekleniyor..."); // 2. satir
display.setCursor(0, 40);
display.print("Sicaklik: ");
display.print(currentTemp, 1); // 3. satir: sicaklik
display.println(" C");
} else if (isLocked) {
// GUVENLIK KILIDI MODU
blinkState = !blinkState; // Yanip sonme efekti
if (blinkState) {
display.setCursor(0, 0);
display.println("!!! GUVENLIK IHLAL !!!"); // 1. satir (yanip soner)
}
display.setCursor(0, 22);
display.println("Sifre Giriniz:"); // 2. satir
display.setCursor(0, 44);
display.println(passwordBuffer); // 3. satir: girilen karakterler
} else {
// NORMAL CALISMA MODU
display.setCursor(0, 0);
display.println("DURUM: AKTIF"); // 1. satir
display.setCursor(0, 22);
display.print("Mesafe: ");
display.print(currentDistance, 0); // 2. satir: mesafe
display.println(" cm");
display.setCursor(0, 44);
display.print("Isi: ");
display.print(currentTemp, 1); // 3. satir: sicaklik
display.println(" C");
}
display.display(); // OLED'e gonder
vTaskDelay(100 / portTICK_PERIOD_MS); // 100ms bekle
}
}
// ============================================================
// setup() - Baslangic fonksiyonu
// ============================================================
void setup() {
Serial.begin(9600); // Seri haberlesme baslat
Wire.begin(); // I2C baslat
// OLED baslat
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED bulunamadi!");
for (;;); // Kritik hata: dur
}
display.clearDisplay();
display.display();
// MPU6050 baslat
if (!mpu.begin()) {
Serial.println("MPU6050 bulunamadi!");
for (;;); // Kritik hata: dur
}
mpu.setAccelerometerRange(MPU6050_RANGE_8_G); // Ivmeolcer araligi +-8G
mpu.setGyroRange(MPU6050_RANGE_500_DEG); // Jiroskop araligi 500 derece/s
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); // Filtre bant genisligi
Serial.println("Sistem baslatiliyor...");
// FreeRTOS Gorevleri olustur
xTaskCreate(Task_Safety, "Safety", 256, NULL, 4, NULL); // Oncelik 4: kritik
xTaskCreate(Task_Health, "Health", 512, NULL, 3, NULL); // Oncelik 3: yuksek
xTaskCreate(Task_Motion, "Motion", 256, NULL, 2, NULL); // Oncelik 2: orta
xTaskCreate(Task_HMI, "HMI", 512, NULL, 1, NULL); // Oncelik 1: dusuk
// Arduino FreeRTOS'ta vTaskStartScheduler() otomatik cagrilir
}
// ============================================================
// loop() - FreeRTOS varken bos birakılir
// ============================================================
void loop() {
// Tum is mantigi FreeRTOS gorevlerinde, loop kullanilmaz
}