#include <Wire.h>
#include <EEPROM.h>
// ==========================================
// 1. تعريف المنافذ بناءً على جدول التهيئة [cite: 32-34]
// ==========================================
#define MPU_INT_PIN 2 // مدخل المقاطعة الخارجية
#define POWER_LED_PIN 8 // خرج
#define ARMED_LED_PIN 4 // خرج
#define FAULT_LED_PIN 5 // خرج
#define TRIGGER_LED_PIN 6 // خرج
#define BUZZER_PIN 7 // خرج
#define TRIGGER_MOSFET_PIN 9 // خرج
#define ARM_SWITCH_PIN 3 // دخل (استخدام Pull-up داخلي)
// ==========================================
// 2. عناوين مسجلات MPU-6050
// ==========================================
#define MPU_ADDR 0x68
#define PWR_MGMT_1 0x6B
#define SMPLRT_DIV 0x19
#define CONFIG_REG 0x1A
#define ACCEL_CONFIG 0x1C
#define INT_PIN_CFG 0x37
#define INT_ENABLE 0x38
#define ACCEL_XOUT_H 0x3B
// عنوان الذاكرة لتخزين عدد الصدمات [cite: 123-125]
#define EEPROM_CRASH_ADDR 0
// عتبة التفعيل > 3G (على مقياس ±16g، القيمة الخام 6144)
// تم إعادتها إلى 6144 للتطبيق الفيزيائي الحقيقي
#define G_THRESHOLD_RAW 3027
// ==========================================
// 3. إدارة حالات النظام والمتغيرات العامة [cite: 13, 133]
// ==========================================
enum SystemState { INIT, DISARMED, ARMED, TRIGGERED, FAULT };
volatile SystemState currentState = INIT;
volatile bool dataReady = false;
// متغير لتخزين عدد الصدمات تاريخياً
int crashCount = 0;
// دالة المقاطعة لتقليل زمن الاستجابة [cite: 83-89]
void dataReadyISR() {
dataReady = true;
}
// الدوال المساعدة (Prototypes)
void MPU6050_Init(void);
void MPU6050_ReadAccel(int16_t* ax, int16_t* ay, int16_t* az);
void TriggerAirbag(void);
void HandleFault(void);
// ==========================================
// 4. الجزء الأول — تهيئة النظام [cite: 30-46]
// ==========================================
void setup() {
// تهيئة المنافذ [cite: 32-34]
pinMode(POWER_LED_PIN, OUTPUT);
pinMode(ARMED_LED_PIN, OUTPUT);
pinMode(FAULT_LED_PIN, OUTPUT);
pinMode(TRIGGER_LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(TRIGGER_MOSFET_PIN, OUTPUT);
pinMode(ARM_SWITCH_PIN, INPUT_PULLUP);
pinMode(MPU_INT_PIN, INPUT);
digitalWrite(POWER_LED_PIN, HIGH);
digitalWrite(TRIGGER_MOSFET_PIN, LOW);
// تهيئة UART بسرعة 115200 [cite: 35-37]
Serial.begin(115200);
Serial.println("SYSTEM INIT"); // [cite: 39]
// قراءة سجل الصدمات من EEPROM [cite: 123-125]
crashCount = EEPROM.read(EEPROM_CRASH_ADDR);
if (crashCount == 255) { crashCount = 0; } // تصفير الذاكرة المصنعية
Serial.print("Previous Crashes: ");
Serial.println(crashCount);
// تهيئة I2C [cite: 44-46]
Wire.begin();
Wire.setClock(400000);
// تهيئة الحساس ومعالجة الأخطاء [cite: 90-96]
MPU6050_Init();
// التحقق من حالة الاتصال
Wire.beginTransmission(MPU_ADDR);
if (Wire.endTransmission() == 0) {
Serial.println("MPU6050 OK"); // [cite: 40]
attachInterrupt(digitalPinToInterrupt(MPU_INT_PIN), dataReadyISR, RISING);
currentState = (digitalRead(ARM_SWITCH_PIN) == LOW) ? ARMED : DISARMED;
} else {
HandleFault();
}
}
// ==========================================
// 5. الحلقة الرئيسية (Non-Blocking) [cite: 133-134]
// ==========================================
void loop() {
if (currentState == TRIGGERED || currentState == FAULT) return;
bool isArmed = (digitalRead(ARM_SWITCH_PIN) == LOW);
// وضع ARM [cite: 75-78]
if (isArmed && currentState == DISARMED) {
currentState = ARMED;
digitalWrite(ARMED_LED_PIN, HIGH);
Serial.println("ARMED"); // [cite: 41]
}
// وضع DISARM [cite: 79-82]
else if (!isArmed && currentState == ARMED) {
currentState = DISARMED;
digitalWrite(ARMED_LED_PIN, LOW);
digitalWrite(TRIGGER_MOSFET_PIN, LOW);
}
// اكتشاف الصدمة وإرسال البيانات [cite: 98, 131]
if (dataReady && currentState == ARMED) {
dataReady = false;
int16_t ax, ay, az;
MPU6050_ReadAccel(&ax, &ay, &az); // [cite: 53-56]
// إرسال البيانات (Telemetry) كل 100 ميلي ثانية لتجنب التأخير [cite: 126-128]
static unsigned long lastTelemetryTime = 0;
if (millis() - lastTelemetryTime >= 100) {
Serial.print("AX="); Serial.print(ax);
Serial.print(" AY="); Serial.print(ay);
Serial.print(" AZ="); Serial.println(az);
lastTelemetryTime = millis();
}
// شرط التفعيل > 3G على أي محور [cite: 61-67]
if (abs(ax) > G_THRESHOLD_RAW || abs(ay) > G_THRESHOLD_RAW || abs(az) > G_THRESHOLD_RAW) {
TriggerAirbag(); // [cite: 68-73]
}
}
}
// ==========================================
// 6. الجزء الثاني — دوال التعامل مع الحساس [cite: 47-57]
// ==========================================
void MPU6050_Init(void) { // [cite: 52]
Wire.beginTransmission(MPU_ADDR);
Wire.write(PWR_MGMT_1);
Wire.write(0x01);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(MPU_ADDR);
Wire.write(ACCEL_CONFIG);
Wire.write(0x18); // ±16g
Wire.endTransmission();
Wire.beginTransmission(MPU_ADDR);
Wire.write(CONFIG_REG);
Wire.write(0x03); // DLPF للحد من False Triggering [cite: 112-114]
Wire.endTransmission();
Wire.beginTransmission(MPU_ADDR);
Wire.write(SMPLRT_DIV);
Wire.write(0x00); // 1kHz
Wire.endTransmission();
Wire.beginTransmission(MPU_ADDR);
Wire.write(INT_PIN_CFG);
Wire.write(0x10);
Wire.endTransmission();
Wire.beginTransmission(MPU_ADDR);
Wire.write(INT_ENABLE);
Wire.write(0x01);
Wire.endTransmission();
}
void MPU6050_ReadAccel(int16_t* ax, int16_t* ay, int16_t* az) { // [cite: 53-57]
Wire.beginTransmission(MPU_ADDR);
Wire.write(ACCEL_XOUT_H);
Wire.endTransmission(false);
Wire.requestFrom((uint8_t)MPU_ADDR, (uint8_t)6, (uint8_t)true);
if(Wire.available() == 6) {
*ax = (Wire.read() << 8 | Wire.read());
*ay = (Wire.read() << 8 | Wire.read());
*az = (Wire.read() << 8 | Wire.read());
}
}
// ==========================================
// 7. إجراءات النظام والأخطاء [cite: 68-73, 90-96]
// ==========================================
void TriggerAirbag(void) {
digitalWrite(TRIGGER_MOSFET_PIN, HIGH); // [cite: 69]
digitalWrite(TRIGGER_LED_PIN, HIGH); // [cite: 70]
digitalWrite(BUZZER_PIN, HIGH); // [cite: 71]
currentState = TRIGGERED;
Serial.println("TRIGGERED"); // [cite: 72-73]
// تحديث سجل الحوادث في EEPROM [cite: 123-125]
crashCount++;
EEPROM.write(EEPROM_CRASH_ADDR, crashCount);
}
void HandleFault(void) {
currentState = FAULT;
digitalWrite(FAULT_LED_PIN, HIGH); // [cite: 93]
digitalWrite(BUZZER_PIN, HIGH); // [cite: 94]
digitalWrite(TRIGGER_MOSFET_PIN, LOW); // الأمان
Serial.println("SENSOR ERROR"); // [cite: 95-96]
}