#include // تعریف پین‌های I2C #define I2C_SDA PB9 #define I2C_SCL PB8 // آدرس سنسورها #define BH1750_ADDR 0x23 #define SHT31_ADDR 0x44 // حالتهای اندازه‌گیری BH1750 #define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10 #define BH1750_ONE_TIME_HIGH_RES_MODE 0x20 // دستورات SHT31 #define SHT31_MEAS_HIGHREP 0x2400 #define SHT31_MEAS_MEDREP 0x240B #define SHT31_MEAS_LOWREP 0x2416 #define SHT31_SOFTRESET 0x30A2 #define SHT31_HEATER_ENABLE 0x306D #define SHT31_HEATER_DISABLE 0x3066 #define SHT31_STATUS_REG 0xF32D #define SHT31_CLEAR_STATUS 0x3041 // متغیرهای ذخیره‌سازی مقادیر float lastLightLevel = 0.0; float lastTemperature = 0.0; float lastHumidity = 0.0; // متغیرهای تشخیص خطا bool bh1750Available = false; bool sht31Available = false; uint8_t bh1750ErrorCount = 0; uint8_t sht31ErrorCount = 0; const uint8_t MAX_ERRORS = 5; // زمان آخرین اندازه‌گیری موفق unsigned long lastBh1750Success = 0; unsigned long lastSht31Success = 0; // تابع بازیابی نرم I2C (بدون ریست سخت‌افزاری) void recoverI2C() { Serial1.println("Attempting I2C recovery..."); // آزاد کردن خطوط pinMode(I2C_SDA, INPUT_PULLUP); pinMode(I2C_SCL, INPUT_PULLUP); delay(1000); // تولید پالس‌های ساعت برای آزادسازی هر دستگاه قفل شده pinMode(I2C_SCL, OUTPUT); for (int i = 0; i < 9; i++) { digitalWrite(I2C_SCL, LOW); delayMicroseconds(5); digitalWrite(I2C_SCL, HIGH); delayMicroseconds(5); } // ایجاد شرط STOP pinMode(I2C_SDA, OUTPUT); digitalWrite(I2C_SDA, LOW); delayMicroseconds(5); digitalWrite(I2C_SCL, HIGH); delayMicroseconds(5); digitalWrite(I2C_SDA, HIGH); delayMicroseconds(5); // بازگشت به حالت عادی Wire.begin(); Serial1.println("I2C recovery completed"); } // تابع بررسی وجود دستگاه روی باس I2C bool checkDevice(uint8_t address) { Wire.beginTransmission(address); byte error = Wire.endTransmission(); return (error == 0); } bool initBH1750() { if (!checkDevice(BH1750_ADDR)) { Serial1.println("BH1750 not found!"); bh1750Available = false; return false; } bh1750Available = true; bh1750ErrorCount = 0; Serial1.println("BH1750 ready (One-Time mode)"); return true; } bool readBH1750(float &lightLevel) { if (!bh1750Available && bh1750ErrorCount < MAX_ERRORS) { if (!initBH1750()) return false; } if (!bh1750Available) return false; // ارسال فرمان One-Time High Resolution Wire.beginTransmission(BH1750_ADDR); Wire.write(BH1750_ONE_TIME_HIGH_RES_MODE); byte error = Wire.endTransmission(); if (error != 0) { bh1750ErrorCount++; Serial1.println("BH1750 command error"); return false; } // زمان تبدیل (حداکثر 180ms طبق دیتاشیت) delay(180); // درخواست 2 بایت داده Wire.requestFrom(BH1750_ADDR, 2); if (Wire.available() == 2) { uint16_t value = Wire.read(); value <<= 8; value |= Wire.read(); lightLevel = value / 1.2; if (lightLevel >= 0 && lightLevel <= 65535) { lastLightLevel = lightLevel; bh1750ErrorCount = 0; lastBh1750Success = millis(); return true; } } // در صورت خطا bh1750ErrorCount++; Serial1.println("Error reading BH1750"); if (bh1750ErrorCount >= MAX_ERRORS) { bh1750Available = false; Serial1.println("BH1750 marked as unavailable"); } return false; } // تابع مقداردهی اولیه BH1750 bool __initBH1750() { if (!checkDevice(BH1750_ADDR)) { Serial1.println("BH1750 not found!"); bh1750Available = false; return false; } // ارسال دستور اندازه‌گیری پیوسته Wire.beginTransmission(BH1750_ADDR); Wire.write(BH1750_CONTINUOUS_HIGH_RES_MODE); byte error = Wire.endTransmission(); if (error == 0) { bh1750Available = true; bh1750ErrorCount = 0; Serial1.println("BH1750 initialized successfully"); return true; } else { bh1750Available = false; Serial1.print("BH1750 init error: "); Serial1.println(error); return false; } } // تابع خواندن نور از BH1750 bool __readBH1750(float &lightLevel) { if (!bh1750Available && bh1750ErrorCount < MAX_ERRORS) { if (initBH1750()) { delay(180); // تأخیر برای اولین اندازه‌گیری } } if (!bh1750Available) return false; // درخواست 2 بایت داده Wire.requestFrom(BH1750_ADDR, 2); if (Wire.available() == 2) { uint16_t value = Wire.read(); value <<= 8; value |= Wire.read(); lightLevel = value / 1.2; // محاسبه لوکس // اعتبارسنجی مقدار if (lightLevel >= 0 && lightLevel <= 65535) { lastLightLevel = lightLevel; bh1750ErrorCount = 0; lastBh1750Success = millis(); return true; } } // در صورت خطا bh1750ErrorCount++; Serial1.println("Error reading BH1750"); if (bh1750ErrorCount >= MAX_ERRORS) { bh1750Available = false; Serial1.println("BH1750 marked as unavailable"); } return false; } // تابع مقداردهی اولیه SHT31 bool initSHT31() { if (!checkDevice(SHT31_ADDR)) { Serial1.println("SHT31 not found!"); sht31Available = false; return false; } // ارسال دستور ریست نرم Wire.beginTransmission(SHT31_ADDR); Wire.write(SHT31_SOFTRESET >> 8); Wire.write(SHT31_SOFTRESET & 0xFF); byte error = Wire.endTransmission(); if (error != 0) { sht31Available = false; Serial1.print("SHT31 reset error: "); Serial1.println(error); return false; } delay(10); // تأخیر بعد از ریست // غیرفعال کردن هیتر (برای مصرف کمتر و عمر طولانی‌تر) Wire.beginTransmission(SHT31_ADDR); Wire.write(SHT31_HEATER_DISABLE >> 8); Wire.write(SHT31_HEATER_DISABLE & 0xFF); error = Wire.endTransmission(); if (error == 0) { sht31Available = true; sht31ErrorCount = 0; Serial1.println("SHT31 initialized successfully"); return true; } else { sht31Available = false; Serial1.print("SHT31 init error: "); Serial1.println(error); return false; } } // تابع خواندن دما و رطوبت از SHT31 bool readSHT31(float &temperature, float &humidity) { if (!sht31Available && sht31ErrorCount < MAX_ERRORS) { initSHT31(); } if (!sht31Available) return false; // ارسال دستور اندازه‌گیری با دقت بالا Wire.beginTransmission(SHT31_ADDR); Wire.write(SHT31_MEAS_HIGHREP >> 8); Wire.write(SHT31_MEAS_HIGHREP & 0xFF); byte error = Wire.endTransmission(); if (error != 0) { sht31ErrorCount++; Serial1.println("Error sending measurement command to SHT31"); return false; } // تأخیر برای تبدیل (حداکثر 15ms برای حالت High Rep) delay(15); // خواندن 6 بایت داده Wire.requestFrom(SHT31_ADDR, 6); if (Wire.available() == 6) { uint16_t tempRaw = Wire.read(); tempRaw <<= 8; tempRaw |= Wire.read(); uint8_t tempCRC = Wire.read(); uint16_t humRaw = Wire.read(); humRaw <<= 8; humRaw |= Wire.read(); uint8_t humCRC = Wire.read(); // تبدیل مقادیر temperature = -45 + (175 * (float)tempRaw / 65535.0); humidity = 100 * (float)humRaw / 65535.0; // اعتبارسنجی مقادیر if (temperature >= -40 && temperature <= 125 && humidity >= 0 && humidity <= 100) { lastTemperature = temperature; lastHumidity = humidity; sht31ErrorCount = 0; lastSht31Success = millis(); return true; } } // در صورت خطا sht31ErrorCount++; Serial1.println("Error reading SHT31"); if (sht31ErrorCount >= MAX_ERRORS) { sht31Available = false; Serial1.println("SHT31 marked as unavailable"); } return false; } // تابع بررسی دوره‌ای سلامت باس I2C void checkI2CHealth() { static unsigned long lastCheck = 0; unsigned long currentMillis = millis(); // هر 30 ثانیه بررسی کن if (currentMillis - lastCheck >= 30000) { lastCheck = currentMillis; bool bh1750WasAvailable = bh1750Available; bool sht31WasAvailable = sht31Available; // بررسی BH1750 if (checkDevice(BH1750_ADDR)) { if (!bh1750WasAvailable) { Serial1.println("BH1750 reappeared, reinitializing..."); initBH1750(); } } else if (bh1750WasAvailable) { Serial1.println("BH1750 disappeared!"); bh1750Available = false; } // بررسی SHT31 if (checkDevice(SHT31_ADDR)) { if (!sht31WasAvailable) { Serial1.println("SHT31 reappeared, reinitializing..."); initSHT31(); } } else if (sht31WasAvailable) { Serial1.println("SHT31 disappeared!"); sht31Available = false; } // اگر هر دو دستگاه از دست رفته‌اند، بازیابی باس I2C if (!bh1750Available && !sht31Available) { recoverI2C(); // تلاش مجدد برای مقداردهی اولیه delay(100); initBH1750(); initSHT31(); } } } void setup() { Serial1.begin(115200); Serial1.println("Starting STM32 with BH1750 and SHT31..."); // مقداردهی اولیه I2C Wire.setSDA(I2C_SDA); Wire.setSCL(I2C_SCL); Wire.begin(); Wire.setClock(100000); // 100kHz برای پایداری بهتر // افزایش timeout برای جلوگیری از hang شدن Wire.setTimeout(1000); delay(1000); // تأخیر برای پایدار شدن // مقداردهی اولیه سنسورها initBH1750(); initSHT31(); Serial1.println("Setup completed"); } void loop() { static unsigned long lastRead = 0; unsigned long currentMillis = millis(); // خواندن هر 2 ثانیه if (currentMillis - lastRead >= 2000) { lastRead = currentMillis; // خواندن BH1750 float light; if (readBH1750(light)) { Serial1.print("Light: "); Serial1.print(light); Serial1.println(" lux"); } else { Serial1.print("Using last BH1750 value: "); Serial1.print(lastLightLevel); Serial1.println(" lux"); } delay(500); // خواندن SHT31 float temp, hum; if (readSHT31(temp, hum)) { Serial1.print("Temperature: "); Serial1.print(temp); Serial1.print(" °C, Humidity: "); Serial1.print(hum); Serial1.println(" %"); } else { Serial1.print("Using last SHT31 values - Temp: "); Serial1.print(lastTemperature); Serial1.print(" °C, Hum: "); Serial1.print(lastHumidity); Serial1.println(" %"); } Serial1.println("---"); } // بررسی سلامت دوره‌ای checkI2CHealth(); // تأخیر کوتاه برای جلوگیری از overload delay(10); }