197 lines
5.5 KiB
C++
197 lines
5.5 KiB
C++
#include <U8g2lib.h>
|
||
#include <Wire.h>
|
||
#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);
|
||
} |