#include #include #include "Voltage_Reader.h" // تنظیمات OLED #define I2C_SDA_PIN PB9 #define I2C_SCL_PIN PB8 U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // ========== پارامترهای مدار MQ7 (مقادیر دقیق اندازه‌گیری‌شده) ========== #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 ADC_PIN PA2 // پین ADC #define NUM_SAMPLES 10 // تعداد نمونه برای میانگین‌گیری // پارامترهای سنسور MQ7 برای تبدیل به ppm (از دیتاشیت) #define CO_A 1.9f // ضریب A #define CO_B -0.6f // ضریب B // ============================ متغیرهای سراسری ============================ // متغیرهای جهانی float VCC_SENSOR = 4.9f; // ولتاژ تغذیه سنسور MQ7 float MQ7_R0 = 21000.0; // مقدار R0 (پس از کالیبراسیون) – تقریب اولیه ۲۰ کیلواهم bool calibrationComplete = false; unsigned long lastReadTime = 0; const unsigned long readInterval = 3000; float volage; float readSensorVoltage() { uint32_t sum = 0; for (int i = 0; i < NUM_SAMPLES; i++) { sum += analogRead(ADC_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); } // ========== کالیبراسیون MQ7 ========== void calibrateMQ7() { Serial1.println("Starting calibration in clean air..."); u8g2.clearBuffer(); u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.drawStr(0, 30, "Calibrating ..."); u8g2.drawStr(0, 50, "Wait 120 seconds"); u8g2.sendBuffer(); // صبر برای پایدار شدن سنسور (توصیه: حداقل ۲ دقیقه، ولی برای نمونه ۳۰ ثانیه) delay(120000); float sumRs = 0; const int samples = 50; for (int i = 0; i < samples; i++) { float vOut = readSensorVoltage(); float rs = calculateRs(vOut); sumRs += rs; delay(20); } //////////MQ7_R0 = sumRs / samples; // در هوای پاک R0 = Rs calibrationComplete = true; Serial1.print("[MQ7] Calibration complete. R0 = "); Serial1.println(MQ7_R0, 1); Serial1.println("You can update the #define R0 in code with this value for future use."); } // ========== خواندن CO با استفاده از پارامترهای جدید ========== float readCO() { if (!calibrationComplete) return -1.0f; float vOut = readSensorVoltage(); float rs = calculateRs(vOut); float ppm = calculatePPM(rs); // محدود کردن به بازه معقول ppm = constrain(ppm, 0.0f, 5000.0f); return ppm; } // نمایش روی OLED void displayCO(int ppm) { if(ppm<0) return; u8g2.clearBuffer(); // انتخاب فونت بر اساس اندازه عدد if (ppm < 1000) { // برای اعداد تا ۳ رقمی از فونت 35 پیکسل u8g2.setFont(u8g2_font_fub35_tr); // موقعیت مرکزی if (ppm < 10) { u8g2.setCursor(50, 55); } else if (ppm < 100) { u8g2.setCursor(25, 55); } else { u8g2.setCursor(10, 55); } } else { // برای اعداد ۴ رقمی از فونت 25 پیکسل u8g2.setFont(u8g2_font_fub25_tr); u8g2.setCursor(10, 60); } u8g2.print(ppm); // نمایش واحد ppm در پایین u8g2.setFont(u8g2_font_ncenB12_tr); u8g2.setCursor(90, 60); u8g2.print("ppm"); u8g2.sendBuffer(); } void setup() { Serial1.begin(115200); delay(2000); // تنظیم پین I2C Wire.setSDA(I2C_SDA_PIN); Wire.setSCL(I2C_SCL_PIN); Wire.begin(); // راه‌اندازی OLED u8g2.begin(); u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.clearBuffer(); u8g2.drawStr(0, 35, "Sensor Calibrating..."); u8g2.sendBuffer(); analogReadResolution(12); bool voltageOK = voltageReader.testCircuit(); if (!voltageOK) { Serial1.println("⚠️ Voltage issue detected!"); } // 2. اطلاعات دیباگ ولتاژ voltageReader.debugInfo(); volage=voltageReader.readVoltage(); VCC_SENSOR=volage; // کالیبراسیون اولیه سنسور calibrateMQ7(); // نمایش پیام راه‌اندازی /*u8g2.clearBuffer(); u8g2.drawStr(0, 40, "MQ-7 Ready!"); u8g2.drawStr(0, 60, "Monitoring CO..."); u8g2.sendBuffer();*/ delay(2000); } void loop() { if (millis() - lastReadTime >= readInterval) { volage=voltageReader.readVoltage(); VCC_SENSOR=volage; float ppm = readCO(); int ppm_rounded = round(ppm); displayCO(ppm_rounded); //voltageReader.debugInfo(); // نمایش در سریال مانیتور (اختیاری) Serial1.print("CO Concentration: "); Serial1.print(ppm); Serial1.println(" ppm"); Serial1.print(" VCC_SENSOR:"); Serial1.println(VCC_SENSOR); lastReadTime = millis(); } delay(1000); }