backup 14041130
This commit is contained in:
924
14041130/TestLCD/Sensors.h
Normal file
924
14041130/TestLCD/Sensors.h
Normal file
@@ -0,0 +1,924 @@
|
||||
#ifndef SENSORS_H
|
||||
#define SENSORS_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include "Config.h"
|
||||
|
||||
// ================== تعاریف و ماکروها از کد دوم ==================
|
||||
// تعریف آدرس سنسورها
|
||||
#define BH1750_ADDR 0x23
|
||||
#define SHT31_ADDR 0x44
|
||||
|
||||
// حالتهای اندازهگیری BH1750
|
||||
#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10
|
||||
#define BH1750_ONE_TIME_HIGH_RES_MODE 0x20
|
||||
|
||||
#define BH1750_POWER_DOWN 0x00
|
||||
#define BH1750_POWER_ON 0x01
|
||||
#define BH1750_RESET 0x07
|
||||
|
||||
// دستورات 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
|
||||
|
||||
|
||||
#define VREF_ADC 3.3f // ولتاژ مرجع ADC
|
||||
#define ADC_RESOLUTION 4095.0f // رزولوشن ADC 12 بیت
|
||||
#define R1 2190.0f // مقاومت سری اول (اهم)
|
||||
#define R2 3270.0f // مقاومت به زمین (اهم)
|
||||
#define RL_SENSOR 839.0f // مقاومت بار ماژول (مقاومت بین خروجی آنالوگ و GND)
|
||||
#define MQ7_PIN PA2 // پین ADC
|
||||
#define NUM_SAMPLES 10 // تعداد نمونه برای میانگینگیری
|
||||
|
||||
// پارامترهای سنسور MQ7 برای تبدیل به ppm (از دیتاشیت)
|
||||
#define CO_A 1.9f // ضریب A
|
||||
#define CO_B -0.6f // ضریب B
|
||||
#define PREHEAT_TIME_MS (2 * 60 * 1000) // 2 دقیقه پیشگرمایش
|
||||
|
||||
// متغیرهای جهانی
|
||||
float VCC_SENSOR = 4.9f; // ولتاژ تغذیه سنسور MQ7
|
||||
float MQ7_R0 = 24150.0; //g:14600,14500 //2:24150.0;
|
||||
unsigned long deviceStartTime = 0;
|
||||
bool MQ7sensorPreheated=false;
|
||||
extern bool coSensorConnected;
|
||||
/* ================== ساختار وضعیت سیستم (از کد اول) ================== */
|
||||
struct SystemStatus {
|
||||
bool sht31OK;
|
||||
bool bh1750OK;
|
||||
uint32_t lastRecovery;
|
||||
uint32_t lastSuccess;
|
||||
uint16_t errorCount;
|
||||
};
|
||||
|
||||
extern SystemStatus i2cStatus;
|
||||
|
||||
/* ================== متغیرهای عمومی ================== */
|
||||
extern SensorData currentData;
|
||||
extern unsigned long lastSensorRead;
|
||||
|
||||
/* ================== متغیرهای اختصاصی از کد دوم ================== */
|
||||
// متغیرهای ذخیرهسازی مقادیر آخرین خوانش موفق
|
||||
extern float lastLightLevel;
|
||||
extern float lastTemperature;
|
||||
extern float lastHumidity;
|
||||
|
||||
// متغیرهای تشخیص خطا از کد دوم
|
||||
extern uint8_t bh1750ErrorCount;
|
||||
extern uint8_t sht31ErrorCount;
|
||||
extern const uint8_t MAX_ERRORS;
|
||||
|
||||
// زمان آخرین اندازهگیری موفق از کد دوم
|
||||
extern unsigned long lastBh1750Success;
|
||||
extern unsigned long lastSht31Success;
|
||||
|
||||
/* ================== توابع عمومی ================== */
|
||||
void initSensors();
|
||||
void readSensors();
|
||||
void updateSensors(); // حلقه اصلی (جایگزین loop)
|
||||
|
||||
/* ================== توابع I2C مستقیم (از کد دوم) ================== */
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// تابع بررسی وجود دستگاه روی باس I2C (از کد دوم)
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline bool checkDevice(uint8_t address) {
|
||||
Wire.beginTransmission(address);
|
||||
byte error = Wire.endTransmission();
|
||||
return (error == 0);
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// تابع مقداردهی اولیه BH1750 (از کد دوم)
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline bool initBH1750Direct() {
|
||||
if (!checkDevice(BH1750_ADDR)) {
|
||||
Serial1.println("BH1750 not found!");
|
||||
i2cStatus.bh1750OK = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
i2cStatus.bh1750OK = true;
|
||||
bh1750ErrorCount = 0;
|
||||
Serial1.println("BH1750 ready (One-Time mode)");
|
||||
return true;
|
||||
}
|
||||
bool bh1750SoftReset() {
|
||||
|
||||
Wire.beginTransmission(BH1750_ADDR);
|
||||
Wire.write(BH1750_POWER_DOWN);
|
||||
if (Wire.endTransmission() != 0) return false;
|
||||
|
||||
delay(5);
|
||||
|
||||
Wire.beginTransmission(BH1750_ADDR);
|
||||
Wire.write(BH1750_POWER_ON);
|
||||
if (Wire.endTransmission() != 0) return false;
|
||||
|
||||
delay(5);
|
||||
|
||||
// دستور Reset فقط بعد از Power On معتبر است
|
||||
Wire.beginTransmission(BH1750_ADDR);
|
||||
Wire.write(BH1750_RESET);
|
||||
if (Wire.endTransmission() != 0) return false;
|
||||
|
||||
delay(5);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool readBH1750Direct(float &lightLevel) {
|
||||
|
||||
if (!i2cStatus.bh1750OK) {
|
||||
if (!initBH1750Direct()) return false;
|
||||
}
|
||||
|
||||
// 👇 مهم: ریست داخلی قبل از هر خواندن
|
||||
if (!bh1750SoftReset()) {
|
||||
bh1750ErrorCount++;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ارسال فرمان اندازهگیری
|
||||
Wire.beginTransmission(BH1750_ADDR);
|
||||
Wire.write(BH1750_ONE_TIME_HIGH_RES_MODE);
|
||||
byte error = Wire.endTransmission();
|
||||
|
||||
if (error != 0) {
|
||||
bh1750ErrorCount++;
|
||||
return false;
|
||||
}
|
||||
|
||||
delay(180);
|
||||
|
||||
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;
|
||||
i2cStatus.bh1750OK = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// اگر به اینجا رسید یعنی خواندن شکست خورده
|
||||
bh1750ErrorCount++;
|
||||
|
||||
if (bh1750ErrorCount >= 3) {
|
||||
// تلاش برای ریست کامل سنسور
|
||||
bh1750SoftReset();
|
||||
delay(50);
|
||||
}
|
||||
|
||||
if (bh1750ErrorCount >= MAX_ERRORS) {
|
||||
i2cStatus.bh1750OK = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// تابع مقداردهی اولیه SHT31 (از کد دوم)
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline bool initSHT31Direct() {
|
||||
if (!checkDevice(SHT31_ADDR)) {
|
||||
Serial1.println("SHT31 not found!");
|
||||
i2cStatus.sht31OK = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ارسال دستور ریست نرم
|
||||
Wire.beginTransmission(SHT31_ADDR);
|
||||
Wire.write(SHT31_SOFTRESET >> 8);
|
||||
Wire.write(SHT31_SOFTRESET & 0xFF);
|
||||
byte error = Wire.endTransmission();
|
||||
|
||||
if (error != 0) {
|
||||
i2cStatus.sht31OK = 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) {
|
||||
i2cStatus.sht31OK = true;
|
||||
sht31ErrorCount = 0;
|
||||
Serial1.println("SHT31 initialized successfully");
|
||||
return true;
|
||||
} else {
|
||||
i2cStatus.sht31OK = false;
|
||||
Serial1.print("SHT31 init error: ");
|
||||
Serial1.println(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// تابع خواندن دما و رطوبت از SHT31 (از کد دوم)
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline bool readSHT31Direct(float &temperature, float &humidity) {
|
||||
// اگر سنسور غیرفعال است و هنوز خطاها کم است، سعی در راهاندازی مجدد
|
||||
if (!i2cStatus.sht31OK && sht31ErrorCount < MAX_ERRORS) {
|
||||
initSHT31Direct();
|
||||
}
|
||||
|
||||
if (!i2cStatus.sht31OK) 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) {
|
||||
i2cStatus.sht31OK = false;
|
||||
Serial1.println("SHT31 marked as unavailable");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ================== توابع I2C Recovery (از کد اول) ================== */
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// پاکسازی باس I2C با Clock Pulse
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline void cleanI2CBus() {
|
||||
pinMode(I2C_SCL_PIN, OUTPUT);
|
||||
pinMode(I2C_SDA_PIN, OUTPUT);
|
||||
|
||||
digitalWrite(I2C_SCL_PIN, HIGH);
|
||||
digitalWrite(I2C_SDA_PIN, HIGH);
|
||||
delay(5);
|
||||
|
||||
// ارسال 16 clock pulse
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
digitalWrite(I2C_SCL_PIN, LOW);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(I2C_SCL_PIN, HIGH);
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
|
||||
// STOP condition
|
||||
digitalWrite(I2C_SDA_PIN, LOW);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(I2C_SCL_PIN, HIGH);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(I2C_SDA_PIN, HIGH);
|
||||
delayMicroseconds(5);
|
||||
|
||||
pinMode(I2C_SCL_PIN, INPUT);
|
||||
pinMode(I2C_SDA_PIN, INPUT);
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// بازیابی نرم I2C (از کد دوم)
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline void recoverI2CSoft() {
|
||||
Serial1.println("Attempting I2C recovery...");
|
||||
|
||||
// آزاد کردن خطوط
|
||||
pinMode(I2C_SDA_PIN, INPUT_PULLUP);
|
||||
pinMode(I2C_SCL_PIN, INPUT_PULLUP);
|
||||
delay(10);
|
||||
|
||||
// تولید پالسهای ساعت برای آزادسازی هر دستگاه قفل شده
|
||||
pinMode(I2C_SCL_PIN, OUTPUT);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
digitalWrite(I2C_SCL_PIN, LOW);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(I2C_SCL_PIN, HIGH);
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
|
||||
// ایجاد شرط STOP
|
||||
pinMode(I2C_SDA_PIN, OUTPUT);
|
||||
digitalWrite(I2C_SDA_PIN, LOW);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(I2C_SCL_PIN, HIGH);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(I2C_SDA_PIN, HIGH);
|
||||
delayMicroseconds(5);
|
||||
|
||||
// بازگشت به حالت عادی
|
||||
Wire.begin();
|
||||
|
||||
Serial1.println("I2C recovery completed");
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// راهاندازی مجدد سنسورهای I2C (منطق کد اول با توابع مستقیم)
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline void initI2CSensors() {
|
||||
i2cStatus.sht31OK = false;
|
||||
i2cStatus.bh1750OK = false;
|
||||
bh1750SoftReset();
|
||||
delay(10);
|
||||
// ─── SHT31 ───
|
||||
if (checkDevice(SHT31_ADDR)) {
|
||||
if (initSHT31Direct()) {
|
||||
Serial1.println("[I2C] SHT31 OK");
|
||||
}
|
||||
} else {
|
||||
Serial1.println("[I2C] SHT31 NOT FOUND");
|
||||
}
|
||||
|
||||
// ─── BH1750 ───
|
||||
if (checkDevice(BH1750_ADDR)) {
|
||||
if (initBH1750Direct()) {
|
||||
Serial1.println("[I2C] BH1750 OK");
|
||||
}
|
||||
} else {
|
||||
Serial1.println("[I2C] BH1750 NOT FOUND");
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// بازیابی کامل I2C (منطق کد اول با بازیابی نرم از کد دوم)
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline void recoverI2C() {
|
||||
uint32_t now = millis();
|
||||
|
||||
// جلوگیری از recovery مکرر
|
||||
if (now - i2cStatus.lastRecovery < RECOVERY_COOLDOWN) return;
|
||||
|
||||
i2cStatus.lastRecovery = now;
|
||||
i2cStatus.errorCount++;
|
||||
|
||||
if (i2cStatus.errorCount > MAX_ERROR_COUNT)
|
||||
i2cStatus.errorCount = 100;
|
||||
|
||||
Serial1.println("\n[RECOVERY] Starting I2C recovery...");
|
||||
|
||||
recoverI2CSoft();
|
||||
|
||||
Wire.end();
|
||||
delay(50);
|
||||
Wire.setSDA(I2C_SDA_PIN);
|
||||
Wire.setSCL(I2C_SCL_PIN);
|
||||
Wire.begin();
|
||||
Wire.setClock(100000); // 100kHz
|
||||
Wire.setTimeout(1000); // افزایش timeout برای جلوگیری از hang شدن
|
||||
delay(50);
|
||||
bh1750SoftReset();
|
||||
delay(20);
|
||||
|
||||
initI2CSensors();
|
||||
|
||||
Serial1.println("[RECOVERY] Complete\n");
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// بررسی سلامت سنسورها (منطق ترکیبی کد اول و دوم)
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline void healthCheck() {
|
||||
bool sht = checkDevice(SHT31_ADDR);
|
||||
bool bh = checkDevice(BH1750_ADDR);
|
||||
|
||||
// اگر هیچکدام پاسخ ندادند → recovery کامل
|
||||
if (!sht && !bh) {
|
||||
Serial1.println("[HEALTH] Both sensors failed, starting recovery...");
|
||||
recoverI2C();
|
||||
return;
|
||||
}
|
||||
|
||||
// منطق کد دوم: بررسی دورهای سلامت سنسورها
|
||||
bool shtWasOK = i2cStatus.sht31OK;
|
||||
bool bhWasOK = i2cStatus.bh1750OK;
|
||||
|
||||
// بررسی SHT31
|
||||
if (checkDevice(SHT31_ADDR)) {
|
||||
if (!shtWasOK) {
|
||||
Serial1.println("[HEALTH] SHT31 reappeared, reinitializing...");
|
||||
initSHT31Direct();
|
||||
}
|
||||
} else if (shtWasOK) {
|
||||
Serial1.println("[HEALTH] SHT31 disappeared!");
|
||||
i2cStatus.sht31OK = false;
|
||||
}
|
||||
|
||||
// بررسی BH1750
|
||||
if (checkDevice(BH1750_ADDR)) {
|
||||
if (!bhWasOK) {
|
||||
Serial1.println("[HEALTH] BH1750 reappeared, reinitializing...");
|
||||
initBH1750Direct();
|
||||
}
|
||||
} else if (bhWasOK) {
|
||||
Serial1.println("[HEALTH] BH1750 disappeared!");
|
||||
i2cStatus.bh1750OK = false;
|
||||
}
|
||||
|
||||
// اگر هر دو دستگاه از دست رفتهاند، بازیابی باس I2C
|
||||
if (!i2cStatus.bh1750OK && !i2cStatus.sht31OK) {
|
||||
recoverI2C();
|
||||
|
||||
// تلاش مجدد برای مقداردهی اولیه
|
||||
delay(100);
|
||||
initBH1750Direct();
|
||||
initSHT31Direct();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================== توابع MQ7 ================== */
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// کالیبراسیون MQ7
|
||||
// ──────────────────────────────────────────────────────
|
||||
|
||||
/*inline void calibrateMQ7() {
|
||||
if(currentData.volage < 1) return;
|
||||
|
||||
Serial1.println("======================================================================");
|
||||
Serial1.println("[MQ7] Final calibration with optimized parameters...");
|
||||
Serial1.print("VCC = ");
|
||||
Serial1.println(currentData.volage, 2);
|
||||
|
||||
// محاسبه پارامترها
|
||||
float correction_factor = V_AO_SENSOR / V_A2_MICRO; // 1.5
|
||||
float VDIV_RATIO = V_AO_SENSOR / currentData.volage; // ~0.045
|
||||
|
||||
// RL تنظیم شده برای رسیدن به R0 ≈ 3kΩ
|
||||
float optimized_RL = 1500.0; // از 790 به 1500 افزایش دادیم
|
||||
|
||||
float sumRS = 0;
|
||||
for(int i = 0; i < 50; i++) {
|
||||
int adc = analogRead(MQ7_PIN);
|
||||
|
||||
// تبدیل ADC به ولتاژ (فرض: مرجع ADC = VCC)
|
||||
float v_a2 = adc * (currentData.volage / 4095.0);
|
||||
|
||||
// تصحیح برای بدست آوردن ولتاژ واقعی AO سنسور
|
||||
float v_ao = v_a2 * correction_factor;
|
||||
|
||||
// اطمینان از محدوده منطقی
|
||||
if (v_ao > currentData.volage * 0.8) {
|
||||
v_ao = currentData.volage * 0.8;
|
||||
}
|
||||
if (v_ao < 0.01) v_ao = 0.01;
|
||||
|
||||
// محاسبه RS
|
||||
float RS = optimized_RL * (currentData.volage / v_ao - 1.0);
|
||||
sumRS += RS;
|
||||
delay(20);
|
||||
}
|
||||
|
||||
MQ7_R0 = (sumRS / 50.0) / 9.8;
|
||||
calibrationComplete = true;
|
||||
|
||||
Serial1.print("Optimized R0 = ");
|
||||
Serial1.print(MQ7_R0, 4);
|
||||
Serial1.println("Ω");
|
||||
|
||||
// ارزیابی نتیجه
|
||||
if (MQ7_R0 > 2000 && MQ7_R0 < 5000) {
|
||||
Serial1.println("✓ Excellent! R0 in perfect range (2-5kΩ)");
|
||||
} else if (MQ7_R0 > 1000 && MQ7_R0 < 10000) {
|
||||
Serial1.println("✓ Good! R0 in acceptable range (1-10kΩ)");
|
||||
} else {
|
||||
Serial1.println("⚠ May need further adjustment");
|
||||
}
|
||||
|
||||
// اطلاعات دیباگ
|
||||
Serial1.print("Parameters used - RL: ");
|
||||
Serial1.print(optimized_RL);
|
||||
Serial1.print("Ω, Correction: ");
|
||||
Serial1.print(correction_factor, 2);
|
||||
Serial1.print(", VDIV_RATIO: ");
|
||||
Serial1.println(VDIV_RATIO, 4);
|
||||
Serial1.println("======================================================================");
|
||||
}*/
|
||||
// inline void calibrateMQ7_() {
|
||||
// if(currentData.volage<1)
|
||||
// return;
|
||||
// Serial1.println("[MQ7] Starting calibration...");
|
||||
|
||||
// float sumRS = 0;
|
||||
// for(int i = 0; i < 50; i++) {
|
||||
// int adc = analogRead(MQ7_PIN);
|
||||
// float v_adc = adc * (currentData.volage / 4095.0);//5.0 -> currentData.volage
|
||||
// float v_ao = v_adc / VDIV_RATIO;
|
||||
|
||||
// if (v_ao < 0.01) v_ao = 0.01;
|
||||
// float RS = RL * (currentData.volage / v_ao - 1.0);//VCC -> currentData.volage
|
||||
// sumRS += RS;
|
||||
// delay(20);
|
||||
// }
|
||||
|
||||
// Serial1.print("currentData.volage In MQCalibrRead:");
|
||||
// Serial1.print(currentData.volage);
|
||||
|
||||
// MQ7_R0 = (sumRS / 50.0) / 9.8;
|
||||
// calibrationComplete = true;
|
||||
|
||||
// Serial1.print("======================================================================");
|
||||
// Serial1.print("[MQ7] Calibration complete. R0 = ");
|
||||
// Serial1.println(MQ7_R0, 4);
|
||||
// }
|
||||
//Serial1.print("======================================================================");
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// خواندن CO با میانگینگیری
|
||||
// ──────────────────────────────────────────────────────
|
||||
|
||||
// ============================ خواندن CO (با مقادیر ثابت) ============================
|
||||
// inline float readCOImproved__() {
|
||||
// // اگر سنسور هنوز گرم نشده، مقدار -1 برگردان
|
||||
// if (!isMQ7sensorPreheated()) {
|
||||
// return -1.0;
|
||||
// }
|
||||
|
||||
// // میانگینگیری برای کاهش نویز
|
||||
// float sumADC = 0;
|
||||
// for (int i = 0; i < 5; i++) {
|
||||
// sumADC += analogRead(MQ7_PIN);
|
||||
// delay(10);
|
||||
// }
|
||||
// int adc_avg = sumADC / 5.0;
|
||||
|
||||
// // تبدیل ADC به ولتاژ
|
||||
// float v_a2 = adc_avg * (currentData.volage / 4095.0);
|
||||
|
||||
// // تصحیح با فاکتور ثابت
|
||||
// float v_ao = v_a2 * CORRECTION_FACTOR_FIXED;
|
||||
|
||||
// // محدود کردن مقادیر غیرمنطقی
|
||||
// if (v_ao < 0.01) v_ao = 0.01;
|
||||
// if (v_ao > currentData.volage * 0.9) {
|
||||
// v_ao = currentData.volage * 0.9;
|
||||
// }
|
||||
|
||||
// // محاسبه مقاومت سنسور
|
||||
// float RS = RL_FIXED * (currentData.volage / v_ao - 1.0);
|
||||
|
||||
// // محاسبه نسبت
|
||||
// float ratio = RS / MQ7_R0;
|
||||
|
||||
// // فرمول CO برای MQ7
|
||||
// float ppm = 10.0 * pow(ratio, -1.53);
|
||||
|
||||
// // فیلتر نویز
|
||||
// if (ppm < 0.1) ppm = 0.0;
|
||||
// ppm = constrain(ppm, 0, 5000);
|
||||
|
||||
// // چاپ دیباگ (هر 30 ثانیه)
|
||||
// static unsigned long lastPrint = 0;
|
||||
// if (millis() - lastPrint > 30000) {
|
||||
// lastPrint = millis();
|
||||
// Serial1.print("[CO] ");
|
||||
// Serial1.print(ppm, 2);
|
||||
// Serial1.print(" ppm (ADC:");
|
||||
// Serial1.print(adc_avg);
|
||||
// Serial1.print(" V_ao:");
|
||||
// Serial1.print(v_ao, 3);
|
||||
// Serial1.println("V)");
|
||||
// }
|
||||
|
||||
// return ppm;
|
||||
// }
|
||||
bool CheckMQ7sensorPreheated() {
|
||||
if (MQ7sensorPreheated) return true;
|
||||
|
||||
unsigned long uptime = millis() - deviceStartTime;
|
||||
if (uptime >= PREHEAT_TIME_MS) {
|
||||
MQ7sensorPreheated = true;
|
||||
Serial1.println("[MQ7] Sensor preheated and ready");
|
||||
return true;
|
||||
}
|
||||
|
||||
int remaining = (PREHEAT_TIME_MS - uptime) / 60000; // به دقیقه
|
||||
if (remaining % 5 == 0) { // هر 5 دقیقه گزارش
|
||||
Serial1.print("[MQ7] Preheating... ");
|
||||
Serial1.print(remaining);
|
||||
Serial1.println(" minutes remaining");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
void calibrateMQ7() {
|
||||
Serial.println("[MQ7] Starting calibration in clean air...");
|
||||
deviceStartTime = millis();
|
||||
}
|
||||
float readSensorVoltage() {
|
||||
uint32_t sum = 0;
|
||||
for (int i = 0; i < NUM_SAMPLES; i++) {
|
||||
sum += analogRead(MQ7_PIN);
|
||||
delay(10);
|
||||
}
|
||||
float adcValue = sum / (float)NUM_SAMPLES;
|
||||
float vAdc = (adcValue / ADC_RESOLUTION) * VREF_ADC;
|
||||
// محاسبه ولتاژ خروجی سنسور با جبران تقسیم ولتاژ (R1 و R2)
|
||||
return vAdc * (R1 + R2) / R2;
|
||||
}
|
||||
|
||||
float calculateRs(float vOut) {
|
||||
if (vOut <= 0.0f) return 0.0f;
|
||||
return RL_SENSOR * (VCC_SENSOR / vOut - 1.0f);
|
||||
}
|
||||
|
||||
float calculatePPM(float rs) {
|
||||
float ratio = rs / MQ7_R0;
|
||||
if (ratio <= 0.0f) return 0.0f;
|
||||
return CO_A * pow(ratio, CO_B);
|
||||
}
|
||||
float readCOImproved() {
|
||||
if (!MQ7sensorPreheated)
|
||||
{
|
||||
CheckMQ7sensorPreheated();
|
||||
return -1.0f;
|
||||
}
|
||||
float vOut = readSensorVoltage();
|
||||
float rs = calculateRs(vOut);
|
||||
float ppm = calculatePPM(rs);
|
||||
|
||||
// محدود کردن به بازه معقول
|
||||
ppm = constrain(ppm, 0.0f, 5000.0f);
|
||||
return ppm;
|
||||
}
|
||||
|
||||
// inline float readCOImproved() {
|
||||
// // میانگینگیری برای کاهش نویز
|
||||
// Serial1.print("=======************===============================================================");
|
||||
// float sumADC = 0;
|
||||
// for (int i = 0; i < 10; i++) {
|
||||
// sumADC += analogRead(MQ7_PIN);
|
||||
// delay(2);
|
||||
// }
|
||||
|
||||
// int adc_avg = sumADC / 10.0;
|
||||
|
||||
// // تبدیل ADC به ولتاژ پین A2 (با فرض VCC به عنوان مرجع ADC)
|
||||
// float v_a2 = adc_avg * (currentData.volage / 4095.0);
|
||||
|
||||
// // تصحیح برای بدست آوردن ولتاژ واقعی AO سنسور (با دیود/مقاومت)
|
||||
// float v_ao = v_a2 * 1.5; // Correction Factor = 1.5
|
||||
|
||||
// // محدود کردن مقادیر غیرمنطقی
|
||||
// if (v_ao < 0.01) v_ao = 0.01;
|
||||
// if (v_ao > currentData.volage * 0.9) v_ao = currentData.volage * 0.9;
|
||||
|
||||
// // محاسبه مقاومت سنسور در گاز
|
||||
// float RS = 1500.0 * (currentData.volage / v_ao - 1.0); // RL = 1500Ω
|
||||
|
||||
// // اگر کالیبراسیون انجام نشده
|
||||
// if (!calibrationComplete || MQ7_R0 <= 0) {
|
||||
// return -1.0;
|
||||
// }
|
||||
|
||||
// // محاسبه نسبت
|
||||
// float ratio = RS / MQ7_R0;
|
||||
|
||||
// // دیباگ اطلاعات
|
||||
// Serial1.print("[MQ7] ADC:");
|
||||
// Serial1.print(adc_avg);
|
||||
// Serial1.print(" v_a2:");
|
||||
// Serial1.print(v_a2, 4);
|
||||
// Serial1.print("V v_ao:");
|
||||
// Serial1.print(v_ao, 4);
|
||||
// Serial1.print("V RS:");
|
||||
// Serial1.print(RS, 4);
|
||||
// Serial1.print("Ω ratio:");
|
||||
// Serial1.print(ratio, 4);
|
||||
|
||||
// // محاسبه ppm CO بر اساس دیتاشیت MQ7
|
||||
// // فرمول: ppm = A * (RS/R0)^B
|
||||
// // برای MQ7 و CO: A ≈ 10, B ≈ -1.53
|
||||
// float ppm = 10.0 * pow(ratio, -1.53);
|
||||
|
||||
// // محدود کردن بازه خروجی
|
||||
// ppm = constrain(ppm, 0, 5000);
|
||||
|
||||
// Serial1.print(" PPM:");
|
||||
// Serial1.println(ppm, 4);
|
||||
|
||||
// return ppm;
|
||||
// }
|
||||
|
||||
|
||||
/* ================== خواندن سنسورها (با توابع مستقیم از کد دوم) ================== */
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// خواندن تمام سنسورها با توابع مستقیم
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline void readSensors() {
|
||||
bool success = false;
|
||||
|
||||
Serial1.println("\n=== Reading Sensors ===");
|
||||
|
||||
// ──── 1. خواندن SHT31 با تابع مستقیم ────
|
||||
float temp, hum;
|
||||
if (readSHT31Direct(temp, hum)) {
|
||||
currentData.temperature = temp;
|
||||
currentData.humidity = hum;
|
||||
|
||||
Serial1.print("[SHT31] T=");
|
||||
Serial1.print(temp, 1);
|
||||
Serial1.print("°C H=");
|
||||
Serial1.print(hum, 1);
|
||||
Serial1.println("%");
|
||||
|
||||
success = true;
|
||||
} else {
|
||||
// استفاده از آخرین مقدار موفق در صورت خطا
|
||||
if (lastTemperature != 0 || lastHumidity != 0) {
|
||||
currentData.temperature = lastTemperature;
|
||||
currentData.humidity = lastHumidity;
|
||||
Serial1.print("[SHT31] Using last values - T=");
|
||||
Serial1.print(lastTemperature, 1);
|
||||
Serial1.print("°C H=");
|
||||
Serial1.print(lastHumidity, 1);
|
||||
Serial1.println("%");
|
||||
} else {
|
||||
Serial1.println("[SHT31] Read error");
|
||||
currentData.temperature = NAN;
|
||||
currentData.humidity = NAN;
|
||||
}
|
||||
}
|
||||
|
||||
// ──── 2. خواندن BH1750 با تابع مستقیم ────
|
||||
float lux;
|
||||
if (readBH1750Direct(lux)) {
|
||||
currentData.lightLux = lux;
|
||||
|
||||
Serial1.print("[BH1750] ");
|
||||
Serial1.print(lux, 0);
|
||||
Serial1.println(" lux");
|
||||
|
||||
success = true;
|
||||
} else {
|
||||
// استفاده از آخرین مقدار موفق در صورت خطا
|
||||
if (lastLightLevel != 0) {
|
||||
currentData.lightLux = lastLightLevel;
|
||||
Serial1.print("[BH1750] Using last value: ");
|
||||
Serial1.print(lastLightLevel, 0);
|
||||
Serial1.println(" lux");
|
||||
} else {
|
||||
Serial1.println("[BH1750] Read error");
|
||||
currentData.lightLux = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ──── 3. کالیبراسیون خودکار MQ7 ────
|
||||
/*if (!calibrationComplete){// && (millis() - systemStartTime >= calibrationPeriod)) {
|
||||
calibrateMQ7();
|
||||
}*/
|
||||
|
||||
// ──── 4. خواندن 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");
|
||||
|
||||
// ──── 5. محاسبه درصدها ────
|
||||
calculatePercentages(currentData);
|
||||
|
||||
// ──── 6. ثبت زمان آخرین موفقیت ────
|
||||
if (success) {
|
||||
i2cStatus.lastSuccess = millis();
|
||||
}
|
||||
|
||||
lastSensorRead = millis();
|
||||
Serial1.println("=== Reading Complete ===\n");
|
||||
}
|
||||
|
||||
/* ================== راهاندازی اولیه ================== */
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// مقداردهی کامل سیستم
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline void initSensors() {
|
||||
delay(2000);
|
||||
Serial1.println("\n=== Initializing Sensor System ===");
|
||||
|
||||
// ──── پاکسازی و راهاندازی I2C ────
|
||||
cleanI2CBus();
|
||||
Wire.setSDA(I2C_SDA_PIN);
|
||||
Wire.setSCL(I2C_SCL_PIN);
|
||||
Wire.begin();
|
||||
Wire.setClock(100000); // 100kHz برای پایداری
|
||||
Wire.setTimeout(1000); // افزایش timeout برای جلوگیری از hang شدن
|
||||
delay(100);
|
||||
bh1750SoftReset();
|
||||
delay(20);
|
||||
// ──── راهاندازی سنسورهای I2C ────
|
||||
initI2CSensors();
|
||||
|
||||
// ──── راهاندازی MQ7 ────
|
||||
pinMode(MQ7_PIN, INPUT);
|
||||
analogReadResolution(12);
|
||||
Serial1.println("[MQ7] Analog pin configured");
|
||||
|
||||
// ──── اسکن I2C (اختیاری - برای debug) ────
|
||||
Serial1.println("\n[I2C] Scanning bus...");
|
||||
byte deviceCount = 0;
|
||||
for(byte addr = 1; addr < 127; addr++) {
|
||||
Wire.beginTransmission(addr);
|
||||
if (Wire.endTransmission() == 0) {
|
||||
Serial1.print(" Device found at 0x");
|
||||
if (addr < 16) Serial1.print("0");
|
||||
Serial1.println(addr, HEX);
|
||||
deviceCount++;
|
||||
}
|
||||
}
|
||||
Serial1.print("Total devices: ");
|
||||
Serial1.println(deviceCount);
|
||||
|
||||
Serial1.println("\n=== System Ready ===\n");
|
||||
}
|
||||
|
||||
/* ================== حلقه اصلی (جایگزین loop) ================== */
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// باید در loop() اصلی فراخوانی شود
|
||||
// ──────────────────────────────────────────────────────
|
||||
inline void updateSensors() {
|
||||
static uint32_t lastRead = 0;
|
||||
static uint32_t lastHealth = 0;
|
||||
|
||||
uint32_t now = millis();
|
||||
|
||||
// جلوگیری از overflow
|
||||
if (now < lastRead) lastRead = 0;
|
||||
if (now < lastHealth) lastHealth = 0;
|
||||
|
||||
// ──── خواندن دورهای سنسورها ────
|
||||
if (now - lastRead >= READ_INTERVAL) {
|
||||
lastRead = now;
|
||||
readSensors();
|
||||
}
|
||||
|
||||
// ──── بررسی سلامت دورهای (هر 30 ثانیه) ────
|
||||
if (now - lastHealth >= HEALTH_CHECK_INTERVAL) {
|
||||
lastHealth = now;
|
||||
healthCheck();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SENSORS_H
|
||||
Reference in New Issue
Block a user