#ifndef SENSORS_H #define SENSORS_H #include #include #include "Config.h" #define VCC 4.63 #define RL 10000.0 #define VDIV_RATIO 0.681 #define I2C_TIMEOUT_MS 100 // تعریف پین‌ها #define BH1750_SDA_PIN PB7 #define BH1750_SCL_PIN PB6 #define SHT31_SDA_PIN PB9 #define SHT31_SCL_PIN PB8 #define SHT31_ADDR 0x44 #define BH1750_ADDR 0x23 // متغیرهای خارجی extern SensorData currentData; extern bool sht31Connected; extern bool lightSensorConnected; extern bool coSensorConnected; extern bool calibrationComplete; extern unsigned long systemStartTime; extern unsigned long lastSensorRead; extern float MQ7_R0; extern TwoWire Wire1; extern const long calibrationPeriod; // توابع void initSensors(); void readSensors(); void checkSensorStatus(); // -------------------- پاکسازی باس I2C -------------------- inline void i2cBusClear(uint8_t scl_pin, uint8_t sda_pin, bool isWire1 = false) { Serial1.print("Clearing I2C bus on pins SCL:"); Serial1.print(scl_pin); Serial1.print(" SDA:"); Serial1.println(sda_pin); // آزاد کردن باس if (isWire1) { Wire1.end(); } else { Wire.end(); } delay(50); // تنظیم پین‌ها به صورت دستی pinMode(scl_pin, OUTPUT_OPEN_DRAIN); pinMode(sda_pin, OUTPUT_OPEN_DRAIN); digitalWrite(sda_pin, HIGH); digitalWrite(scl_pin, HIGH); delayMicroseconds(10); // تولید پالس کلاک برای رهاسازی باس for (int i = 0; i < 18; i++) { digitalWrite(scl_pin, LOW); delayMicroseconds(5); digitalWrite(scl_pin, HIGH); delayMicroseconds(5); } // ایجاد شرط STOP digitalWrite(sda_pin, LOW); delayMicroseconds(5); digitalWrite(scl_pin, HIGH); delayMicroseconds(5); digitalWrite(sda_pin, HIGH); delayMicroseconds(5); delay(100); // راه‌اندازی مجدد if (isWire1) { Wire1.setSDA(sda_pin); Wire1.setSCL(scl_pin); Wire1.begin(); Wire1.setClock(50000); // سرعت پایین برای پایداری } else { Wire.setSDA(sda_pin); Wire.setSCL(scl_pin); Wire.begin(); Wire.setClock(50000); // سرعت پایین برای پایداری } delay(100); } // -------------------- کالیبراسیون MQ7 -------------------- inline void calibrateMQ7() { Serial1.println("Calibrating MQ7..."); float sumRS = 0; for(int i = 0; i < 50; i++) { // کاهش از 100 به 50 int adc = analogRead(MQ7_PIN); float v_adc = adc * (5.0 / 4095.0); float v_ao = v_adc / VDIV_RATIO; if (v_ao < 0.01) v_ao = 0.01; float RS = RL * (VCC / v_ao - 1.0); sumRS += RS; delay(20); // کاهش تاخیر } MQ7_R0 = (sumRS / 50.0) / 9.8; calibrationComplete = true; Serial1.print("MQ7 R0 calibrated: "); Serial1.println(MQ7_R0); } // -------------------- خواندن CO -------------------- inline float readCOImproved() { float sumVoltage = 0; for (int i = 0; i < 10; i++) { // کاهش از 20 به 10 int adc = analogRead(MQ7_PIN); float v_adc = adc * (5.0 / 4095.0); sumVoltage += v_adc; delay(1); } float v_avg = sumVoltage / 10.0; if (v_avg < 0.01) v_avg = 0.01; if (v_avg > 4.99) v_avg = 4.99; float v_ao = v_avg / VDIV_RATIO; float RS = RL * (VCC / v_ao - 1.0); float ratio = RS / MQ7_R0; float ppm = 0; if (ratio > 0) { ppm = 100.0 * pow(ratio, -1.53); ppm = constrain(ppm, 0, 5000); } if (!calibrationComplete) { ppm = -ppm; } return ppm; } // -------------------- خواندن SHT31 (ساده‌شده) -------------------- inline bool readSHT31(float &temperature, float &humidity) { static uint8_t errorCount = 0; static bool needsReset = false; // اگر نیاز به بازنشانی داریم if (needsReset) { Serial1.println("Resetting SHT31 I2C bus..."); i2cBusClear(SHT31_SCL_PIN, SHT31_SDA_PIN, false); needsReset = false; delay(100); } // تست اتصال اولیه Wire.beginTransmission(SHT31_ADDR); uint8_t connError = Wire.endTransmission(); if (connError != 0) { Serial1.print("SHT31 connection error: "); Serial1.println(connError); errorCount++; if (errorCount >= 2) { needsReset = true; errorCount = 0; } return false; } // ارسال دستور اندازه‌گیری (کوتاه) Wire.beginTransmission(SHT31_ADDR); if (Wire.write(0x2C) != 1) { // دستور سریع Serial1.println("SHT31 write failed"); return false; } if (Wire.write(0x06) != 1) { // تکرار بالا Serial1.println("SHT31 write failed"); return false; } uint8_t writeError = Wire.endTransmission(); if (writeError != 0) { Serial1.print("SHT31 write error: "); Serial1.println(writeError); errorCount++; if (errorCount >= 2) { needsReset = true; errorCount = 0; } return false; } // تاخیر اندازه‌گیری delay(20); // برای حالت High Repeatability // خواندن داده uint8_t bytesRead = Wire.requestFrom(SHT31_ADDR, (uint8_t)6, (uint8_t)true); if (bytesRead != 6) { Serial1.print("SHT31 read error, bytes: "); Serial1.println(bytesRead); // خالی کردن بافر while (Wire.available()) { Wire.read(); } errorCount++; if (errorCount >= 2) { needsReset = true; errorCount = 0; } return false; } // خواندن بایت‌ها uint8_t data[6]; for (int i = 0; i < 6; i++) { data[i] = Wire.read(); } // بررسی CRC (ساده‌شده) uint16_t tRaw = (data[0] << 8) | data[1]; uint16_t hRaw = (data[3] << 8) | data[4]; // تبدیل مقادیر temperature = -45.0 + 175.0 * tRaw / 65535.0; humidity = 100.0 * hRaw / 65535.0; // اعتبارسنجی if (isnan(temperature) || isnan(humidity) || temperature < -40 || temperature > 125 || humidity < 0 || humidity > 100) { Serial1.println("SHT31 invalid data"); return false; } errorCount = 0; // ریست شمارنده خطا return true; } // -------------------- خواندن BH1750 -------------------- inline bool readBH1750(float &lux) { static bool initialized = false; static uint8_t errorCount = 0; // مقداردهی اولیه if (!initialized) { Serial1.println("Initializing BH1750..."); Wire1.setSDA(BH1750_SDA_PIN); Wire1.setSCL(BH1750_SCL_PIN); Wire1.begin(); Wire1.setClock(50000); // سرعت پایین delay(100); // پاور آن Wire1.beginTransmission(BH1750_ADDR); Wire1.write(0x01); if (Wire1.endTransmission() != 0) { Serial1.println("BH1750 power on failed"); return false; } delay(10); // تنظیم حالت Wire1.beginTransmission(BH1750_ADDR); Wire1.write(0x13); // Continuous H-Resolution Mode 0.5lx if (Wire1.endTransmission() != 0) { Serial1.println("BH1750 mode set failed"); return false; } initialized = true; delay(180); // زمان اولیه برای اندازه‌گیری } // خواندن داده uint8_t bytesRead = Wire1.requestFrom(BH1750_ADDR, (uint8_t)2); if (bytesRead != 2) { Serial1.print("BH1750 read error, bytes: "); Serial1.println(bytesRead); errorCount++; if (errorCount >= 3) { initialized = false; errorCount = 0; } return false; } // خواندن بایت‌ها uint8_t highByte = Wire1.read(); uint8_t lowByte = Wire1.read(); uint16_t raw = (highByte << 8) | lowByte; lux = raw / 1.2f; errorCount = 0; return true; } // -------------------- بررسی وضعیت سنسورها -------------------- inline void checkSensorStatus() { // فقط چاپ وضعیت فعلی Serial1.println("--- Sensor Status ---"); Serial1.print("SHT31: "); Serial1.println(sht31Connected ? "OK" : "ERROR"); Serial1.print("BH1750: "); Serial1.println(lightSensorConnected ? "OK" : "ERROR"); Serial1.print("MQ7: "); Serial1.println(coSensorConnected ? "OK" : "ERROR"); } // -------------------- خواندن همه سنسورها -------------------- inline void readSensors() { Serial1.println("\n=== Reading Sensors ==="); // اول BH1750 را بخوان (چون کار می‌کند) float lux; if (readBH1750(lux)) { currentData.lightLux = lux; lightSensorConnected = true; Serial1.print("BH1750: "); Serial1.print(lux, 0); Serial1.println(" lux"); } else { currentData.lightLux = 0; lightSensorConnected = false; Serial1.println("BH1750: FAILED"); } // سپس SHT31 float temperature = NAN, humidity = NAN; bool sht31Read = readSHT31(temperature, humidity); if (sht31Read && !isnan(temperature) && !isnan(humidity)) { currentData.temperature = temperature; currentData.humidity = humidity; sht31Connected = true; Serial1.print("SHT31: T="); Serial1.print(temperature, 1); Serial1.print("C, H="); Serial1.print(humidity, 1); Serial1.println("%"); } else { currentData.temperature = NAN; currentData.humidity = NAN; sht31Connected = false; Serial1.println("SHT31: FAILED"); } // کالیبراسیون MQ7 if (!calibrationComplete && (millis() - systemStartTime >= calibrationPeriod)) { calibrateMQ7(); calibrationComplete = true; } // خواندن CO currentData.coPPM = readCOImproved(); int adc = analogRead(MQ7_PIN); coSensorConnected = (adc > 10 && adc < 4085); Serial1.print("MQ7: "); Serial1.print(currentData.coPPM, 1); Serial1.println(" ppm"); // محاسبه درصدها calculatePercentages(currentData); lastSensorRead = millis(); Serial1.println("=== Sensor Readings Complete ===\n"); // اگر SHT31 کار نمی‌کند، سیستم را مسدود نکن if (!sht31Connected) { Serial1.println("Warning: SHT31 not responding, continuing anyway..."); } } // -------------------- مقداردهی اولیه -------------------- inline void initSensors() { Serial1.println("Initializing sensors..."); // راه‌اندازی I2C1 برای SHT31 (سرعت پایین) Wire.setSDA(SHT31_SDA_PIN); Wire.setSCL(SHT31_SCL_PIN); Wire.begin(); Wire.setClock(50000); // 50kHz برای پایداری Wire.setTimeout(100); // راه‌اندازی I2C2 برای BH1750 Wire1.setSDA(BH1750_SDA_PIN); Wire1.setSCL(BH1750_SCL_PIN); Wire1.begin(); Wire1.setClock(50000); // 50kHz Wire1.setTimeout(100); // پیکربندی MQ7 pinMode(MQ7_PIN, INPUT); analogReadResolution(12); delay(1000); // اسکن آدرس‌های I2C Serial1.println("Scanning I2C1 (SHT31)..."); byte error; int found1 = 0; for(byte addr = 1; addr < 127; addr++) { Wire.beginTransmission(addr); error = Wire.endTransmission(); if (error == 0) { Serial1.print("Found device at 0x"); if (addr < 16) Serial1.print("0"); Serial1.println(addr, HEX); found1++; } } Serial1.print("I2C1 devices: "); Serial1.println(found1); Serial1.println("Scanning I2C2 (BH1750)..."); int found2 = 0; for(byte addr = 1; addr < 127; addr++) { Wire1.beginTransmission(addr); error = Wire1.endTransmission(); if (error == 0) { Serial1.print("Found device at 0x"); if (addr < 16) Serial1.print("0"); Serial1.println(addr, HEX); found2++; } } Serial1.print("I2C2 devices: "); Serial1.println(found2); // تست اولیه سریع Serial1.println("Quick sensor test..."); float lux; if (readBH1750(lux)) { lightSensorConnected = true; Serial1.print("BH1750 OK: "); Serial1.print(lux); Serial1.println(" lux"); } delay(100); float temp, hum; if (readSHT31(temp, hum)) { sht31Connected = true; Serial1.print("SHT31 OK: "); Serial1.print(temp); Serial1.print("C "); Serial1.print(hum); Serial1.println("%"); } Serial1.println("Sensor init done"); } #endif // SENSORS_H