Files
Arduino/14041130/I2C-best/I2C-best.ino
2026-02-19 06:17:44 +03:30

433 lines
11 KiB
C++

#include <Wire.h>
// تعریف پین‌های 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);
}