backup 14041130
This commit is contained in:
433
14041130/I2C-best/I2C-best.ino
Normal file
433
14041130/I2C-best/I2C-best.ino
Normal file
@@ -0,0 +1,433 @@
|
||||
#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);
|
||||
}
|
||||
197
14041130/MQ7-1/MQ7-1.ino
Normal file
197
14041130/MQ7-1/MQ7-1.ino
Normal file
@@ -0,0 +1,197 @@
|
||||
#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);
|
||||
}
|
||||
148
14041130/MQ7-1/Voltage_Reader.h
Normal file
148
14041130/MQ7-1/Voltage_Reader.h
Normal file
@@ -0,0 +1,148 @@
|
||||
#ifndef VOLTAGE_READER_H
|
||||
#define VOLTAGE_READER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define VOLTAGE_DIVIDER_PIN PA0 // پین خواندن ولتاژ
|
||||
#define BATTERY_VOLTAGE_PIN_A3 PA3 // پین جدید برای باتری
|
||||
#define VOLTAGE_DIVIDER_RATIO 2.0 // نسبت تقسیم (R1=R2=10k => نسبت = 2)
|
||||
#define ADC_REF_VOLTAGE 3.3 // ولتاژ مرجع ADC در STM32 (معمولاً 3.3V)
|
||||
#define ADC_RESOLUTION 4096 // رزولوشن ADC 12-bit = 4096
|
||||
|
||||
|
||||
class VoltageReader {
|
||||
private:
|
||||
float filteredVoltage = 0.0;
|
||||
bool firstReading = true; // فلگ برای اولین خواندن
|
||||
const float alpha = 0.3; // ضریب فیلتر را کمی بیشتر کردم
|
||||
|
||||
public:
|
||||
VoltageReader() {
|
||||
init();
|
||||
}
|
||||
|
||||
void init() {
|
||||
pinMode(VOLTAGE_DIVIDER_PIN, INPUT_ANALOG);
|
||||
analogReadResolution(12); // تنظیم رزولوشن ADC به 12-bit
|
||||
delay(100); // کمی بیشتر صبر کن
|
||||
|
||||
// چند بار خواندن برای تخلیه خازنهای داخلی
|
||||
for (int i = 0; i < 10; i++) {
|
||||
analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
// خواندن ولتاژ بدون فیلتر
|
||||
float readRawVoltage() {
|
||||
int samples = 32; // تعداد نمونهها را بیشتر کردم
|
||||
long sum = 0;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
sum += analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
delayMicroseconds(20);
|
||||
}
|
||||
|
||||
int rawValue = sum / samples;
|
||||
|
||||
// تبدیل به ولتاژ
|
||||
float voltageAtPin = (rawValue * ADC_REF_VOLTAGE) / ADC_RESOLUTION;
|
||||
|
||||
// محاسبه ولتاژ اصلی
|
||||
float actualVoltage = voltageAtPin * VOLTAGE_DIVIDER_RATIO;
|
||||
|
||||
return actualVoltage;
|
||||
}
|
||||
|
||||
// خواندن با فیلتر
|
||||
float readVoltage() {
|
||||
float currentVoltage = readRawVoltage();
|
||||
|
||||
// اگر اولین بار است، فیلتر را با مقدار فعلی مقداردهی کن
|
||||
if (firstReading) {
|
||||
filteredVoltage = currentVoltage;
|
||||
firstReading = false;
|
||||
} else {
|
||||
// اعمال فیلتر Low-pass
|
||||
filteredVoltage = (alpha * currentVoltage) + ((1 - alpha) * filteredVoltage);
|
||||
}
|
||||
|
||||
return currentVoltage; // actual voltage برمیگردانیم
|
||||
}
|
||||
|
||||
// دریافت ولتاژ فیلتر شده
|
||||
float getFilteredVoltage() {
|
||||
return filteredVoltage;
|
||||
}
|
||||
|
||||
// تست سلامت مدار
|
||||
bool testCircuit() {
|
||||
Serial1.println("\n🔌 Testing voltage divider circuit...");
|
||||
|
||||
// چند بار خواندن برای اطمینان
|
||||
float sum = 0;
|
||||
int readings = 10;
|
||||
|
||||
for (int i = 0; i < readings; i++) {
|
||||
sum += readRawVoltage();
|
||||
delay(50);
|
||||
}
|
||||
|
||||
float avgVoltage = sum / readings;
|
||||
|
||||
Serial1.print("Average voltage: ");
|
||||
Serial1.print(avgVoltage, 2);
|
||||
Serial1.println("V");
|
||||
|
||||
Serial1.print("Raw ADC value: ");
|
||||
Serial1.println(analogRead(VOLTAGE_DIVIDER_PIN));
|
||||
|
||||
// ولتاژ در پین
|
||||
float pinVoltage = avgVoltage / VOLTAGE_DIVIDER_RATIO;
|
||||
Serial1.print("Voltage at PA0 pin: ");
|
||||
Serial1.print(pinVoltage, 2);
|
||||
Serial1.println("V");
|
||||
|
||||
if (avgVoltage > 4.5 && avgVoltage < 5.5) {
|
||||
Serial1.println("✅ Circuit OK (within expected 5V ±10%)");
|
||||
return true;
|
||||
} else {
|
||||
Serial1.print("❌ Expected ~5V, got ");
|
||||
Serial1.print(avgVoltage, 2);
|
||||
Serial1.println("V");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// نمایش اطلاعات دیباگ
|
||||
void debugInfo() {
|
||||
float rawVoltage = readRawVoltage();
|
||||
int rawADC = analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
float pinVoltage = rawVoltage / VOLTAGE_DIVIDER_RATIO;
|
||||
|
||||
Serial1.println("\n📊 Voltage Debug Info:");
|
||||
Serial1.print("Raw ADC value: ");
|
||||
Serial1.println(rawADC);
|
||||
Serial1.print("Voltage at PA0 pin: ");
|
||||
Serial1.print(pinVoltage, 3);
|
||||
Serial1.println("V");
|
||||
Serial1.print("Actual voltage (raw): ");
|
||||
Serial1.print(rawVoltage, 3);
|
||||
Serial1.println("V");
|
||||
Serial1.print("Filtered voltage: ");
|
||||
Serial1.print(filteredVoltage, 3);
|
||||
Serial1.println("V");
|
||||
}
|
||||
|
||||
// ریست فیلتر
|
||||
void resetFilter() {
|
||||
filteredVoltage = 0.0;
|
||||
firstReading = true;
|
||||
Serial1.println("✅ Voltage filter reset");
|
||||
}
|
||||
};
|
||||
|
||||
// ایجاد نمونه سراسری
|
||||
VoltageReader voltageReader;
|
||||
|
||||
#endif // VOLTAGE_READER_H
|
||||
98
14041130/TestLCD/BatteryReader.h
Normal file
98
14041130/TestLCD/BatteryReader.h
Normal file
@@ -0,0 +1,98 @@
|
||||
// BatteryReader.h
|
||||
#ifndef BATTERY_READER_H
|
||||
#define BATTERY_READER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Config.h"
|
||||
|
||||
class BatteryReader {
|
||||
private:
|
||||
uint8_t batteryPin;
|
||||
float filteredVoltage = 0.0;
|
||||
bool firstReading = true;
|
||||
const float alpha = 0.3;
|
||||
|
||||
// پارامترهای مخصوص باتری لیتیومی
|
||||
const float BATTERY_RATIO = (10000.0 + 10000.0) / 10000.0; // اگر مقسم ولتاژ مشابه است
|
||||
const float BATTERY_FULL_VOLTAGE = 4.2; // ولتاژ کامل باتری لیتیومی
|
||||
const float BATTERY_EMPTY_VOLTAGE = 3.0; // ولتاژ خالی
|
||||
|
||||
public:
|
||||
BatteryReader(uint8_t pin) : batteryPin(pin) {
|
||||
init();
|
||||
}
|
||||
|
||||
void init() {
|
||||
pinMode(batteryPin, INPUT_ANALOG);
|
||||
analogReadResolution(12);
|
||||
delay(50);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
analogRead(batteryPin);
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
float readRawVoltage() {
|
||||
int samples = 32;
|
||||
long sum = 0;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
sum += analogRead(batteryPin);
|
||||
delayMicroseconds(20);
|
||||
}
|
||||
|
||||
int rawValue = sum / samples;
|
||||
float voltageAtPin = (rawValue * ADC_REF_VOLTAGE) / ADC_RESOLUTION;
|
||||
float batteryVoltage = voltageAtPin * BATTERY_RATIO;
|
||||
|
||||
return batteryVoltage;
|
||||
}
|
||||
|
||||
float readVoltage() {
|
||||
float currentVoltage = readRawVoltage();
|
||||
|
||||
if (firstReading) {
|
||||
filteredVoltage = currentVoltage;
|
||||
firstReading = false;
|
||||
} else {
|
||||
filteredVoltage = (alpha * currentVoltage) + ((1 - alpha) * filteredVoltage);
|
||||
}
|
||||
|
||||
return currentVoltage;
|
||||
}
|
||||
|
||||
// محاسبه درصد شارژ باتری
|
||||
float getBatteryPercentage() {
|
||||
float voltage = readVoltage();
|
||||
// محدود کردن ولتاژ به محدوده تعریف شده
|
||||
voltage = constrain(voltage, BATTERY_EMPTY_VOLTAGE, BATTERY_FULL_VOLTAGE);
|
||||
|
||||
// محاسبه درصد
|
||||
float percentage = ((voltage - BATTERY_EMPTY_VOLTAGE) /
|
||||
(BATTERY_FULL_VOLTAGE - BATTERY_EMPTY_VOLTAGE)) * 100.0;
|
||||
|
||||
return constrain(percentage, 0, 100);
|
||||
}
|
||||
|
||||
void debugInfo() {
|
||||
float rawVoltage = readRawVoltage();
|
||||
int rawADC = analogRead(batteryPin);
|
||||
float pinVoltage = rawVoltage / BATTERY_RATIO;
|
||||
|
||||
Serial1.println("\n🔋 Battery Debug Info:");
|
||||
Serial1.print("Raw ADC value: ");
|
||||
Serial1.println(rawADC);
|
||||
Serial1.print("Voltage at pin: ");
|
||||
Serial1.print(pinVoltage, 3);
|
||||
Serial1.println("V");
|
||||
Serial1.print("Battery voltage: ");
|
||||
Serial1.print(rawVoltage, 3);
|
||||
Serial1.println("V");
|
||||
Serial1.print("Battery percentage: ");
|
||||
Serial1.print(getBatteryPercentage(), 1);
|
||||
Serial1.println("%");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
157
14041130/TestLCD/Config.h
Normal file
157
14041130/TestLCD/Config.h
Normal file
@@ -0,0 +1,157 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define I2C_SDA_PIN PB9
|
||||
#define I2C_SCL_PIN PB8
|
||||
|
||||
#define SHT31_ADDRESS 0x44
|
||||
#define BH1750_ADDRESS 0x23
|
||||
|
||||
// ========== تنظیمات Timing (از کد اول) ==========
|
||||
#define READ_INTERVAL 2000UL // ms - خواندن سنسورها
|
||||
#define HEALTH_CHECK_INTERVAL 30000UL // ms - بررسی سلامت
|
||||
#define RECOVERY_COOLDOWN 5000UL // ms - فاصله بین recoveryها
|
||||
#define MAX_ERROR_COUNT 1000 // حداکثر خطاهای ثبتشده
|
||||
|
||||
unsigned long lastBh1750Success = 0;
|
||||
unsigned long lastSht31Success = 0;
|
||||
|
||||
uint8_t bh1750ErrorCount = 0;
|
||||
uint8_t sht31ErrorCount = 0;
|
||||
const uint8_t MAX_ERRORS = 5;
|
||||
|
||||
float lastLightLevel = 0.0;
|
||||
float lastTemperature = 0.0;
|
||||
float lastHumidity = 0.0;
|
||||
|
||||
|
||||
// -------------------- پیکربندی --------------------
|
||||
#define FLASH_CS PB12
|
||||
#define FLASH_MOSI PB15
|
||||
#define FLASH_MISO PB14
|
||||
#define FLASH_SCK PB13
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
|
||||
//#define MQ7_PIN PA2
|
||||
//#define VCC 4.63
|
||||
#define RL 790.0 //10000.0
|
||||
//#define VDIV_RATIO 0.03017 //0.681
|
||||
|
||||
//#define SDA_PIN PB9
|
||||
//#define SCL_PIN PB8
|
||||
#define PWRKEY_PIN PB5
|
||||
#define SENSOR_READ_INTERVAL 5000
|
||||
|
||||
#define POWER_PIN PA1
|
||||
|
||||
#define TFT_WIDTH 240
|
||||
#define TFT_HEIGHT 240
|
||||
// #define TFT_CS PB0 // تغییر به پینهای شما
|
||||
// #define TFT_DC PA4
|
||||
// #define TFT_RST PA6
|
||||
// #define TFT_BL PB1
|
||||
|
||||
#define VOLTAGE_DIVIDER_PIN PA0 // پین خواندن ولتاژ
|
||||
#define BATTERY_VOLTAGE_PIN_A3 PA3 // پین جدید برای باتری
|
||||
#define VOLTAGE_DIVIDER_RATIO 2.0 // نسبت تقسیم (R1=R2=10k => نسبت = 2)
|
||||
#define ADC_REF_VOLTAGE 3.3 // ولتاژ مرجع ADC در STM32 (معمولاً 3.3V)
|
||||
#define ADC_RESOLUTION 4096 // رزولوشن ADC 12-bit = 4096
|
||||
|
||||
// -------------------- آدرسهای حافظه --------------------
|
||||
#define CONFIG_ADDRESS 0x000000
|
||||
#define DATA_ADDRESS 0x010000
|
||||
|
||||
// -------------------- آدرس حافظه داخلی STM32 --------------------
|
||||
#define INTERNAL_CONFIG_ADDR 0x8007800 // آخرین صفحه فلش در STM32F103C8
|
||||
|
||||
// -------------------- انومها --------------------
|
||||
enum SIMType { SIM_UNKNOWN = 0, SIM_HAMRAHE_AVAL = 1, SIM_IRANCELL = 2, SIM_RIGHTEL = 3 };
|
||||
|
||||
// -------------------- ساختارها --------------------
|
||||
struct DeviceConfig {
|
||||
char signature[4];
|
||||
char deviceId[16];
|
||||
char serverPhoneNumber[16];
|
||||
char serverUrl[64];
|
||||
unsigned long uploadInterval;
|
||||
unsigned long smsInterval;
|
||||
unsigned long saveInterval;
|
||||
SIMType simType;
|
||||
bool smsEnabled;
|
||||
bool verified;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
struct SensorData {
|
||||
float temperature;
|
||||
float humidity;
|
||||
float coPPM;
|
||||
float lightLux;
|
||||
unsigned long timestamp;
|
||||
uint8_t sent;
|
||||
float volage;
|
||||
int power;
|
||||
int oldPower;
|
||||
float batteryVoltage;
|
||||
float batteryPercent;
|
||||
|
||||
// اضافه شدن برای نمایشگر
|
||||
float tempPercent; // درصد دما (0-100)
|
||||
float humPercent; // درصد رطوبت (0-100)
|
||||
float lightPercent; // درصد نور (0-100)
|
||||
float gasPercent; // درصد گاز (0-100)
|
||||
};
|
||||
|
||||
// -------------------- توابع کمکی --------------------
|
||||
inline String simTypeToString(SIMType type) {
|
||||
switch(type) {
|
||||
case SIM_HAMRAHE_AVAL: return "Hamrah Aval";
|
||||
case SIM_IRANCELL: return "Irancell";
|
||||
case SIM_RIGHTEL: return "Rightel";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
inline String simTypeToAPN(SIMType type) {
|
||||
switch(type) {
|
||||
case SIM_HAMRAHE_AVAL: return "mcinet";
|
||||
case SIM_IRANCELL: return "mtnirancell";
|
||||
case SIM_RIGHTEL: return "rightel";
|
||||
default: return "mcinet";
|
||||
}
|
||||
}
|
||||
|
||||
inline String generateVerificationCode(String tokenCode) {
|
||||
long token = tokenCode.toInt();
|
||||
long verification = (token * 7 + 12345) % 100000;
|
||||
char buffer[6];
|
||||
sprintf(buffer, "%05ld", verification);
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
inline void calculatePercentages(SensorData& data) {
|
||||
// دما: فرض 0-50 درجه سانتیگراد
|
||||
data.tempPercent = (data.temperature * 100) / 50.0;
|
||||
if (data.tempPercent > 100) data.tempPercent = 100;
|
||||
if (data.tempPercent < 0) data.tempPercent = 0;
|
||||
|
||||
// رطوبت: 0-100%
|
||||
data.humPercent = data.humidity;
|
||||
if (data.humPercent > 100) data.humPercent = 100;
|
||||
if (data.humPercent < 0) data.humPercent = 0;
|
||||
|
||||
// نور: فرض 0-10000 لوکس
|
||||
data.lightPercent = (data.lightLux * 100) / 10000.0;
|
||||
if (data.lightPercent > 100) data.lightPercent = 100;
|
||||
if (data.lightPercent < 0) data.lightPercent = 0;
|
||||
|
||||
// گاز: فرض 0-200 ppm (خطای تایپی تصحیح شد)
|
||||
data.gasPercent = (data.coPPM * 100) / 200.0;
|
||||
if (data.gasPercent > 100) data.gasPercent = 100;
|
||||
if (data.gasPercent < 0) data.gasPercent = 0;
|
||||
}
|
||||
|
||||
#endif // CONFIG_H
|
||||
342
14041130/TestLCD/Display - Copy__old
Normal file
342
14041130/TestLCD/Display - Copy__old
Normal file
@@ -0,0 +1,342 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Fonts/FreeSans9pt7b.h>
|
||||
#include <Fonts/FreeSansBold12pt7b.h>
|
||||
#include <Fonts/FreeSansBold18pt7b.h>
|
||||
#include "Config.h"
|
||||
|
||||
// -------------------- متغیرهای خارجی --------------------
|
||||
extern Adafruit_SSD1306 display;
|
||||
extern DeviceConfig config;
|
||||
extern SensorData currentData;
|
||||
extern bool sht31Connected;
|
||||
extern bool lightSensorConnected;
|
||||
extern bool coSensorConnected;
|
||||
extern bool calibrationComplete;
|
||||
extern bool awaitingSMS2;
|
||||
extern int signalStrength;
|
||||
extern String lastMessage;
|
||||
extern int displayMode;
|
||||
extern unsigned long lastDisplayChange;
|
||||
extern unsigned long lastNetworkStatusUpdate;
|
||||
|
||||
// Forward declaration
|
||||
void updateNetworkStatus();
|
||||
|
||||
// -------------------- توابع نمایشگر --------------------
|
||||
inline void displayAllParameters() {
|
||||
display.clearDisplay();
|
||||
//display.setTextColor(SSD1306_WHITE);
|
||||
|
||||
// عنوان با فونت زیبا
|
||||
display.setFont();
|
||||
display.setCursor(0, 4);
|
||||
if(currentData.power==1)
|
||||
display.print("P:");
|
||||
else
|
||||
display.print("B:");
|
||||
|
||||
display.setCursor(15, 4);
|
||||
display.print(String(currentData.volage, 1));
|
||||
|
||||
display.setCursor(45, 4);
|
||||
display.print("VB:");
|
||||
display.setCursor(65, 4);
|
||||
display.print(String(currentData.batteryVoltage, 2));
|
||||
display.setCursor(97, 4);
|
||||
display.print("D:");
|
||||
display.setCursor(107, 4);
|
||||
display.print(String(currentData.batteryPercent,0)+"%");
|
||||
|
||||
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
// خط جداکننده
|
||||
display.drawLine(0, 15, 128, 15, SSD1306_WHITE);
|
||||
|
||||
// ارتفاع 12-14
|
||||
// دما
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(1, 30);
|
||||
display.print("T:");//16 پیکسل
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(18, 30);
|
||||
display.print(currentData.temperature, 1);//34 پیکسل
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
//display.setCursor(55, 30);
|
||||
//display.print("-");//3 پیکسل
|
||||
|
||||
// رطوبت
|
||||
display.setCursor(65, 30);
|
||||
display.print("H:");//16 پیکسل
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(83, 30);
|
||||
display.print(currentData.humidity, 0);//34 پیکسل
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(110, 31);
|
||||
display.print("%");
|
||||
|
||||
// نور
|
||||
display.setCursor(1, 55);
|
||||
display.print("L:");//15 پیکسل
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(20, 55);
|
||||
display.print((int)currentData.lightLux);//40 پیکسل
|
||||
|
||||
//گاز
|
||||
display.setCursor(70, 55);
|
||||
display.print("G:");//15 پیکسل
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(88, 55);
|
||||
display.print((int)currentData.coPPM);//40 پیکسل
|
||||
|
||||
// برگشت به فونت پیشفرض
|
||||
display.setFont();
|
||||
display.display();
|
||||
}
|
||||
|
||||
inline void displayTemperature() {
|
||||
display.clearDisplay();
|
||||
|
||||
// عنوان
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(18, 14);
|
||||
display.print("Temperature");
|
||||
|
||||
// خط جداکننده
|
||||
display.drawLine(0, 18, 128, 18, SSD1306_WHITE);
|
||||
|
||||
// مقدار دما - عدد بزرگ و نرم
|
||||
display.setFont(&FreeSansBold18pt7b);
|
||||
display.setCursor(10, 50);
|
||||
display.print(currentData.temperature, 1);
|
||||
|
||||
// واحد
|
||||
display.setFont(&FreeSansBold12pt7b);
|
||||
display.setCursor(90, 45);
|
||||
display.print("C");
|
||||
|
||||
// علامت درجه
|
||||
display.drawCircle(85, 30, 3, SSD1306_WHITE);
|
||||
|
||||
// وضعیت سنسور
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(50, 63);
|
||||
if (!sht31Connected) {
|
||||
display.print("ERR");
|
||||
}
|
||||
|
||||
display.setFont();
|
||||
display.display();
|
||||
}
|
||||
|
||||
inline void displayHumidity() {
|
||||
display.clearDisplay();
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
|
||||
// عنوان
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(30, 14);
|
||||
display.print("Humidity");
|
||||
|
||||
// خط جداکننده
|
||||
display.drawLine(0, 18, 128, 18, SSD1306_WHITE);
|
||||
|
||||
// مقدار رطوبت - عدد بزرگ و نرم
|
||||
display.setFont(&FreeSansBold18pt7b);
|
||||
display.setCursor(25, 50);
|
||||
display.print(currentData.humidity, 0);
|
||||
|
||||
// واحد درصد
|
||||
display.setFont(&FreeSansBold12pt7b);
|
||||
display.setCursor(75, 48);
|
||||
display.print("%");
|
||||
|
||||
// وضعیت سنسور
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(50, 63);
|
||||
if (!sht31Connected) {
|
||||
display.print("ERR");
|
||||
}
|
||||
|
||||
display.setFont();
|
||||
display.display();
|
||||
}
|
||||
|
||||
inline void displayCO() {
|
||||
display.clearDisplay();
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
|
||||
// عنوان
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(35, 14);
|
||||
display.print("CO Gas");
|
||||
|
||||
// خط جداکننده
|
||||
display.drawLine(0, 18, 128, 18, SSD1306_WHITE);
|
||||
|
||||
// مقدار CO (منفی = در حال کالیبره) - عدد بزرگ و نرم
|
||||
display.setFont(&FreeSansBold18pt7b);
|
||||
display.setCursor(8, 50);
|
||||
display.print(currentData.coPPM, 0);
|
||||
|
||||
// واحد
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(70, 48);
|
||||
display.print("ppm");
|
||||
|
||||
// وضعیت سنسور و کالیبراسیون
|
||||
display.setCursor(5, 63);
|
||||
if (!calibrationComplete) {
|
||||
display.print("Calibrating...");
|
||||
} else if (!coSensorConnected) {
|
||||
display.print("Sensor ERR");
|
||||
}
|
||||
|
||||
display.setFont();
|
||||
display.display();
|
||||
}
|
||||
|
||||
inline void displayLight() {
|
||||
display.clearDisplay();
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
|
||||
// عنوان
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(40, 14);
|
||||
display.print("Light");
|
||||
|
||||
// خط جداکننده
|
||||
display.drawLine(0, 18, 128, 18, SSD1306_WHITE);
|
||||
|
||||
// مقدار نور - عدد بزرگ و نرم
|
||||
display.setFont(&FreeSansBold18pt7b);
|
||||
display.setCursor(8, 50);
|
||||
display.print((int)currentData.lightLux);
|
||||
|
||||
// واحد
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(75, 48);
|
||||
display.print("lux");
|
||||
|
||||
// وضعیت سنسور
|
||||
display.setCursor(50, 63);
|
||||
if (!lightSensorConnected) {
|
||||
display.print("ERR");
|
||||
}
|
||||
|
||||
display.setFont();
|
||||
display.display();
|
||||
}
|
||||
|
||||
inline void displaySIMStatus() {
|
||||
display.clearDisplay();
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
|
||||
// عنوان
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(25, 14);
|
||||
display.print("SIM Status");
|
||||
|
||||
// خط جداکننده
|
||||
display.drawLine(0, 18, 128, 18, SSD1306_WHITE);
|
||||
|
||||
// بقیه اطلاعات با فونت پیشفرض برای جا شدن بیشتر
|
||||
display.setFont();
|
||||
|
||||
if (!config.verified) {
|
||||
// وضعیت تنظیم نشده
|
||||
display.setTextSize(1);
|
||||
display.setCursor(20, 28);
|
||||
if (!awaitingSMS2) {
|
||||
display.print("Waiting SMS1");
|
||||
display.setCursor(15, 42);
|
||||
display.print("for activation");
|
||||
} else {
|
||||
display.print("Waiting SMS2");
|
||||
display.setCursor(15, 42);
|
||||
display.print("for config");
|
||||
}
|
||||
} else {
|
||||
// وضعیت تنظیم شده
|
||||
display.setTextSize(1);
|
||||
display.setCursor(5, 22);
|
||||
display.print("ID:");
|
||||
display.setCursor(25, 22);
|
||||
display.print(config.deviceId);
|
||||
|
||||
display.setCursor(5, 32);
|
||||
display.print("SIM:");
|
||||
display.setCursor(30, 32);
|
||||
display.print(simTypeToString(config.simType));
|
||||
|
||||
display.setCursor(5, 42);
|
||||
display.print("Upload:");
|
||||
display.setCursor(50, 42);
|
||||
display.print(config.uploadInterval);
|
||||
display.print("m");
|
||||
|
||||
// سیگنال با نشانگر گرافیکی
|
||||
display.setCursor(80, 42);
|
||||
display.print("Sig:");
|
||||
display.setCursor(105, 42);
|
||||
display.print(signalStrength);
|
||||
}
|
||||
|
||||
// آخرین پیام
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(5, 62);
|
||||
if (lastMessage.length() > 14) {
|
||||
display.print(lastMessage.substring(0, 14));
|
||||
} else {
|
||||
display.print(lastMessage);
|
||||
}
|
||||
|
||||
display.setFont();
|
||||
display.display();
|
||||
}
|
||||
|
||||
inline void updateDisplay() {
|
||||
// تغییر صفحه هر 3 ثانیه
|
||||
if (millis() - lastDisplayChange > 3000) {
|
||||
displayMode = (displayMode + 1) % 6; // 6 صفحه داریم
|
||||
lastDisplayChange = millis();
|
||||
}
|
||||
|
||||
// بهروزرسانی وضعیت شبکه هر 30 ثانیه
|
||||
if (millis() - lastNetworkStatusUpdate > 30000) {
|
||||
updateNetworkStatus();
|
||||
lastNetworkStatusUpdate = millis();
|
||||
}
|
||||
|
||||
switch(displayMode) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
displayAllParameters();
|
||||
break;
|
||||
// case 1:
|
||||
// displayTemperature();
|
||||
// break;
|
||||
// case 2:
|
||||
// displayHumidity();
|
||||
// break;
|
||||
// case 3:
|
||||
// displayCO();
|
||||
// break;
|
||||
// case 4:
|
||||
// displayLight();
|
||||
// break;
|
||||
case 4:
|
||||
displaySIMStatus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DISPLAY_H
|
||||
|
||||
503
14041130/TestLCD/Display.h
Normal file
503
14041130/TestLCD/Display.h
Normal file
@@ -0,0 +1,503 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Arduino_GFX_Library.h>
|
||||
#include <math.h>
|
||||
#include "Config.h"
|
||||
|
||||
// ==================== فونتها ====================
|
||||
#include <Fonts/FreeSansBold9pt7b.h>
|
||||
#include <Fonts/FreeSansBold12pt7b.h>
|
||||
#include <Fonts/FreeSansBold18pt7b.h>
|
||||
|
||||
// ==================== تنظیمات LCD ====================
|
||||
#define TFT_CS PB0
|
||||
#define TFT_DC PA4
|
||||
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define LCD_CENTER_X 120
|
||||
#define LCD_CENTER_Y 120
|
||||
|
||||
// ==================== رنگهای سفارشی ====================
|
||||
#define COLOR_BG_DARK 0x0000 // مشکی
|
||||
#define COLOR_TEMP 0xF800 // قرمز برای دما
|
||||
#define COLOR_HUM 0x001F // آبی برای رطوبت
|
||||
#define COLOR_LIGHT 0xFFE0 // زرد برای نور
|
||||
#define COLOR_GAS 0xFD20 // نارنجی برای گاز
|
||||
#define COLOR_BATTERY 0x07E0 // سبز برای باتری
|
||||
#define COLOR_POWER 0x07FF // آبی فیروزهای برای برق
|
||||
#define COLOR_TEXT 0xFFFF // سفید برای متن
|
||||
#define COLOR_TEXT_DIM 0x7BEF // خاکستری برای متن کمرنگ
|
||||
#define COLOR_HEADER 0x8410 // خاکستری تیره برای هدر
|
||||
|
||||
// ==================== متغیرهای خارجی ====================
|
||||
extern Arduino_GC9A01* tft;
|
||||
extern DeviceConfig config;
|
||||
extern SensorData currentData;
|
||||
extern bool sht31Connected;
|
||||
extern bool lightSensorConnected;
|
||||
extern bool coSensorConnected;
|
||||
extern bool calibrationComplete;
|
||||
extern int signalStrength;
|
||||
extern String lastMessage;
|
||||
extern unsigned long lastDisplayChange;
|
||||
|
||||
// پیشاعلام توابع
|
||||
void displayAllParameters();
|
||||
void updateDisplay();
|
||||
void initDisplay();
|
||||
|
||||
// تعریف توابع
|
||||
|
||||
// تابع نمایش مقدار با عنوان
|
||||
inline void drawValueWithLabel(String label, String value, int x, int y, uint16_t valueColor) {
|
||||
if (!tft) return;
|
||||
|
||||
// نمایش عنوان
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
tft->setCursor(x, y);
|
||||
tft->print(label);
|
||||
|
||||
// نمایش مقدار
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds(label + ":", 0, 0, &x1, &y1, &w, &h);
|
||||
|
||||
tft->setTextColor(valueColor, COLOR_BG_DARK);
|
||||
tft->setCursor(x + w + 5, y);
|
||||
tft->print(value);
|
||||
}
|
||||
|
||||
// تابع نمایش هدر
|
||||
inline void drawHeader() {
|
||||
if (!tft) return;
|
||||
|
||||
// پس زمینه هدر
|
||||
tft->fillRect(0, 0, SCREEN_WIDTH, 40, COLOR_HEADER);
|
||||
|
||||
// نمایش عنوان دستگاه
|
||||
tft->setFont(&FreeSansBold12pt7b);
|
||||
tft->setTextColor(COLOR_TEXT, COLOR_HEADER);
|
||||
|
||||
String title = "Station " + String(config.deviceId);
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds(title, 0, 0, &x1, &y1, &w, &h);
|
||||
|
||||
tft->setCursor((SCREEN_WIDTH - w) / 2, 30);
|
||||
tft->print(title);
|
||||
}
|
||||
|
||||
// تابع نمایش دمای بزرگ در مرکز
|
||||
inline void drawLargeTemperature() {
|
||||
if (!tft) return;
|
||||
|
||||
tft->setFont(&FreeSansBold18pt7b);
|
||||
tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK);
|
||||
|
||||
String tempText = String(currentData.temperature, 1) + "°C";
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds(tempText, 0, 0, &x1, &y1, &w, &h);
|
||||
|
||||
tft->setCursor((SCREEN_WIDTH - w) / 2, 90);
|
||||
tft->print(tempText);
|
||||
|
||||
// زیرنویس
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
tft->setCursor((SCREEN_WIDTH - 60) / 2, 115);
|
||||
tft->print("Temperature");
|
||||
}
|
||||
|
||||
// تابع نمایش اطلاعات در دو ستون
|
||||
inline void drawTwoColumnData() {
|
||||
if (!tft) return;
|
||||
|
||||
int startY = 130;
|
||||
int rowHeight = 25;
|
||||
|
||||
// ستون سمت چپ
|
||||
drawValueWithLabel("Humidity:", String(currentData.humidity, 0) + "%", 20, startY, COLOR_HUM);
|
||||
drawValueWithLabel("Light:", String((int)currentData.lightLux) + " lux", 20, startY + rowHeight, COLOR_LIGHT);
|
||||
drawValueWithLabel("Battery:", String(currentData.batteryPercent) + "%", 20, startY + rowHeight * 2, COLOR_BATTERY);
|
||||
|
||||
// ستون سمت راست
|
||||
drawValueWithLabel("CO:", String((int)currentData.coPPM) + " ppm", 140, startY, COLOR_GAS);
|
||||
drawValueWithLabel("Voltage:", String(currentData.batteryVoltage, 1) + "V", 140, startY + rowHeight, COLOR_POWER);
|
||||
|
||||
// وضعیت برق
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
if (currentData.power == 1) {
|
||||
tft->setTextColor(COLOR_POWER, COLOR_BG_DARK);
|
||||
tft->setCursor(140, startY + rowHeight * 2);
|
||||
tft->print("Power: ON");
|
||||
}
|
||||
}
|
||||
|
||||
// تابع نمایش وضعیت سنسورها
|
||||
inline void drawSensorStatus() {
|
||||
if (!tft) return;
|
||||
|
||||
int y = 210;
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
|
||||
// نمایش وضعیت اتصال سنسورها
|
||||
String status = "";
|
||||
if (!sht31Connected) status += "TEMP ";
|
||||
if (!lightSensorConnected) status += "LIGHT ";
|
||||
if (!coSensorConnected) status += "GAS ";
|
||||
|
||||
if (status.length() > 0) {
|
||||
tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK);
|
||||
tft->setCursor(10, y);
|
||||
tft->print("Err: " + status);
|
||||
} else {
|
||||
tft->setTextColor(COLOR_BATTERY, COLOR_BG_DARK);
|
||||
tft->setCursor(10, y);
|
||||
tft->print("All Sensors OK");
|
||||
}
|
||||
|
||||
// نمایش قدرت سیگنال
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
String signalText = "Sig: " + String(signalStrength);
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds(signalText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(SCREEN_WIDTH - w - 10, y);
|
||||
tft->print(signalText);
|
||||
}
|
||||
|
||||
// تابع نمایش فاصله آپلود
|
||||
inline void drawUploadInterval() {
|
||||
if (!tft) return;
|
||||
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
|
||||
String intervalText = "Upload: " + String(config.uploadInterval) + "min";
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds(intervalText, 0, 0, &x1, &y1, &w, &h);
|
||||
|
||||
tft->setCursor((SCREEN_WIDTH - w) / 2, 230);
|
||||
tft->print(intervalText);
|
||||
}
|
||||
inline void displaySimpleMode() {
|
||||
if (!tft) {
|
||||
Serial1.print("Not TFT!!");
|
||||
return;
|
||||
}
|
||||
|
||||
// پاک کردن صفحه
|
||||
tft->fillScreen(COLOR_BG_DARK);
|
||||
|
||||
// ========== نمایش دما بزرگ در مرکز ==========
|
||||
String tempText = String(currentData.temperature, 1) + "°C";
|
||||
tft->setFont(&FreeSansBold18pt7b);
|
||||
tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK);
|
||||
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds(tempText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, LCD_CENTER_Y - 30);
|
||||
tft->print(tempText);
|
||||
|
||||
// ========== نمایش رطوبت زیر دما ==========
|
||||
tft->setFont(&FreeSansBold12pt7b);
|
||||
String humText = "H:" + String(currentData.humidity, 0) + "%";
|
||||
tft->getTextBounds(humText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(COLOR_HUM, COLOR_BG_DARK);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, LCD_CENTER_Y + 20);
|
||||
tft->print(humText);
|
||||
|
||||
// ========== نمایش باتری و نور در یک خط ==========
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
|
||||
// باتری
|
||||
String batText = "B:" + String(currentData.batteryPercent) + "%";
|
||||
if (currentData.power == 1) {
|
||||
batText = "PWR:ON";
|
||||
}
|
||||
tft->getTextBounds(batText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(currentData.power == 1 ? COLOR_POWER : COLOR_BATTERY, COLOR_BG_DARK);
|
||||
tft->setCursor(30, 180); // سمت چپ
|
||||
|
||||
tft->print(batText);
|
||||
|
||||
// نور
|
||||
String lightText = "L:" + String((int)currentData.lightLux);
|
||||
if (currentData.lightLux > 9999) {
|
||||
lightText = "L:" + String(currentData.lightLux / 1000, 0) + "K";
|
||||
}
|
||||
tft->getTextBounds(lightText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(COLOR_LIGHT, COLOR_BG_DARK);
|
||||
tft->setCursor(240 - w - 30, 180); // سمت راست
|
||||
tft->print(lightText);
|
||||
|
||||
// ========== نمایش CO در پایین مرکز ==========
|
||||
bool gasWarning = currentData.coPPM > 50;
|
||||
String gasText = "CO:" + String((int)currentData.coPPM) + "ppm";
|
||||
tft->getTextBounds(gasText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(gasWarning ? COLOR_TEMP : COLOR_GAS, COLOR_BG_DARK);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 210);
|
||||
tft->print(gasText);
|
||||
|
||||
// ========== نمایش ولتاژ و شناسه در بالا ==========
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
|
||||
// ولتاژ در سمت چپ بالا
|
||||
String voltageText = String(currentData.batteryVoltage, 1) + "V";
|
||||
tft->setCursor(10, 20);
|
||||
tft->print(voltageText);
|
||||
|
||||
// شناسه دستگاه در سمت راست بالا
|
||||
String idText = "#" + String(config.deviceId);
|
||||
tft->getTextBounds(idText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(240 - w - 10, 20);
|
||||
tft->print(idText);
|
||||
|
||||
// نمایش وضعیت سنسورها در پایین
|
||||
int errorCount = 0;
|
||||
if (!sht31Connected) errorCount++;
|
||||
if (!lightSensorConnected) errorCount++;
|
||||
if (!coSensorConnected) errorCount++;
|
||||
|
||||
if (errorCount > 0) {
|
||||
tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK);
|
||||
String statusText = String(errorCount) + " ERR";
|
||||
tft->getTextBounds(statusText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 230);
|
||||
tft->print(statusText);
|
||||
}
|
||||
}
|
||||
// ==================== طراحی اصلی ====================
|
||||
|
||||
inline void GdisplayAllParameters() {
|
||||
if (!tft)
|
||||
{
|
||||
Serial1.print("Not TFT!!");
|
||||
return;
|
||||
}
|
||||
// پاک کردن صفحه
|
||||
tft->fillScreen(COLOR_BG_DARK);
|
||||
|
||||
// ========== نمایش دما بزرگ در مرکز ==========
|
||||
String tempText = String(currentData.temperature, 1) + "°C";
|
||||
tft->setFont(&FreeSansBold18pt7b);
|
||||
tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK);
|
||||
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds(tempText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, /*100*/ 115);
|
||||
tft->print(tempText);
|
||||
|
||||
// زیرنویس دما
|
||||
/*tft->setFont(&FreeSansBold9pt7b);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
String tempLabel = "Temperature";
|
||||
tft->getTextBounds(tempLabel, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 140);
|
||||
tft->print(tempLabel);*/
|
||||
|
||||
// ========== نمایش پارامترها در چهار گوشه (داخل دایره) ==========
|
||||
tft->setFont(&FreeSansBold12pt7b);
|
||||
|
||||
// گوشه بالا چپ: نور (L) - فاصله از لبه
|
||||
String lightText = "L:" + String((int)currentData.lightLux);
|
||||
if (currentData.lightLux > 9999) {
|
||||
lightText = "L:" + String(currentData.lightLux / 1000, 0) + "K";
|
||||
}
|
||||
tft->getTextBounds(lightText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(COLOR_LIGHT, COLOR_BG_DARK);
|
||||
tft->setCursor(40, /*60*/ 140); // به سمت مرکز منتقل شد
|
||||
tft->print(lightText);
|
||||
|
||||
// گوشه بالا راست: رطوبت (H)
|
||||
String humText = "H:" + String(currentData.humidity, 0) + "%";
|
||||
tft->getTextBounds(humText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(COLOR_HUM, COLOR_BG_DARK);
|
||||
tft->setCursor(240 - w - 40, 140/*60*/); // به سمت مرکز منتقل شد
|
||||
tft->print(humText);
|
||||
|
||||
// گوشه پایین چپ: باتری (B)
|
||||
String batText;
|
||||
if (currentData.power == 1) {
|
||||
batText = "P:ON";
|
||||
tft->setTextColor(COLOR_POWER, COLOR_BG_DARK);
|
||||
} else {
|
||||
batText = "B:" + String(currentData.batteryPercent) + "%";
|
||||
tft->setTextColor(COLOR_BATTERY, COLOR_BG_DARK);
|
||||
}
|
||||
tft->getTextBounds(batText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(40, 180); // به سمت مرکز منتقل شد
|
||||
tft->print(batText);
|
||||
|
||||
// گوشه پایین راست: گاز CO (G)
|
||||
bool gasWarning = currentData.coPPM > 50;
|
||||
String gasText = "G:" + String((int)currentData.coPPM);
|
||||
tft->getTextBounds(gasText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(gasWarning ? COLOR_TEMP : COLOR_GAS, COLOR_BG_DARK);
|
||||
tft->setCursor(240 - w - 40, 180); // به سمت مرکز منتقل شد
|
||||
tft->print(gasText);
|
||||
|
||||
// ========== نمایش ولتاژ باتری در پایین مرکز ==========
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
String voltageText = String(currentData.batteryVoltage, 1) + "V";
|
||||
tft->getTextBounds(voltageText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 210); // به بالا منتقل شد
|
||||
tft->print(voltageText);
|
||||
|
||||
// ========== نمایش شناسه دستگاه کوچک در گوشه بالا مرکز ==========
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
String idText = "#" + String(config.deviceId);
|
||||
tft->getTextBounds(idText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 20); // به پایین منتقل شد
|
||||
tft->print(idText);
|
||||
}
|
||||
|
||||
inline void displayAllParameters() {
|
||||
if (!tft)
|
||||
{
|
||||
Serial1.print("Not TFT!!");
|
||||
return;
|
||||
}
|
||||
// پاک کردن صفحه
|
||||
tft->fillScreen(COLOR_BG_DARK);
|
||||
|
||||
// ========== نمایش دما بزرگ در مرکز ==========
|
||||
String tempText = String(currentData.temperature, 1) + "°C";
|
||||
tft->setFont(&FreeSansBold18pt7b);
|
||||
tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK);
|
||||
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds(tempText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 100);
|
||||
tft->print(tempText);
|
||||
|
||||
// زیرنویس دما
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
String tempLabel = "Temperature";
|
||||
tft->getTextBounds(tempLabel, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 140);
|
||||
tft->print(tempLabel);
|
||||
|
||||
// ========== نمایش پارامترها در چهار گوشه (داخل دایره) ==========
|
||||
tft->setFont(&FreeSansBold12pt7b);
|
||||
|
||||
// گوشه بالا چپ: نور (L) - فاصله از لبه
|
||||
String lightText = "L:" + String((int)currentData.lightLux);
|
||||
if (currentData.lightLux > 9999) {
|
||||
lightText = "L:" + String(currentData.lightLux / 1000, 0) + "K";
|
||||
}
|
||||
tft->getTextBounds(lightText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(COLOR_LIGHT, COLOR_BG_DARK);
|
||||
tft->setCursor(40, 60); // به سمت مرکز منتقل شد
|
||||
tft->print(lightText);
|
||||
|
||||
// گوشه بالا راست: رطوبت (H)
|
||||
String humText = "H:" + String(currentData.humidity, 0) + "%";
|
||||
tft->getTextBounds(humText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(COLOR_HUM, COLOR_BG_DARK);
|
||||
tft->setCursor(240 - w - 40, 60); // به سمت مرکز منتقل شد
|
||||
tft->print(humText);
|
||||
|
||||
// گوشه پایین چپ: باتری (B)
|
||||
String batText;
|
||||
if (currentData.power == 1) {
|
||||
batText = "P:ON";
|
||||
tft->setTextColor(COLOR_POWER, COLOR_BG_DARK);
|
||||
} else {
|
||||
batText = "B:" + String(currentData.batteryPercent) + "%";
|
||||
tft->setTextColor(COLOR_BATTERY, COLOR_BG_DARK);
|
||||
}
|
||||
tft->getTextBounds(batText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(40, 180); // به سمت مرکز منتقل شد
|
||||
tft->print(batText);
|
||||
|
||||
// گوشه پایین راست: گاز CO (G)
|
||||
bool gasWarning = currentData.coPPM > 50;
|
||||
String gasText = "G:" + String((int)currentData.coPPM);
|
||||
tft->getTextBounds(gasText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(gasWarning ? COLOR_TEMP : COLOR_GAS, COLOR_BG_DARK);
|
||||
tft->setCursor(240 - w - 40, 180); // به سمت مرکز منتقل شد
|
||||
tft->print(gasText);
|
||||
|
||||
// ========== نمایش ولتاژ باتری در پایین مرکز ==========
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
String voltageText = String(currentData.batteryVoltage, 1) + "V";
|
||||
tft->getTextBounds(voltageText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 210); // به بالا منتقل شد
|
||||
tft->print(voltageText);
|
||||
|
||||
// ========== نمایش شناسه دستگاه کوچک در گوشه بالا مرکز ==========
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK);
|
||||
String idText = "#" + String(config.deviceId);
|
||||
tft->getTextBounds(idText, 0, 0, &x1, &y1, &w, &h);
|
||||
tft->setCursor(LCD_CENTER_X - w/2, 20); // به پایین منتقل شد
|
||||
tft->print(idText);
|
||||
}
|
||||
|
||||
// ==================== تابع آپدیت نمایشگر ====================
|
||||
|
||||
inline void updateDisplay() {
|
||||
if (!tft) {
|
||||
Serial1.print("Display not initialized!");
|
||||
return;
|
||||
}
|
||||
|
||||
// تغییر خودکار صفحه هر 15 ثانیه
|
||||
static int displayMode = 0;
|
||||
if (millis() - lastDisplayChange > 3000) {
|
||||
displayMode = (displayMode + 1) % 7;
|
||||
lastDisplayChange = millis();
|
||||
}
|
||||
|
||||
// نمایش بر اساس حالت
|
||||
if (displayMode < 6) {
|
||||
displayAllParameters();
|
||||
//GdisplayAllParameters();
|
||||
}
|
||||
else
|
||||
{
|
||||
displayAllParameters();
|
||||
//GdisplayAllParameters();
|
||||
//displaySimpleMode();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== تابع راهاندازی نمایشگر ====================
|
||||
|
||||
inline void initDisplay() {
|
||||
// ایجاد شیء نمایشگر
|
||||
Arduino_DataBus *bus = new Arduino_HWSPI(TFT_DC, TFT_CS, &SPI);
|
||||
tft = new Arduino_GC9A01(bus, -1, 0, true); // بدون پین RST
|
||||
|
||||
// راهاندازی نمایشگر
|
||||
if (tft) {
|
||||
tft->begin();
|
||||
tft->setRotation(1); // جهت نمایش
|
||||
tft->fillScreen(COLOR_BG_DARK);
|
||||
tft->setTextWrap(false);
|
||||
|
||||
// تنظیم فونت پیشفرض
|
||||
tft->setFont(&FreeSansBold9pt7b);
|
||||
|
||||
Serial1.println("Display initialized successfully");
|
||||
} else {
|
||||
Serial1.println("Failed to initialize display");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DISPLAY_H
|
||||
1612
14041130/TestLCD/EC200U-old.aaaaa
Normal file
1612
14041130/TestLCD/EC200U-old.aaaaa
Normal file
File diff suppressed because it is too large
Load Diff
1509
14041130/TestLCD/EC200U.h
Normal file
1509
14041130/TestLCD/EC200U.h
Normal file
File diff suppressed because it is too large
Load Diff
214
14041130/TestLCD/Icons.h
Normal file
214
14041130/TestLCD/Icons.h
Normal file
@@ -0,0 +1,214 @@
|
||||
#ifndef ICONS_H
|
||||
#define ICONS_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
// ==================== کدهای آیکونهای Unicode ====================
|
||||
#define ICON_SUN 0x2600 // ☀️
|
||||
#define ICON_THERMO 0x1F321 // 🌡️
|
||||
#define ICON_DROP 0x1F4A7 // 💧
|
||||
#define ICON_WARNING 0x26A0 // ⚠️
|
||||
#define ICON_BATTERY 0x1F50B // 🔋
|
||||
#define ICON_SIGNAL 0x1F4F6 // 📶
|
||||
#define ICON_POWER 0x1F50C // 🔌
|
||||
#define ICON_WIFI 0x1F4F6 // 📶
|
||||
#define ICON_CLOCK 0x1F552 // 🕒
|
||||
#define ICON_HOME 0x1F3E0 // 🏠
|
||||
#define ICON_COG 0x2699 // ⚙️
|
||||
#define ICON_DEGREE 0x00B0 // °
|
||||
|
||||
// ==================== توابع رسم آیکونهای گرافیکی ====================
|
||||
|
||||
// تابع رسم آیکون خورشید (دایرهای شکل)
|
||||
inline void drawSunIcon(TFT_eSPI& tft, int x, int y, int radius, uint16_t color) {
|
||||
// دایره مرکزی
|
||||
tft.fillCircle(x, y, radius, color);
|
||||
tft.drawCircle(x, y, radius, TFT_WHITE);
|
||||
|
||||
// پرتوهای خورشید
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float angle = i * 45 * 3.14159 / 180;
|
||||
int x1 = x + (radius * cos(angle));
|
||||
int y1 = y + (radius * sin(angle));
|
||||
int x2 = x + (radius * 1.5 * cos(angle));
|
||||
int y2 = y + (radius * 1.5 * sin(angle));
|
||||
tft.drawLine(x1, y1, x2, y2, color);
|
||||
}
|
||||
}
|
||||
|
||||
// تابع رسم آیکون دماسنج (برای LCD دایرهای)
|
||||
inline void drawThermometerIcon(TFT_eSPI& tft, int x, int y, int height, uint16_t color, float tempPercent) {
|
||||
// بدنه دماسنج
|
||||
tft.drawRoundRect(x - 3, y, 6, height, 3, color);
|
||||
|
||||
// حباب پایین
|
||||
tft.fillCircle(x, y + height + 5, 8, color);
|
||||
tft.drawCircle(x, y + height + 5, 8, TFT_WHITE);
|
||||
|
||||
// سطح جیوه
|
||||
int mercuryHeight = (tempPercent * height) / 100;
|
||||
tft.fillRect(x - 2, y + (height - mercuryHeight), 4, mercuryHeight, TFT_RED);
|
||||
}
|
||||
|
||||
// تابع رسم آیکون قطره (رطوبت)
|
||||
inline void drawDropIcon(TFT_eSPI& tft, int x, int y, int size, uint16_t color, float fillPercent) {
|
||||
// بدنه قطره
|
||||
int dropHeight = size;
|
||||
int dropWidth = size / 2;
|
||||
|
||||
// قسمت دایرهای بالایی
|
||||
tft.fillCircle(x, y + dropWidth/2, dropWidth/2, color);
|
||||
tft.drawCircle(x, y + dropWidth/2, dropWidth/2, TFT_WHITE);
|
||||
|
||||
// قسمت مثلثی پایینی
|
||||
tft.fillTriangle(x - dropWidth/2, y + dropWidth/2,
|
||||
x + dropWidth/2, y + dropWidth/2,
|
||||
x, y + dropHeight, color);
|
||||
|
||||
tft.drawTriangle(x - dropWidth/2, y + dropWidth/2,
|
||||
x + dropWidth/2, y + dropWidth/2,
|
||||
x, y + dropHeight, TFT_WHITE);
|
||||
|
||||
// سطح آب داخل قطره
|
||||
if (fillPercent > 0) {
|
||||
int waterHeight = (fillPercent * dropHeight) / 100;
|
||||
int waterY = y + dropHeight - waterHeight;
|
||||
|
||||
// قسمت دایرهای آب
|
||||
if (waterY < y + dropWidth/2) {
|
||||
int waterRadius = dropWidth/2;
|
||||
int waterLevel = (y + dropWidth/2) - waterY;
|
||||
tft.fillCircle(x, y + dropWidth/2, waterRadius - waterLevel, TFT_BLUE);
|
||||
}
|
||||
|
||||
// قسمت مثلثی آب
|
||||
tft.fillTriangle(x - dropWidth/2, y + dropHeight - waterHeight,
|
||||
x + dropWidth/2, y + dropHeight - waterHeight,
|
||||
x, y + dropHeight, TFT_BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
// تابع رسم آیکون گاز (هشدار)
|
||||
inline void drawGasIcon(TFT_eSPI& tft, int x, int y, int size, uint16_t color, bool warning) {
|
||||
// مثلث هشدار
|
||||
tft.fillTriangle(x, y,
|
||||
x - size/2, y + size,
|
||||
x + size/2, y + size,
|
||||
warning ? TFT_RED : color);
|
||||
|
||||
tft.drawTriangle(x, y,
|
||||
x - size/2, y + size,
|
||||
x + size/2, y + size,
|
||||
TFT_WHITE);
|
||||
|
||||
// علامت تعجب
|
||||
tft.fillRect(x - 1, y + size/3, 2, size/3, TFT_WHITE);
|
||||
tft.fillCircle(x, y + size*2/3, 2, TFT_WHITE);
|
||||
|
||||
// امواج گاز (دایرههای متحدالمرکز)
|
||||
if (warning) {
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
tft.drawCircle(x, y + size + 5, i * 4, TFT_YELLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// تابع رسم آیکون باتری (برای LCD دایرهای)
|
||||
inline void drawBatteryIcon(TFT_eSPI& tft, int x, int y, int width, int height, int percent, bool charging) {
|
||||
// بدنه باتری
|
||||
tft.drawRoundRect(x, y, width, height, 2, TFT_WHITE);
|
||||
|
||||
// قطب مثبت
|
||||
tft.fillRoundRect(x + width, y + height/3, 2, height/3, 1, TFT_WHITE);
|
||||
|
||||
// سطح شارژ
|
||||
int fillWidth = (percent * (width - 4)) / 100;
|
||||
|
||||
// رنگ باتری بر اساس درصد
|
||||
uint16_t fillColor;
|
||||
if (percent > 70) fillColor = TFT_GREEN;
|
||||
else if (percent > 30) fillColor = TFT_YELLOW;
|
||||
else fillColor = TFT_RED;
|
||||
|
||||
tft.fillRoundRect(x + 2, y + 2, fillWidth, height - 4, 1, fillColor);
|
||||
|
||||
// آیکون شارژ (صاعقه)
|
||||
if (charging && percent < 95) {
|
||||
tft.fillTriangle(x + width/2, y + 3,
|
||||
x + width/2 - 3, y + height - 3,
|
||||
x + width/2 + 3, y + height - 3, TFT_CYAN);
|
||||
}
|
||||
|
||||
// نمایش درصد در وسط باتری (اگر جای کافی باشد)
|
||||
if (width > 30) {
|
||||
tft.setTextColor(TFT_WHITE, fillColor);
|
||||
tft.setTextSize(1);
|
||||
tft.setTextDatum(MC_DATUM);
|
||||
tft.drawNumber(percent, x + width/2, y + height/2 + 1);
|
||||
tft.setTextDatum(TL_DATUM); // بازگشت به حالت پیشفرض
|
||||
}
|
||||
}
|
||||
|
||||
// تابع رسم نوار سیگنال (دایرهای)
|
||||
inline void drawSignalBars(TFT_eSPI& tft, int x, int y, int radius, int strength) {
|
||||
// 4 میله سیگنال به شکل دایرهای
|
||||
int bars = (strength * 4) / 31;
|
||||
if (bars > 4) bars = 4;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int barRadius = radius - (i * 5);
|
||||
if (barRadius > 0) {
|
||||
if (i < bars) {
|
||||
uint16_t barColor;
|
||||
if (strength > 20) barColor = TFT_GREEN;
|
||||
else if (strength > 10) barColor = TFT_YELLOW;
|
||||
else barColor = TFT_RED;
|
||||
|
||||
// رسم قوس برای هر میله
|
||||
int startAngle = 180 + (i * 15);
|
||||
int endAngle = 180 - (i * 15);
|
||||
tft.drawArc(x, y, barRadius, barRadius - 2, startAngle, endAngle, barColor, barColor);
|
||||
} else {
|
||||
//tft.drawArc(x, y, barRadius, barRadius - 2, 150, 210, TFT_DARKGREY, TFT_DARKGREY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// نقطه مرکزی
|
||||
tft.fillCircle(x, y, 2, TFT_WHITE);
|
||||
}
|
||||
|
||||
// تابع رسم آیکون برق شهری
|
||||
inline void drawPowerIcon(TFT_eSPI& tft, int x, int y, int size, uint16_t color) {
|
||||
// دایره بیرونی
|
||||
tft.drawCircle(x, y, size/2, color);
|
||||
|
||||
// علامت پاور (دایره با خط)
|
||||
tft.drawLine(x, y - size/4, x, y + size/4, color);
|
||||
tft.fillTriangle(x, y - size/4,
|
||||
x - size/6, y,
|
||||
x + size/6, y, color);
|
||||
}
|
||||
|
||||
// تابع رسم آیکون وایفای (دایرهای)
|
||||
inline void drawWifiIcon(TFT_eSPI& tft, int x, int y, int radius, uint16_t color, bool connected) {
|
||||
if (!connected) {
|
||||
tft.drawLine(x - radius/2, y - radius/2, x + radius/2, y + radius/2, TFT_RED);
|
||||
tft.drawLine(x + radius/2, y - radius/2, x - radius/2, y + radius/2, TFT_RED);
|
||||
return;
|
||||
}
|
||||
|
||||
// حلقههای وایفای
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
int r = radius - (i * 4);
|
||||
if (r > 0) {
|
||||
tft.drawCircle(x, y, r, color);
|
||||
}
|
||||
}
|
||||
|
||||
// نقطه مرکزی
|
||||
tft.fillCircle(x, y, 2, color);
|
||||
}
|
||||
|
||||
#endif // ICONS_H
|
||||
433
14041130/TestLCD/Memory.h
Normal file
433
14041130/TestLCD/Memory.h
Normal file
@@ -0,0 +1,433 @@
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "Config.h"
|
||||
|
||||
// -------------------- کتابخانه EEPROM داخلی برای STM32 --------------------
|
||||
#if defined(STM32F1xx) || defined(STM32F3xx) || defined(STM32F4xx)
|
||||
#include <EEPROM.h>
|
||||
#endif
|
||||
|
||||
// -------------------- متغیرهای خارجی --------------------
|
||||
extern SPIClass flashSPI;
|
||||
extern DeviceConfig config;
|
||||
|
||||
// -------------------- تنظیمات EEPROM داخلی --------------------
|
||||
#define EEPROM_CONFIG_START 0 // آدرس شروع در EEPROM
|
||||
#define EEPROM_SIGNATURE_ADDR 0 // آدرس سیگنچور در EEPROM
|
||||
#define EEPROM_CONFIG_SIZE sizeof(DeviceConfig)
|
||||
|
||||
// -------------------- توابع حافظه SPI Flash --------------------
|
||||
inline void flashInit() {
|
||||
pinMode(FLASH_CS, OUTPUT);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
flashSPI.begin();
|
||||
flashSPI.setClockDivider(SPI_CLOCK_DIV4);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
inline bool flashIsBusy() {
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x05);
|
||||
uint8_t status = flashSPI.transfer(0);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
return (status & 0x01);
|
||||
}
|
||||
|
||||
inline void flashWaitForReady() {
|
||||
unsigned long start = millis();
|
||||
while (flashIsBusy()) {
|
||||
if (millis() - start > 1000) {
|
||||
Serial1.println("⚠️ Flash wait timeout");
|
||||
break;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool flashReadBytes(uint32_t addr, uint8_t *data, uint32_t len) {
|
||||
if (len == 0) return false;
|
||||
|
||||
flashWaitForReady();
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x03); // Read command
|
||||
flashSPI.transfer((addr >> 16) & 0xFF);
|
||||
flashSPI.transfer((addr >> 8) & 0xFF);
|
||||
flashSPI.transfer(addr & 0xFF);
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
data[i] = flashSPI.transfer(0);
|
||||
}
|
||||
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool flashWriteBytes(uint32_t addr, uint8_t *data, uint32_t len) {
|
||||
if (len == 0) return false;
|
||||
|
||||
// Write Enable
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x06);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
delay(1);
|
||||
|
||||
// Page Program
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x02);
|
||||
flashSPI.transfer((addr >> 16) & 0xFF);
|
||||
flashSPI.transfer((addr >> 8) & 0xFF);
|
||||
flashSPI.transfer(addr & 0xFF);
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
flashSPI.transfer(data[i]);
|
||||
}
|
||||
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
flashWaitForReady();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void flashSectorErase(uint32_t addr) {
|
||||
// Write Enable
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x06);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
delay(1);
|
||||
|
||||
// Sector Erase
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x20);
|
||||
flashSPI.transfer((addr >> 16) & 0xFF);
|
||||
flashSPI.transfer((addr >> 8) & 0xFF);
|
||||
flashSPI.transfer(addr & 0xFF);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
|
||||
flashWaitForReady();
|
||||
}
|
||||
|
||||
inline bool testFlashCommunication() {
|
||||
Serial1.print("Testing flash communication... ");
|
||||
|
||||
// دستور خواندن JEDEC ID
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x9F);
|
||||
uint8_t manuf = flashSPI.transfer(0);
|
||||
uint8_t type = flashSPI.transfer(0);
|
||||
uint8_t capacity = flashSPI.transfer(0);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
|
||||
if (manuf == 0xFF || manuf == 0x00) {
|
||||
Serial1.println("❌ FAILED (No response)");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial1.print("✅ OK (Manuf: 0x");
|
||||
Serial1.print(manuf, HEX);
|
||||
Serial1.print(", Type: 0x");
|
||||
Serial1.print(type, HEX);
|
||||
Serial1.print(", Capacity: 0x");
|
||||
Serial1.print(capacity, HEX);
|
||||
Serial1.println(")");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------- توابع EEPROM داخلی STM32 --------------------
|
||||
inline bool eepromIsAvailable() {
|
||||
#if defined(STM32F1xx) || defined(STM32F3xx) || defined(STM32F4xx)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool eepromWriteConfig(const DeviceConfig &cfg) {
|
||||
if (!eepromIsAvailable()) {
|
||||
Serial1.println("❌ EEPROM not available on this board");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial1.print("Writing config to EEPROM (");
|
||||
Serial1.print(sizeof(cfg));
|
||||
Serial1.println(" bytes)...");
|
||||
|
||||
uint8_t *data = (uint8_t*)&cfg;
|
||||
|
||||
// نوشتن در EEPROM
|
||||
for (uint16_t i = 0; i < sizeof(cfg); i++) {
|
||||
EEPROM.write(EEPROM_CONFIG_START + i, data[i]);
|
||||
}
|
||||
|
||||
// ذخیره تغییرات
|
||||
#if defined(EEPROM_commit)
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
|
||||
Serial1.println("✅ Config written to EEPROM");
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool eepromReadConfig(DeviceConfig &cfg) {
|
||||
if (!eepromIsAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *data = (uint8_t*)&cfg;
|
||||
|
||||
// خواندن از EEPROM
|
||||
for (uint16_t i = 0; i < sizeof(cfg); i++) {
|
||||
data[i] = EEPROM.read(EEPROM_CONFIG_START + i);
|
||||
}
|
||||
|
||||
// بررسی سیگنچور
|
||||
if (strcmp(cfg.signature, "CFG") != 0) {
|
||||
Serial1.println("❌ Invalid signature in EEPROM");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial1.println("✅ Config read from EEPROM");
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool eepromClearConfig() {
|
||||
if (!eepromIsAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// پاک کردن با نوشتن 0xFF
|
||||
for (uint16_t i = 0; i < EEPROM_CONFIG_SIZE; i++) {
|
||||
EEPROM.write(EEPROM_CONFIG_START + i, 0xFF);
|
||||
}
|
||||
|
||||
#if defined(EEPROM_commit)
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
|
||||
Serial1.println("✅ EEPROM cleared");
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------- توابع مدیریت کانفیگ هوشمند --------------------
|
||||
inline void saveConfig() {
|
||||
Serial1.println("\n💾 SAVING CONFIGURATION");
|
||||
|
||||
config.valid = true;
|
||||
uint8_t buffer[sizeof(DeviceConfig)];
|
||||
memcpy(buffer, &config, sizeof(DeviceConfig));
|
||||
|
||||
bool flashSuccess = false;
|
||||
bool eepromSuccess = false;
|
||||
|
||||
// 1. ذخیره در حافظه SPI Flash (اصلی)
|
||||
Serial1.println("1. Saving to SPI Flash...");
|
||||
if (testFlashCommunication()) {
|
||||
flashSectorErase(CONFIG_ADDRESS);
|
||||
if (flashWriteBytes(CONFIG_ADDRESS, buffer, sizeof(DeviceConfig))) {
|
||||
// تأیید
|
||||
uint8_t verifyBuffer[sizeof(DeviceConfig)];
|
||||
if (flashReadBytes(CONFIG_ADDRESS, verifyBuffer, sizeof(DeviceConfig))) {
|
||||
if (memcmp(buffer, verifyBuffer, sizeof(DeviceConfig)) == 0) {
|
||||
flashSuccess = true;
|
||||
Serial1.println(" ✅ SPI Flash: Saved and verified");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!flashSuccess) {
|
||||
Serial1.println(" ❌ SPI Flash: Failed or not available");
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. ذخیره در EEPROM داخلی (پشتیبان)
|
||||
Serial1.println("2. Saving to internal EEPROM...");
|
||||
eepromSuccess = eepromWriteConfig(config);
|
||||
|
||||
if (eepromSuccess) {
|
||||
Serial1.println(" ✅ EEPROM: Backup saved");
|
||||
} else {
|
||||
Serial1.println(" ⚠️ EEPROM: Backup not available");
|
||||
}
|
||||
|
||||
// خلاصه
|
||||
Serial1.println("\n📊 SAVE SUMMARY:");
|
||||
Serial1.print(" SPI Flash: ");
|
||||
Serial1.println(flashSuccess ? "✅" : "❌");
|
||||
Serial1.print(" Internal EEPROM: ");
|
||||
Serial1.println(eepromSuccess ? "✅" : "⚠️");
|
||||
|
||||
if (flashSuccess || eepromSuccess) {
|
||||
Serial1.println("✅ Configuration saved successfully");
|
||||
} else {
|
||||
Serial1.println("❌ CRITICAL: Could not save config anywhere!");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool loadConfigFromFlash() {
|
||||
Serial1.print("Trying to load from SPI Flash... ");
|
||||
|
||||
uint8_t buffer[sizeof(DeviceConfig)];
|
||||
|
||||
if (!testFlashCommunication()) {
|
||||
Serial1.println("❌ Flash not responding");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!flashReadBytes(CONFIG_ADDRESS, buffer, sizeof(DeviceConfig))) {
|
||||
Serial1.println("❌ Failed to read from flash");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&config, buffer, sizeof(DeviceConfig));
|
||||
|
||||
if (strcmp(config.signature, "CFG") != 0) {
|
||||
Serial1.println("❌ Invalid signature in flash");
|
||||
return false;
|
||||
}
|
||||
|
||||
config.valid = true;
|
||||
Serial1.println("✅ Success");
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool loadConfigFromEEPROM() {
|
||||
Serial1.print("Trying to load from internal EEPROM... ");
|
||||
|
||||
if (!eepromIsAvailable()) {
|
||||
Serial1.println("❌ EEPROM not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eepromReadConfig(config)) {
|
||||
Serial1.println("❌ Failed to read from EEPROM");
|
||||
return false;
|
||||
}
|
||||
|
||||
config.valid = true;
|
||||
Serial1.println("✅ Success");
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void createDefaultConfig() {
|
||||
Serial1.println("Creating default configuration...");
|
||||
|
||||
strcpy(config.signature, "CFG");
|
||||
strcpy(config.deviceId, "");
|
||||
strcpy(config.serverPhoneNumber, "");
|
||||
strcpy(config.serverUrl, "https://ghback.nabaksoft.ir");
|
||||
config.uploadInterval = 5;
|
||||
config.smsInterval = 10;
|
||||
config.saveInterval = 60;
|
||||
config.simType = SIM_UNKNOWN;
|
||||
config.smsEnabled = false;
|
||||
config.verified = false;
|
||||
config.valid = false;
|
||||
}
|
||||
|
||||
inline void readConfig() {
|
||||
Serial1.println("\n📖 LOADING CONFIGURATION");
|
||||
|
||||
bool configLoaded = false;
|
||||
String source = "";
|
||||
|
||||
// استراتژی: اول SPI Flash، اگر نشد EEPROM داخلی
|
||||
Serial1.println("Strategy: SPI Flash → Internal EEPROM");
|
||||
|
||||
// 1. اول از SPI Flash بخوان
|
||||
if (loadConfigFromFlash()) {
|
||||
configLoaded = true;
|
||||
source = "SPI Flash";
|
||||
|
||||
// همچنین در EEPROM هم بروزرسانی کن (sync)
|
||||
//eepromWriteConfig(config);
|
||||
}
|
||||
// 2. اگر SPI Flash کار نکرد، از EEPROM داخلی بخوان
|
||||
else if (loadConfigFromEEPROM()) {
|
||||
configLoaded = true;
|
||||
source = "Internal EEPROM (backup)";
|
||||
|
||||
// سعی کن دوباره در SPI Flash ذخیره کنی (بازیابی)
|
||||
Serial1.println("Attempting to restore to SPI Flash...");
|
||||
uint8_t buffer[sizeof(DeviceConfig)];
|
||||
memcpy(buffer, &config, sizeof(DeviceConfig));
|
||||
|
||||
if (testFlashCommunication()) {
|
||||
flashSectorErase(CONFIG_ADDRESS);
|
||||
flashWriteBytes(CONFIG_ADDRESS, buffer, sizeof(DeviceConfig));
|
||||
Serial1.println("✅ Restored to SPI Flash");
|
||||
}
|
||||
}
|
||||
|
||||
// 3. اگر هیچ کدام کار نکرد، کانفیگ پیشفرض بساز
|
||||
if (!configLoaded) {
|
||||
Serial1.println("❌ No valid config found in any memory");
|
||||
source = "Default";
|
||||
|
||||
createDefaultConfig();
|
||||
saveConfig(); // ذخیره کانفیگ جدید
|
||||
configLoaded = true;
|
||||
}
|
||||
|
||||
// نمایش نتیجه
|
||||
Serial1.println("\n📊 LOAD RESULT:");
|
||||
Serial1.print(" Status: ");
|
||||
Serial1.println(configLoaded ? "✅ LOADED" : "❌ FAILED");
|
||||
Serial1.print(" Source: ");
|
||||
Serial1.println(source);
|
||||
Serial1.print(" Device ID: ");
|
||||
Serial1.println(strlen(config.deviceId) > 0 ? config.deviceId : "[Empty]");
|
||||
Serial1.print(" Verified: ");
|
||||
Serial1.println(config.verified ? "YES" : "NO");
|
||||
|
||||
if (configLoaded) {
|
||||
Serial1.println("✅ Configuration ready");
|
||||
}
|
||||
}
|
||||
|
||||
// تابع دیباگ برای نمایش وضعیت حافظهها
|
||||
inline void memoryStatus() {
|
||||
Serial1.println("\n🔍 MEMORY STATUS");
|
||||
Serial1.println("================");
|
||||
|
||||
// تست SPI Flash
|
||||
Serial1.print("SPI Flash: ");
|
||||
Serial1.println(testFlashCommunication() ? "✅ Available" : "❌ Not available");
|
||||
|
||||
// تست EEPROM داخلی
|
||||
Serial1.print("Internal EEPROM: ");
|
||||
Serial1.println(eepromIsAvailable() ? "✅ Available" : "❌ Not available");
|
||||
|
||||
// وضعیت کانفیگ فعلی
|
||||
Serial1.print("Config in RAM: ");
|
||||
Serial1.println(config.valid ? "✅ Valid" : "❌ Invalid");
|
||||
|
||||
Serial1.println("================\n");
|
||||
}
|
||||
|
||||
// تابع ریست کامل (برای تست)
|
||||
inline void resetAllConfig() {
|
||||
Serial1.println("\n⚠️ RESETTING ALL CONFIGURATION");
|
||||
|
||||
// پاک کردن SPI Flash
|
||||
if (testFlashCommunication()) {
|
||||
flashSectorErase(CONFIG_ADDRESS);
|
||||
Serial1.println("✅ SPI Flash erased");
|
||||
}
|
||||
|
||||
// پاک کردن EEPROM
|
||||
eepromClearConfig();
|
||||
|
||||
// ایجاد کانفیگ پیشفرض
|
||||
createDefaultConfig();
|
||||
saveConfig();
|
||||
|
||||
Serial1.println("✅ All configuration reset to defaults\n");
|
||||
}
|
||||
|
||||
#endif // MEMORY_H
|
||||
14
14041130/TestLCD/STM32_InternalFlash.h.h
Normal file
14
14041130/TestLCD/STM32_InternalFlash.h.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// STM32_InternalFlash.h
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
bool STM32_InternalFlash_Write(uint32_t address, const uint8_t* data, uint32_t size);
|
||||
bool STM32_InternalFlash_Read(uint32_t address, uint8_t* data, uint32_t size);
|
||||
bool STM32_InternalFlash_Erase(uint32_t address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
472
14041130/TestLCD/Sensors - Copy.hold
Normal file
472
14041130/TestLCD/Sensors - Copy.hold
Normal file
@@ -0,0 +1,472 @@
|
||||
#ifndef SENSORS_H
|
||||
#define SENSORS_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include "Config.h"
|
||||
|
||||
#define VCC 4.63
|
||||
#define RL 10000.0
|
||||
#define VDIV_RATIO 0.681
|
||||
#define I2C_TIMEOUT_MS 100
|
||||
|
||||
// تعریف پینها
|
||||
#define BH1750_SDA_PIN PB7
|
||||
#define BH1750_SCL_PIN PB6
|
||||
#define SHT31_SDA_PIN PB9
|
||||
#define SHT31_SCL_PIN PB8
|
||||
|
||||
#define SHT31_ADDR 0x44
|
||||
#define BH1750_ADDR 0x23
|
||||
|
||||
// متغیرهای خارجی
|
||||
extern SensorData currentData;
|
||||
extern bool sht31Connected;
|
||||
extern bool lightSensorConnected;
|
||||
extern bool coSensorConnected;
|
||||
extern bool calibrationComplete;
|
||||
extern unsigned long systemStartTime;
|
||||
extern unsigned long lastSensorRead;
|
||||
extern float MQ7_R0;
|
||||
extern TwoWire Wire1;
|
||||
extern const long calibrationPeriod;
|
||||
|
||||
// توابع
|
||||
void initSensors();
|
||||
void readSensors();
|
||||
void checkSensorStatus();
|
||||
|
||||
// -------------------- پاکسازی باس I2C --------------------
|
||||
inline void i2cBusClear(uint8_t scl_pin, uint8_t sda_pin, bool isWire1 = false) {
|
||||
Serial1.print("Clearing I2C bus on pins SCL:");
|
||||
Serial1.print(scl_pin);
|
||||
Serial1.print(" SDA:");
|
||||
Serial1.println(sda_pin);
|
||||
|
||||
// آزاد کردن باس
|
||||
if (isWire1) {
|
||||
Wire1.end();
|
||||
} else {
|
||||
Wire.end();
|
||||
}
|
||||
|
||||
delay(50);
|
||||
|
||||
// تنظیم پینها به صورت دستی
|
||||
pinMode(scl_pin, OUTPUT_OPEN_DRAIN);
|
||||
pinMode(sda_pin, OUTPUT_OPEN_DRAIN);
|
||||
|
||||
digitalWrite(sda_pin, HIGH);
|
||||
digitalWrite(scl_pin, HIGH);
|
||||
delayMicroseconds(10);
|
||||
|
||||
// تولید پالس کلاک برای رهاسازی باس
|
||||
for (int i = 0; i < 18; i++) {
|
||||
digitalWrite(scl_pin, LOW);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(scl_pin, HIGH);
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
|
||||
// ایجاد شرط STOP
|
||||
digitalWrite(sda_pin, LOW);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(scl_pin, HIGH);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(sda_pin, HIGH);
|
||||
delayMicroseconds(5);
|
||||
|
||||
delay(100);
|
||||
|
||||
// راهاندازی مجدد
|
||||
if (isWire1) {
|
||||
Wire1.setSDA(sda_pin);
|
||||
Wire1.setSCL(scl_pin);
|
||||
Wire1.begin();
|
||||
Wire1.setClock(50000); // سرعت پایین برای پایداری
|
||||
} else {
|
||||
Wire.setSDA(sda_pin);
|
||||
Wire.setSCL(scl_pin);
|
||||
Wire.begin();
|
||||
Wire.setClock(50000); // سرعت پایین برای پایداری
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// -------------------- کالیبراسیون MQ7 --------------------
|
||||
inline void calibrateMQ7() {
|
||||
Serial1.println("Calibrating MQ7...");
|
||||
|
||||
float sumRS = 0;
|
||||
for(int i = 0; i < 50; i++) { // کاهش از 100 به 50
|
||||
int adc = analogRead(MQ7_PIN);
|
||||
float v_adc = adc * (5.0 / 4095.0);
|
||||
float v_ao = v_adc / VDIV_RATIO;
|
||||
|
||||
if (v_ao < 0.01) v_ao = 0.01;
|
||||
float RS = RL * (VCC / v_ao - 1.0);
|
||||
sumRS += RS;
|
||||
delay(20); // کاهش تاخیر
|
||||
}
|
||||
|
||||
MQ7_R0 = (sumRS / 50.0) / 9.8;
|
||||
calibrationComplete = true;
|
||||
|
||||
Serial1.print("MQ7 R0 calibrated: ");
|
||||
Serial1.println(MQ7_R0);
|
||||
}
|
||||
|
||||
// -------------------- خواندن CO --------------------
|
||||
inline float readCOImproved() {
|
||||
float sumVoltage = 0;
|
||||
for (int i = 0; i < 10; i++) { // کاهش از 20 به 10
|
||||
int adc = analogRead(MQ7_PIN);
|
||||
float v_adc = adc * (5.0 / 4095.0);
|
||||
sumVoltage += v_adc;
|
||||
delay(1);
|
||||
}
|
||||
|
||||
float v_avg = sumVoltage / 10.0;
|
||||
if (v_avg < 0.01) v_avg = 0.01;
|
||||
if (v_avg > 4.99) v_avg = 4.99;
|
||||
|
||||
float v_ao = v_avg / VDIV_RATIO;
|
||||
float RS = RL * (VCC / v_ao - 1.0);
|
||||
float ratio = RS / MQ7_R0;
|
||||
float ppm = 0;
|
||||
|
||||
if (ratio > 0) {
|
||||
ppm = 100.0 * pow(ratio, -1.53);
|
||||
ppm = constrain(ppm, 0, 5000);
|
||||
}
|
||||
|
||||
if (!calibrationComplete) {
|
||||
ppm = -ppm;
|
||||
}
|
||||
|
||||
return ppm;
|
||||
}
|
||||
|
||||
// -------------------- خواندن SHT31 (سادهشده) --------------------
|
||||
inline bool readSHT31(float &temperature, float &humidity) {
|
||||
static uint8_t errorCount = 0;
|
||||
static bool needsReset = false;
|
||||
|
||||
// اگر نیاز به بازنشانی داریم
|
||||
if (needsReset) {
|
||||
Serial1.println("Resetting SHT31 I2C bus...");
|
||||
i2cBusClear(SHT31_SCL_PIN, SHT31_SDA_PIN, false);
|
||||
needsReset = false;
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// تست اتصال اولیه
|
||||
Wire.beginTransmission(SHT31_ADDR);
|
||||
uint8_t connError = Wire.endTransmission();
|
||||
|
||||
if (connError != 0) {
|
||||
Serial1.print("SHT31 connection error: ");
|
||||
Serial1.println(connError);
|
||||
errorCount++;
|
||||
|
||||
if (errorCount >= 2) {
|
||||
needsReset = true;
|
||||
errorCount = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ارسال دستور اندازهگیری (کوتاه)
|
||||
Wire.beginTransmission(SHT31_ADDR);
|
||||
if (Wire.write(0x2C) != 1) { // دستور سریع
|
||||
Serial1.println("SHT31 write failed");
|
||||
return false;
|
||||
}
|
||||
if (Wire.write(0x06) != 1) { // تکرار بالا
|
||||
Serial1.println("SHT31 write failed");
|
||||
return false;
|
||||
}
|
||||
uint8_t writeError = Wire.endTransmission();
|
||||
|
||||
if (writeError != 0) {
|
||||
Serial1.print("SHT31 write error: ");
|
||||
Serial1.println(writeError);
|
||||
errorCount++;
|
||||
|
||||
if (errorCount >= 2) {
|
||||
needsReset = true;
|
||||
errorCount = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// تاخیر اندازهگیری
|
||||
delay(20); // برای حالت High Repeatability
|
||||
|
||||
// خواندن داده
|
||||
uint8_t bytesRead = Wire.requestFrom(SHT31_ADDR, (uint8_t)6, (uint8_t)true);
|
||||
|
||||
if (bytesRead != 6) {
|
||||
Serial1.print("SHT31 read error, bytes: ");
|
||||
Serial1.println(bytesRead);
|
||||
|
||||
// خالی کردن بافر
|
||||
while (Wire.available()) {
|
||||
Wire.read();
|
||||
}
|
||||
|
||||
errorCount++;
|
||||
if (errorCount >= 2) {
|
||||
needsReset = true;
|
||||
errorCount = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// خواندن بایتها
|
||||
uint8_t data[6];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
data[i] = Wire.read();
|
||||
}
|
||||
|
||||
// بررسی CRC (سادهشده)
|
||||
uint16_t tRaw = (data[0] << 8) | data[1];
|
||||
uint16_t hRaw = (data[3] << 8) | data[4];
|
||||
|
||||
// تبدیل مقادیر
|
||||
temperature = -45.0 + 175.0 * tRaw / 65535.0;
|
||||
humidity = 100.0 * hRaw / 65535.0;
|
||||
|
||||
// اعتبارسنجی
|
||||
if (isnan(temperature) || isnan(humidity) ||
|
||||
temperature < -40 || temperature > 125 ||
|
||||
humidity < 0 || humidity > 100) {
|
||||
Serial1.println("SHT31 invalid data");
|
||||
return false;
|
||||
}
|
||||
|
||||
errorCount = 0; // ریست شمارنده خطا
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------- خواندن BH1750 --------------------
|
||||
inline bool readBH1750(float &lux) {
|
||||
static bool initialized = false;
|
||||
static uint8_t errorCount = 0;
|
||||
|
||||
// مقداردهی اولیه
|
||||
if (!initialized) {
|
||||
Serial1.println("Initializing BH1750...");
|
||||
Wire1.setSDA(BH1750_SDA_PIN);
|
||||
Wire1.setSCL(BH1750_SCL_PIN);
|
||||
Wire1.begin();
|
||||
Wire1.setClock(50000); // سرعت پایین
|
||||
delay(100);
|
||||
|
||||
// پاور آن
|
||||
Wire1.beginTransmission(BH1750_ADDR);
|
||||
Wire1.write(0x01);
|
||||
if (Wire1.endTransmission() != 0) {
|
||||
Serial1.println("BH1750 power on failed");
|
||||
return false;
|
||||
}
|
||||
delay(10);
|
||||
|
||||
// تنظیم حالت
|
||||
Wire1.beginTransmission(BH1750_ADDR);
|
||||
Wire1.write(0x13); // Continuous H-Resolution Mode 0.5lx
|
||||
if (Wire1.endTransmission() != 0) {
|
||||
Serial1.println("BH1750 mode set failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
delay(180); // زمان اولیه برای اندازهگیری
|
||||
}
|
||||
|
||||
// خواندن داده
|
||||
uint8_t bytesRead = Wire1.requestFrom(BH1750_ADDR, (uint8_t)2);
|
||||
|
||||
if (bytesRead != 2) {
|
||||
Serial1.print("BH1750 read error, bytes: ");
|
||||
Serial1.println(bytesRead);
|
||||
errorCount++;
|
||||
|
||||
if (errorCount >= 3) {
|
||||
initialized = false;
|
||||
errorCount = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// خواندن بایتها
|
||||
uint8_t highByte = Wire1.read();
|
||||
uint8_t lowByte = Wire1.read();
|
||||
|
||||
uint16_t raw = (highByte << 8) | lowByte;
|
||||
lux = raw / 1.2f;
|
||||
|
||||
errorCount = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------- بررسی وضعیت سنسورها --------------------
|
||||
inline void checkSensorStatus() {
|
||||
// فقط چاپ وضعیت فعلی
|
||||
Serial1.println("--- Sensor Status ---");
|
||||
Serial1.print("SHT31: ");
|
||||
Serial1.println(sht31Connected ? "OK" : "ERROR");
|
||||
Serial1.print("BH1750: ");
|
||||
Serial1.println(lightSensorConnected ? "OK" : "ERROR");
|
||||
Serial1.print("MQ7: ");
|
||||
Serial1.println(coSensorConnected ? "OK" : "ERROR");
|
||||
}
|
||||
|
||||
// -------------------- خواندن همه سنسورها --------------------
|
||||
inline void readSensors() {
|
||||
Serial1.println("\n=== Reading Sensors ===");
|
||||
|
||||
// اول BH1750 را بخوان (چون کار میکند)
|
||||
float lux;
|
||||
if (readBH1750(lux)) {
|
||||
currentData.lightLux = lux;
|
||||
lightSensorConnected = true;
|
||||
Serial1.print("BH1750: ");
|
||||
Serial1.print(lux, 0);
|
||||
Serial1.println(" lux");
|
||||
} else {
|
||||
currentData.lightLux = 0;
|
||||
lightSensorConnected = false;
|
||||
Serial1.println("BH1750: FAILED");
|
||||
}
|
||||
|
||||
// سپس SHT31
|
||||
float temperature = NAN, humidity = NAN;
|
||||
bool sht31Read = readSHT31(temperature, humidity);
|
||||
|
||||
if (sht31Read && !isnan(temperature) && !isnan(humidity)) {
|
||||
currentData.temperature = temperature;
|
||||
currentData.humidity = humidity;
|
||||
sht31Connected = true;
|
||||
Serial1.print("SHT31: T=");
|
||||
Serial1.print(temperature, 1);
|
||||
Serial1.print("C, H=");
|
||||
Serial1.print(humidity, 1);
|
||||
Serial1.println("%");
|
||||
} else {
|
||||
currentData.temperature = NAN;
|
||||
currentData.humidity = NAN;
|
||||
sht31Connected = false;
|
||||
Serial1.println("SHT31: FAILED");
|
||||
}
|
||||
|
||||
// کالیبراسیون MQ7
|
||||
if (!calibrationComplete && (millis() - systemStartTime >= calibrationPeriod)) {
|
||||
calibrateMQ7();
|
||||
calibrationComplete = true;
|
||||
}
|
||||
|
||||
// خواندن 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");
|
||||
|
||||
// محاسبه درصدها
|
||||
calculatePercentages(currentData);
|
||||
|
||||
lastSensorRead = millis();
|
||||
Serial1.println("=== Sensor Readings Complete ===\n");
|
||||
|
||||
// اگر SHT31 کار نمیکند، سیستم را مسدود نکن
|
||||
if (!sht31Connected) {
|
||||
Serial1.println("Warning: SHT31 not responding, continuing anyway...");
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- مقداردهی اولیه --------------------
|
||||
inline void initSensors() {
|
||||
Serial1.println("Initializing sensors...");
|
||||
|
||||
// راهاندازی I2C1 برای SHT31 (سرعت پایین)
|
||||
Wire.setSDA(SHT31_SDA_PIN);
|
||||
Wire.setSCL(SHT31_SCL_PIN);
|
||||
Wire.begin();
|
||||
Wire.setClock(50000); // 50kHz برای پایداری
|
||||
Wire.setTimeout(100);
|
||||
|
||||
// راهاندازی I2C2 برای BH1750
|
||||
Wire1.setSDA(BH1750_SDA_PIN);
|
||||
Wire1.setSCL(BH1750_SCL_PIN);
|
||||
Wire1.begin();
|
||||
Wire1.setClock(50000); // 50kHz
|
||||
Wire1.setTimeout(100);
|
||||
|
||||
// پیکربندی MQ7
|
||||
pinMode(MQ7_PIN, INPUT);
|
||||
analogReadResolution(12);
|
||||
|
||||
delay(1000);
|
||||
|
||||
// اسکن آدرسهای I2C
|
||||
Serial1.println("Scanning I2C1 (SHT31)...");
|
||||
byte error;
|
||||
int found1 = 0;
|
||||
for(byte addr = 1; addr < 127; addr++) {
|
||||
Wire.beginTransmission(addr);
|
||||
error = Wire.endTransmission();
|
||||
if (error == 0) {
|
||||
Serial1.print("Found device at 0x");
|
||||
if (addr < 16) Serial1.print("0");
|
||||
Serial1.println(addr, HEX);
|
||||
found1++;
|
||||
}
|
||||
}
|
||||
Serial1.print("I2C1 devices: ");
|
||||
Serial1.println(found1);
|
||||
|
||||
Serial1.println("Scanning I2C2 (BH1750)...");
|
||||
int found2 = 0;
|
||||
for(byte addr = 1; addr < 127; addr++) {
|
||||
Wire1.beginTransmission(addr);
|
||||
error = Wire1.endTransmission();
|
||||
if (error == 0) {
|
||||
Serial1.print("Found device at 0x");
|
||||
if (addr < 16) Serial1.print("0");
|
||||
Serial1.println(addr, HEX);
|
||||
found2++;
|
||||
}
|
||||
}
|
||||
Serial1.print("I2C2 devices: ");
|
||||
Serial1.println(found2);
|
||||
|
||||
// تست اولیه سریع
|
||||
Serial1.println("Quick sensor test...");
|
||||
float lux;
|
||||
if (readBH1750(lux)) {
|
||||
lightSensorConnected = true;
|
||||
Serial1.print("BH1750 OK: ");
|
||||
Serial1.print(lux);
|
||||
Serial1.println(" lux");
|
||||
}
|
||||
|
||||
delay(100);
|
||||
|
||||
float temp, hum;
|
||||
if (readSHT31(temp, hum)) {
|
||||
sht31Connected = true;
|
||||
Serial1.print("SHT31 OK: ");
|
||||
Serial1.print(temp);
|
||||
Serial1.print("C ");
|
||||
Serial1.print(hum);
|
||||
Serial1.println("%");
|
||||
}
|
||||
|
||||
Serial1.println("Sensor init done");
|
||||
}
|
||||
|
||||
#endif // SENSORS_H
|
||||
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
|
||||
130
14041130/TestLCD/SoftI2C.cppppp
Normal file
130
14041130/TestLCD/SoftI2C.cppppp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "SoftI2C.h"
|
||||
|
||||
SoftI2C::SoftI2C(uint8_t sda, uint8_t scl, uint32_t freq) {
|
||||
sda_pin = sda;
|
||||
scl_pin = scl;
|
||||
delay_us = 1000000 / (2 * freq); // نیم پریود
|
||||
}
|
||||
|
||||
void SoftI2C::begin() {
|
||||
pinMode(sda_pin, INPUT_PULLUP);
|
||||
pinMode(scl_pin, INPUT_PULLUP);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void SoftI2C::end() {
|
||||
stop_condition();
|
||||
pinMode(sda_pin, INPUT);
|
||||
pinMode(scl_pin, INPUT);
|
||||
}
|
||||
|
||||
void SoftI2C::start_condition() {
|
||||
pinMode(sda_pin, OUTPUT);
|
||||
sda_high();
|
||||
scl_high();
|
||||
i2c_delay();
|
||||
sda_low();
|
||||
i2c_delay();
|
||||
scl_low();
|
||||
i2c_delay();
|
||||
}
|
||||
|
||||
void SoftI2C::stop_condition() {
|
||||
pinMode(sda_pin, OUTPUT);
|
||||
sda_low();
|
||||
i2c_delay();
|
||||
scl_high();
|
||||
i2c_delay();
|
||||
sda_high();
|
||||
i2c_delay();
|
||||
pinMode(sda_pin, INPUT_PULLUP);
|
||||
pinMode(scl_pin, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
bool SoftI2C::write_byte(uint8_t data) {
|
||||
pinMode(sda_pin, OUTPUT);
|
||||
|
||||
for(int i = 7; i >= 0; i--) {
|
||||
if(data & (1 << i)) {
|
||||
sda_high();
|
||||
} else {
|
||||
sda_low();
|
||||
}
|
||||
i2c_delay();
|
||||
scl_high();
|
||||
i2c_delay();
|
||||
scl_low();
|
||||
i2c_delay();
|
||||
}
|
||||
|
||||
// خواندن ACK
|
||||
pinMode(sda_pin, INPUT_PULLUP);
|
||||
i2c_delay();
|
||||
scl_high();
|
||||
i2c_delay();
|
||||
bool ack = !read_sda();
|
||||
scl_low();
|
||||
i2c_delay();
|
||||
|
||||
return ack;
|
||||
}
|
||||
|
||||
uint8_t SoftI2C::read_byte(bool ack) {
|
||||
pinMode(sda_pin, INPUT_PULLUP);
|
||||
uint8_t data = 0;
|
||||
|
||||
for(int i = 7; i >= 0; i--) {
|
||||
scl_high();
|
||||
i2c_delay();
|
||||
if(read_sda()) {
|
||||
data |= (1 << i);
|
||||
}
|
||||
scl_low();
|
||||
i2c_delay();
|
||||
}
|
||||
|
||||
// ارسال ACK/NACK
|
||||
pinMode(sda_pin, OUTPUT);
|
||||
if(ack) {
|
||||
sda_low();
|
||||
} else {
|
||||
sda_high();
|
||||
}
|
||||
i2c_delay();
|
||||
scl_high();
|
||||
i2c_delay();
|
||||
scl_low();
|
||||
i2c_delay();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool SoftI2C::begin_transmission(uint8_t addr) {
|
||||
start_condition();
|
||||
return write_byte(addr << 1); // آدرس + بیت write
|
||||
}
|
||||
|
||||
bool SoftI2C::write(uint8_t data) {
|
||||
return write_byte(data);
|
||||
}
|
||||
|
||||
bool SoftI2C::end_transmission() {
|
||||
stop_condition();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t SoftI2C::request_from(uint8_t addr, uint8_t count) {
|
||||
start_condition();
|
||||
if(!write_byte((addr << 1) | 1)) { // آدرس + بیت read
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t SoftI2C::read() {
|
||||
return read_byte(true);
|
||||
}
|
||||
|
||||
bool SoftI2C::available() {
|
||||
return true;
|
||||
}
|
||||
41
14041130/TestLCD/SoftI2C.hhhh
Normal file
41
14041130/TestLCD/SoftI2C.hhhh
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef SOFTI2C_H
|
||||
#define SOFTI2C_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class SoftI2C {
|
||||
private:
|
||||
uint8_t sda_pin;
|
||||
uint8_t scl_pin;
|
||||
uint32_t delay_us;
|
||||
|
||||
void sda_low() { digitalWrite(sda_pin, LOW); }
|
||||
void sda_high() { digitalWrite(sda_pin, HIGH); }
|
||||
void scl_low() { digitalWrite(scl_pin, LOW); }
|
||||
void scl_high() { digitalWrite(scl_pin, HIGH); }
|
||||
bool read_sda() { return digitalRead(sda_pin); }
|
||||
|
||||
void i2c_delay() { delayMicroseconds(delay_us); }
|
||||
|
||||
void start_condition();
|
||||
void stop_condition();
|
||||
bool write_byte(uint8_t data);
|
||||
uint8_t read_byte(bool ack);
|
||||
bool send_ack();
|
||||
void send_nack();
|
||||
|
||||
public:
|
||||
SoftI2C(uint8_t sda, uint8_t scl, uint32_t freq = 100000);
|
||||
|
||||
void begin();
|
||||
void end();
|
||||
|
||||
bool begin_transmission(uint8_t addr);
|
||||
bool write(uint8_t data);
|
||||
bool end_transmission();
|
||||
uint8_t request_from(uint8_t addr, uint8_t count);
|
||||
uint8_t read();
|
||||
bool available();
|
||||
};
|
||||
|
||||
#endif
|
||||
248
14041130/TestLCD/TestLCD.ino
Normal file
248
14041130/TestLCD/TestLCD.ino
Normal file
@@ -0,0 +1,248 @@
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Fonts/FreeSans9pt7b.h>
|
||||
#include <Fonts/FreeSansBold12pt7b.h>
|
||||
#include <Fonts/FreeSansBold18pt7b.h>
|
||||
//#include <Adafruit_SHT31.h>
|
||||
//#include <BH1750.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// -------------------- فایلهای پروژه --------------------
|
||||
#include "Config.h"
|
||||
#include "Memory.h"
|
||||
#include "Sensors.h"
|
||||
#include "EC200U.h"
|
||||
#include "Display.h"
|
||||
#include "Voltage_Reader.h"
|
||||
#include "BatteryReader.h"
|
||||
|
||||
// -------------------- متغیرهای سراسری --------------------
|
||||
//Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
|
||||
BatteryReader batteryReader(BATTERY_VOLTAGE_PIN_A3); // برای باتری
|
||||
|
||||
//Adafruit_SHT31 sht31 = Adafruit_SHT31();
|
||||
//BH1750 lightMeter;
|
||||
|
||||
SystemStatus i2cStatus = {false, false, 0, 0, 0};
|
||||
|
||||
HardwareSerial EC200U(USART3);
|
||||
SPIClass flashSPI(FLASH_MOSI, FLASH_MISO, FLASH_SCK);
|
||||
|
||||
DeviceConfig config;
|
||||
SensorData currentData;
|
||||
|
||||
// متغیرهای موقت برای پردازش پیامکها
|
||||
String tempPhoneNumber = "";
|
||||
String tempTokenCode = "";
|
||||
bool awaitingSMS2 = false;
|
||||
|
||||
unsigned long lastSensorRead = 0;
|
||||
unsigned long lastUpload = 0;
|
||||
unsigned long lastDisplayChange = 0;
|
||||
unsigned long lastNetworkStatusUpdate = 0;
|
||||
|
||||
Arduino_GC9A01* tft = nullptr;
|
||||
|
||||
bool networkConnected = false;
|
||||
int displayMode = 0;
|
||||
String lastError = "";
|
||||
String currentAPN = "";
|
||||
String lastMessage = "";
|
||||
|
||||
// وضعیت سنسورها و اتصالات
|
||||
bool sht31Connected = false;
|
||||
bool lightSensorConnected = false;
|
||||
bool coSensorConnected = false;
|
||||
bool simConnected = false;
|
||||
bool networkRegistered = false;
|
||||
int signalStrength = 0;
|
||||
|
||||
// متغیرهای CO کالیبراسیون
|
||||
unsigned long systemStartTime = 0;
|
||||
const long calibrationPeriod = 600000; // 10 دقیقه
|
||||
|
||||
//float MQ7_R0 = 10000.0;
|
||||
|
||||
bool isInCall = false;
|
||||
|
||||
|
||||
bool powerState = false;
|
||||
|
||||
|
||||
TwoWire Wire1(1); // I2C1
|
||||
|
||||
|
||||
// -------------------- Setup --------------------
|
||||
void setup() {
|
||||
Serial1.begin(115200);
|
||||
|
||||
pinMode(PWRKEY_PIN, OUTPUT);
|
||||
digitalWrite(PWRKEY_PIN, LOW);
|
||||
|
||||
pinMode(POWER_PIN, INPUT);
|
||||
|
||||
powerState = digitalRead(POWER_PIN) == HIGH;
|
||||
|
||||
delay(1000);
|
||||
|
||||
Serial1.println("\n\n🚀 IoT Device Starting...");
|
||||
|
||||
systemStartTime = millis();
|
||||
|
||||
pinMode(MQ7_PIN, INPUT);
|
||||
initDisplay();
|
||||
initSensors();
|
||||
// Wire1.setSDA(PB9);
|
||||
// Wire1.setSCL(PB8);
|
||||
// Wire1.begin();
|
||||
// //Wire1.setClock(100000);
|
||||
|
||||
// // I2C2 برای BH1750
|
||||
// Wire.setSDA(PB7);
|
||||
// Wire.setSCL(PB6);
|
||||
// Wire.begin();
|
||||
//Wire.setClock(100000);
|
||||
|
||||
// 1. ولتاژ را تست کن
|
||||
bool voltageOK = voltageReader.testCircuit();
|
||||
|
||||
if (!voltageOK) {
|
||||
Serial1.println("⚠️ Voltage issue detected!");
|
||||
}
|
||||
|
||||
// 2. اطلاعات دیباگ ولتاژ
|
||||
voltageReader.debugInfo();
|
||||
|
||||
// 3. خواندن اولیه ولتاژ
|
||||
float initialVoltage = voltageReader.readVoltage();
|
||||
Serial1.print("Initial voltage: ");
|
||||
Serial1.print(initialVoltage, 2);
|
||||
Serial1.println("V");
|
||||
Serial1.println("1");
|
||||
|
||||
/*
|
||||
// Wire = Wire1;
|
||||
sht31Connected = sht31.begin(0x44,&Wire1);
|
||||
Serial1.println("1");
|
||||
Wire.beginTransmission(0x23);
|
||||
uint8_t err = Wire.endTransmission();
|
||||
|
||||
Serial1.print("BH1750 ACK = ");
|
||||
Serial1.println(err);
|
||||
lightSensorConnected = lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23);
|
||||
//lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);
|
||||
Serial1.println("2");
|
||||
*/
|
||||
flashInit();
|
||||
readConfig();
|
||||
|
||||
currentData.batteryVoltage = batteryReader.readVoltage();
|
||||
|
||||
//calibrateMQ7();
|
||||
//setupMQ7();
|
||||
|
||||
awaitingSMS2 = false;
|
||||
tempPhoneNumber = "";
|
||||
tempTokenCode = "";
|
||||
|
||||
readSensors();
|
||||
displayAllParameters();
|
||||
updateDisplay();
|
||||
//--------------------------------
|
||||
|
||||
EC200U.begin(115200);
|
||||
initEC200U();
|
||||
if (config.verified) {
|
||||
Serial1.println("Device ID: " + String(config.deviceId));
|
||||
currentAPN = simTypeToAPN(config.simType);
|
||||
//initEC200U();
|
||||
} else {
|
||||
Serial1.println("⚠️ Not configured - Waiting for SMS");
|
||||
}
|
||||
|
||||
|
||||
updateNetworkStatus();
|
||||
lastNetworkStatusUpdate = millis();
|
||||
|
||||
Serial1.println("✅ Ready - CO calibration: " + String(MQ7sensorPreheated ? "Complete" : "In progress"));
|
||||
|
||||
if (config.verified && networkConnected) {
|
||||
Serial1.println("\n🚀 First upload - sending data immediately...");
|
||||
uploadData();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- Loop --------------------
|
||||
void loop() {
|
||||
if (!isInCall) {
|
||||
digitalWrite(PWRKEY_PIN, LOW);
|
||||
}
|
||||
|
||||
|
||||
checkSMS();
|
||||
|
||||
if (millis() - lastSensorRead > SENSOR_READ_INTERVAL) {
|
||||
//readSensors();
|
||||
readSensors();
|
||||
lastSensorRead=millis();
|
||||
float batteryVoltage = batteryReader.readVoltage();
|
||||
float batteryPercent = batteryReader.getBatteryPercentage();
|
||||
currentData.batteryVoltage=batteryVoltage;
|
||||
currentData.batteryPercent=batteryPercent;
|
||||
|
||||
/*Serial1.print("📊 Battery Voltage: ");
|
||||
Serial1.print(batteryVoltage, 2);
|
||||
Serial1.println("V");*/
|
||||
/*
|
||||
Serial1.print("📊 Battery Percentage: ");
|
||||
Serial1.print(batteryPercent, 2);
|
||||
Serial1.println("%");
|
||||
*/
|
||||
|
||||
float voltage = voltageReader.readVoltage();
|
||||
/**/
|
||||
Serial1.print("📊 System Voltage: ");
|
||||
Serial1.print(voltage, 2);
|
||||
Serial1.println("V");
|
||||
/**/
|
||||
currentData.volage=voltage;
|
||||
|
||||
bool currentPower = digitalRead(POWER_PIN) == HIGH;
|
||||
|
||||
if(currentPower)
|
||||
currentData.power=1;
|
||||
else
|
||||
currentData.power=0;
|
||||
|
||||
if(powerState)
|
||||
currentData.oldPower=1;
|
||||
else
|
||||
currentData.oldPower=0;
|
||||
|
||||
if (currentPower != powerState) {
|
||||
powerState = currentPower;
|
||||
|
||||
if (powerState) {
|
||||
Serial.println("5V Connected");
|
||||
} else {
|
||||
Serial.println("5V Disconnected");
|
||||
}
|
||||
lastUpload -= 86400000L;
|
||||
}
|
||||
powerState = currentPower;
|
||||
|
||||
updateDisplay();
|
||||
unsigned long uploadIntervalMs = config.uploadInterval * 60000UL;
|
||||
if (millis() - lastUpload > uploadIntervalMs) {
|
||||
// Serial1.print("Upload interval reached (");
|
||||
// Serial1.print(config.uploadInterval);
|
||||
// Serial1.println(" min), starting upload...");
|
||||
uploadData();
|
||||
}
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
142
14041130/TestLCD/Voltage_Reader.h
Normal file
142
14041130/TestLCD/Voltage_Reader.h
Normal file
@@ -0,0 +1,142 @@
|
||||
#ifndef VOLTAGE_READER_H
|
||||
#define VOLTAGE_READER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Config.h"
|
||||
|
||||
class VoltageReader {
|
||||
private:
|
||||
float filteredVoltage = 0.0;
|
||||
bool firstReading = true; // فلگ برای اولین خواندن
|
||||
const float alpha = 0.3; // ضریب فیلتر را کمی بیشتر کردم
|
||||
|
||||
public:
|
||||
VoltageReader() {
|
||||
init();
|
||||
}
|
||||
|
||||
void init() {
|
||||
pinMode(VOLTAGE_DIVIDER_PIN, INPUT_ANALOG);
|
||||
analogReadResolution(12); // تنظیم رزولوشن ADC به 12-bit
|
||||
delay(100); // کمی بیشتر صبر کن
|
||||
|
||||
// چند بار خواندن برای تخلیه خازنهای داخلی
|
||||
for (int i = 0; i < 10; i++) {
|
||||
analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
// خواندن ولتاژ بدون فیلتر
|
||||
float readRawVoltage() {
|
||||
int samples = 32; // تعداد نمونهها را بیشتر کردم
|
||||
long sum = 0;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
sum += analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
delayMicroseconds(20);
|
||||
}
|
||||
|
||||
int rawValue = sum / samples;
|
||||
|
||||
// تبدیل به ولتاژ
|
||||
float voltageAtPin = (rawValue * ADC_REF_VOLTAGE) / ADC_RESOLUTION;
|
||||
|
||||
// محاسبه ولتاژ اصلی
|
||||
float actualVoltage = voltageAtPin * VOLTAGE_DIVIDER_RATIO;
|
||||
|
||||
return actualVoltage;
|
||||
}
|
||||
|
||||
// خواندن با فیلتر
|
||||
float readVoltage() {
|
||||
float currentVoltage = readRawVoltage();
|
||||
|
||||
// اگر اولین بار است، فیلتر را با مقدار فعلی مقداردهی کن
|
||||
if (firstReading) {
|
||||
filteredVoltage = currentVoltage;
|
||||
firstReading = false;
|
||||
} else {
|
||||
// اعمال فیلتر Low-pass
|
||||
filteredVoltage = (alpha * currentVoltage) + ((1 - alpha) * filteredVoltage);
|
||||
}
|
||||
|
||||
return currentVoltage; // actual voltage برمیگردانیم
|
||||
}
|
||||
|
||||
// دریافت ولتاژ فیلتر شده
|
||||
float getFilteredVoltage() {
|
||||
return filteredVoltage;
|
||||
}
|
||||
|
||||
// تست سلامت مدار
|
||||
bool testCircuit() {
|
||||
Serial1.println("\n🔌 Testing voltage divider circuit...");
|
||||
|
||||
// چند بار خواندن برای اطمینان
|
||||
float sum = 0;
|
||||
int readings = 10;
|
||||
|
||||
for (int i = 0; i < readings; i++) {
|
||||
sum += readRawVoltage();
|
||||
delay(50);
|
||||
}
|
||||
|
||||
float avgVoltage = sum / readings;
|
||||
|
||||
Serial1.print("Average voltage: ");
|
||||
Serial1.print(avgVoltage, 2);
|
||||
Serial1.println("V");
|
||||
|
||||
Serial1.print("Raw ADC value: ");
|
||||
Serial1.println(analogRead(VOLTAGE_DIVIDER_PIN));
|
||||
|
||||
// ولتاژ در پین
|
||||
float pinVoltage = avgVoltage / VOLTAGE_DIVIDER_RATIO;
|
||||
Serial1.print("Voltage at PA0 pin: ");
|
||||
Serial1.print(pinVoltage, 2);
|
||||
Serial1.println("V");
|
||||
|
||||
if (avgVoltage > 4.5 && avgVoltage < 5.5) {
|
||||
Serial1.println("✅ Circuit OK (within expected 5V ±10%)");
|
||||
return true;
|
||||
} else {
|
||||
Serial1.print("❌ Expected ~5V, got ");
|
||||
Serial1.print(avgVoltage, 2);
|
||||
Serial1.println("V");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// نمایش اطلاعات دیباگ
|
||||
void debugInfo() {
|
||||
float rawVoltage = readRawVoltage();
|
||||
int rawADC = analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
float pinVoltage = rawVoltage / VOLTAGE_DIVIDER_RATIO;
|
||||
|
||||
Serial1.println("\n📊 Voltage Debug Info:");
|
||||
Serial1.print("Raw ADC value: ");
|
||||
Serial1.println(rawADC);
|
||||
Serial1.print("Voltage at PA0 pin: ");
|
||||
Serial1.print(pinVoltage, 3);
|
||||
Serial1.println("V");
|
||||
Serial1.print("Actual voltage (raw): ");
|
||||
Serial1.print(rawVoltage, 3);
|
||||
Serial1.println("V");
|
||||
Serial1.print("Filtered voltage: ");
|
||||
Serial1.print(filteredVoltage, 3);
|
||||
Serial1.println("V");
|
||||
}
|
||||
|
||||
// ریست فیلتر
|
||||
void resetFilter() {
|
||||
filteredVoltage = 0.0;
|
||||
firstReading = true;
|
||||
Serial1.println("✅ Voltage filter reset");
|
||||
}
|
||||
};
|
||||
|
||||
// ایجاد نمونه سراسری
|
||||
VoltageReader voltageReader;
|
||||
|
||||
#endif // VOLTAGE_READER_H
|
||||
290
14041130/TestLCD/fonts/FreeSansBold12pt7b.h
Normal file
290
14041130/TestLCD/fonts/FreeSansBold12pt7b.h
Normal file
@@ -0,0 +1,290 @@
|
||||
#pragma once
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
const uint8_t FreeSansBold12pt7bBitmaps[] PROGMEM = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x76, 0x66, 0x60, 0xFF, 0xF0, 0xF3, 0xFC, 0xFF,
|
||||
0x3F, 0xCF, 0x61, 0x98, 0x60, 0x0E, 0x70, 0x73, 0x83, 0x18, 0xFF, 0xF7,
|
||||
0xFF, 0xBF, 0xFC, 0x73, 0x83, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFD, 0xFF,
|
||||
0xE3, 0x18, 0x39, 0xC1, 0xCE, 0x0E, 0x70, 0x02, 0x00, 0x7E, 0x0F, 0xF8,
|
||||
0x7F, 0xE7, 0xAF, 0xB9, 0x3D, 0xC8, 0x0F, 0x40, 0x3F, 0x00, 0xFF, 0x00,
|
||||
0xFC, 0x05, 0xFF, 0x27, 0xF9, 0x3F, 0xEB, 0xEF, 0xFE, 0x3F, 0xE0, 0x7C,
|
||||
0x00, 0x80, 0x04, 0x00, 0x3C, 0x06, 0x0F, 0xC1, 0x81, 0xFC, 0x30, 0x73,
|
||||
0x8C, 0x0C, 0x31, 0x81, 0xCE, 0x60, 0x1F, 0xCC, 0x03, 0xF3, 0x00, 0x3C,
|
||||
0x67, 0x80, 0x19, 0xF8, 0x02, 0x7F, 0x80, 0xCE, 0x70, 0x11, 0x86, 0x06,
|
||||
0x39, 0xC1, 0x87, 0xF8, 0x30, 0x7E, 0x0C, 0x07, 0x80, 0x07, 0x80, 0x1F,
|
||||
0xC0, 0x3F, 0xE0, 0x3C, 0xE0, 0x3C, 0xE0, 0x3E, 0xE0, 0x0F, 0xC0, 0x07,
|
||||
0x00, 0x3F, 0x8C, 0x7F, 0xCC, 0xF1, 0xFC, 0xF0, 0xF8, 0xF0, 0x78, 0xF8,
|
||||
0xF8, 0x7F, 0xFC, 0x3F, 0xDE, 0x1F, 0x8E, 0xFF, 0xFF, 0x66, 0x0C, 0x73,
|
||||
0x8E, 0x71, 0xC7, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x1C, 0x71, 0xC3,
|
||||
0x8E, 0x18, 0x70, 0xC3, 0x87, 0x1C, 0x38, 0xE3, 0x87, 0x1C, 0x71, 0xC7,
|
||||
0x1C, 0x71, 0xCE, 0x38, 0xE7, 0x1C, 0x63, 0x80, 0x10, 0x23, 0x5F, 0xF3,
|
||||
0x87, 0x1B, 0x14, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x0F, 0xFF, 0xFF, 0xFF,
|
||||
0xF8, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x00, 0xFF, 0xF3, 0x36, 0xC0, 0xFF,
|
||||
0xFF, 0xC0, 0xFF, 0xF0, 0x0C, 0x30, 0x86, 0x18, 0x61, 0x0C, 0x30, 0xC2,
|
||||
0x18, 0x61, 0x84, 0x30, 0xC0, 0x1F, 0x83, 0xFC, 0x7F, 0xE7, 0x9E, 0xF0,
|
||||
0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0,
|
||||
0xF7, 0x9E, 0x7F, 0xE3, 0xFC, 0x0F, 0x00, 0x06, 0x1C, 0x7F, 0xFF, 0xE3,
|
||||
0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x1F, 0x83,
|
||||
0xFC, 0x7F, 0xEF, 0x9F, 0xF0, 0xFF, 0x0F, 0x00, 0xF0, 0x0F, 0x01, 0xE0,
|
||||
0x3C, 0x0F, 0x81, 0xE0, 0x3C, 0x03, 0x80, 0x7F, 0xF7, 0xFF, 0x7F, 0xF0,
|
||||
0x1F, 0x07, 0xFC, 0xFF, 0xEF, 0x1E, 0xF1, 0xE0, 0x1E, 0x03, 0xC0, 0x78,
|
||||
0x07, 0xC0, 0x1E, 0x00, 0xF0, 0x0F, 0xF0, 0xFF, 0x1F, 0x7F, 0xE7, 0xFC,
|
||||
0x1F, 0x80, 0x03, 0xC0, 0xF8, 0x1F, 0x07, 0xE1, 0xBC, 0x27, 0x8C, 0xF3,
|
||||
0x1E, 0x63, 0xD8, 0x7B, 0xFF, 0xFF, 0xFF, 0xFE, 0x07, 0x80, 0xF0, 0x1E,
|
||||
0x03, 0xC0, 0x3F, 0xE7, 0xFE, 0x7F, 0xE7, 0x00, 0x60, 0x06, 0xF8, 0x7F,
|
||||
0xCF, 0xFE, 0xF1, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFE, 0x1E, 0xFF,
|
||||
0xE7, 0xFC, 0x3F, 0x00, 0x0F, 0x83, 0xFC, 0x7F, 0xE7, 0x9F, 0xF0, 0x0F,
|
||||
0x78, 0xFF, 0xCF, 0xFE, 0xF9, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xF7,
|
||||
0x9F, 0x7F, 0xE3, 0xFC, 0x0F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xE0,
|
||||
0x1C, 0x07, 0x01, 0xE0, 0x38, 0x0F, 0x01, 0xC0, 0x78, 0x0F, 0x01, 0xE0,
|
||||
0x38, 0x0F, 0x01, 0xE0, 0x3C, 0x00, 0x0F, 0x03, 0xFC, 0x7F, 0xC7, 0x9E,
|
||||
0x70, 0xE7, 0x0E, 0x39, 0xC1, 0xF8, 0x3F, 0xC7, 0x9E, 0xF0, 0xFF, 0x0F,
|
||||
0xF0, 0xFF, 0x9F, 0x7F, 0xE3, 0xFC, 0x1F, 0x80, 0x1F, 0x03, 0xFC, 0x7F,
|
||||
0xEF, 0x9E, 0xF0, 0xEF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF9, 0xF7, 0xFF, 0x3F,
|
||||
0xF1, 0xEF, 0x00, 0xEF, 0x1E, 0x7F, 0xE7, 0xFC, 0x1F, 0x00, 0xFF, 0xF0,
|
||||
0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0x11, 0x6C,
|
||||
0x00, 0x10, 0x07, 0x03, 0xF1, 0xFC, 0x7E, 0x0F, 0x80, 0xE0, 0x0F, 0xC0,
|
||||
0x3F, 0x80, 0x7F, 0x00, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0E, 0x00, 0xFC,
|
||||
0x07, 0xF0, 0x0F, 0xE0, 0x1F, 0x00, 0xF0, 0x7F, 0x1F, 0x8F, 0xE0, 0xF0,
|
||||
0x08, 0x00, 0x1F, 0x07, 0xFC, 0x7F, 0xEF, 0x9F, 0xF0, 0xFF, 0x0F, 0x00,
|
||||
0xF0, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x0E, 0x00, 0xE0, 0x00,
|
||||
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x00, 0xFE, 0x00, 0x1F, 0xFC, 0x03, 0xC0,
|
||||
0xF0, 0x38, 0x01, 0xC3, 0x80, 0x07, 0x18, 0x3D, 0x99, 0x87, 0xEC, 0x6C,
|
||||
0x71, 0xC3, 0xC3, 0x06, 0x1E, 0x18, 0x30, 0xF1, 0x81, 0x87, 0x8C, 0x18,
|
||||
0x7C, 0x60, 0xC3, 0x63, 0x8E, 0x3B, 0x8F, 0xDF, 0x8C, 0x3C, 0xF0, 0x70,
|
||||
0x00, 0x01, 0xC0, 0x00, 0x07, 0x80, 0x80, 0x1F, 0xFE, 0x00, 0x1F, 0xC0,
|
||||
0x00, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x07, 0xF0, 0x07, 0xF0, 0x07,
|
||||
0x70, 0x0F, 0x78, 0x0E, 0x78, 0x0E, 0x38, 0x1E, 0x3C, 0x1C, 0x3C, 0x3F,
|
||||
0xFC, 0x3F, 0xFE, 0x3F, 0xFE, 0x78, 0x0E, 0x78, 0x0F, 0x70, 0x0F, 0xF0,
|
||||
0x07, 0xFF, 0xC3, 0xFF, 0xCF, 0xFF, 0x3C, 0x3E, 0xF0, 0x7B, 0xC1, 0xEF,
|
||||
0x0F, 0xBF, 0xFC, 0xFF, 0xE3, 0xFF, 0xCF, 0x07, 0xBC, 0x0F, 0xF0, 0x3F,
|
||||
0xC0, 0xFF, 0x07, 0xFF, 0xFE, 0xFF, 0xFB, 0xFF, 0x80, 0x07, 0xE0, 0x1F,
|
||||
0xF8, 0x3F, 0xFC, 0x7C, 0x3E, 0x78, 0x1F, 0xF8, 0x0F, 0xF0, 0x00, 0xF0,
|
||||
0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF8, 0x0F, 0x78,
|
||||
0x1F, 0x7C, 0x3E, 0x3F, 0xFE, 0x1F, 0xFC, 0x07, 0xF0, 0xFF, 0xE1, 0xFF,
|
||||
0xE3, 0xFF, 0xE7, 0x83, 0xEF, 0x03, 0xDE, 0x07, 0xFC, 0x07, 0xF8, 0x0F,
|
||||
0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0xFF, 0x03, 0xFE, 0x07, 0xBC,
|
||||
0x1F, 0x7F, 0xFC, 0xFF, 0xF1, 0xFF, 0x80, 0xFF, 0xF7, 0xFF, 0xBF, 0xFD,
|
||||
0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFC, 0xFF, 0xE7, 0xFF, 0x3C,
|
||||
0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
|
||||
0xFE, 0xFF, 0xEF, 0xFE, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
|
||||
0x00, 0xF0, 0x0F, 0x00, 0x03, 0xF0, 0x0F, 0xFC, 0x3F, 0xFE, 0x3E, 0x1F,
|
||||
0x78, 0x07, 0x78, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x7F, 0xF0, 0x7F,
|
||||
0xF0, 0x7F, 0xF0, 0x07, 0x78, 0x07, 0x7C, 0x0F, 0x3E, 0x1F, 0x3F, 0xFB,
|
||||
0x0F, 0xFB, 0x03, 0xE3, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0,
|
||||
0x3F, 0xC0, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFC,
|
||||
0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xF0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xE0, 0x3C,
|
||||
0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07,
|
||||
0xF8, 0xFF, 0x1F, 0xE3, 0xFC, 0x7B, 0xFE, 0x7F, 0xC3, 0xE0, 0xF0, 0x3E,
|
||||
0xF0, 0x3C, 0xF0, 0x78, 0xF0, 0xF0, 0xF1, 0xE0, 0xF3, 0xC0, 0xF7, 0x80,
|
||||
0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0xFB, 0xC0, 0xF1, 0xE0, 0xF0, 0xF0,
|
||||
0xF0, 0xF0, 0xF0, 0x78, 0xF0, 0x3C, 0xF0, 0x3E, 0xF0, 0x1E, 0xF0, 0x1E,
|
||||
0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03,
|
||||
0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xFF, 0xFF, 0xFF, 0xFC, 0xF8,
|
||||
0x1F, 0xFE, 0x0F, 0xFF, 0x0F, 0xFF, 0x87, 0xFF, 0xC3, 0xFF, 0xE1, 0xFF,
|
||||
0xF9, 0xFF, 0xFC, 0xEF, 0xFE, 0x77, 0xFB, 0x3B, 0xFD, 0xDD, 0xFE, 0xFC,
|
||||
0xFF, 0x7E, 0x7F, 0x9F, 0x3F, 0xCF, 0x9F, 0xE7, 0x8F, 0xF3, 0xC7, 0xF8,
|
||||
0xE3, 0xC0, 0xF0, 0x1F, 0xF0, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xE1, 0xFF,
|
||||
0xC3, 0xFD, 0xC7, 0xFB, 0x8F, 0xF3, 0x9F, 0xE7, 0x3F, 0xC7, 0x7F, 0x8F,
|
||||
0xFF, 0x0F, 0xFE, 0x1F, 0xFC, 0x1F, 0xF8, 0x1F, 0xF0, 0x3F, 0xE0, 0x3C,
|
||||
0x03, 0xE0, 0x0F, 0xFC, 0x0F, 0xFF, 0x87, 0xC7, 0xC7, 0x80, 0xF3, 0xC0,
|
||||
0x7B, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE,
|
||||
0x00, 0xF7, 0x80, 0xF3, 0xC0, 0x78, 0xF0, 0xF8, 0x7F, 0xFC, 0x1F, 0xFC,
|
||||
0x03, 0xF8, 0x00, 0xFF, 0xE3, 0xFF, 0xEF, 0xFF, 0xBC, 0x1F, 0xF0, 0x3F,
|
||||
0xC0, 0xFF, 0x03, 0xFC, 0x1F, 0xFF, 0xFB, 0xFF, 0xCF, 0xFE, 0x3C, 0x00,
|
||||
0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x00, 0x03,
|
||||
0xE0, 0x0F, 0xFC, 0x0F, 0xFF, 0x87, 0xC7, 0xC7, 0x80, 0xF3, 0xC0, 0x7B,
|
||||
0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE, 0x04,
|
||||
0xF7, 0x87, 0xF3, 0xC3, 0xF8, 0xF0, 0xF8, 0x7F, 0xFC, 0x1F, 0xFF, 0x83,
|
||||
0xF1, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0xFC, 0xF0, 0x3E,
|
||||
0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x3C, 0xFF, 0xF8, 0xFF, 0xF0,
|
||||
0xFF, 0xF8, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x3C,
|
||||
0xF0, 0x3C, 0xF0, 0x1F, 0x0F, 0xC0, 0x7F, 0xE1, 0xFF, 0xE7, 0xC3, 0xEF,
|
||||
0x03, 0xDE, 0x00, 0x3C, 0x00, 0x7F, 0x00, 0x7F, 0xF0, 0x3F, 0xF8, 0x0F,
|
||||
0xF8, 0x01, 0xF0, 0x01, 0xFE, 0x03, 0xDE, 0x0F, 0xBF, 0xFE, 0x3F, 0xF8,
|
||||
0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
|
||||
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
|
||||
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F,
|
||||
0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03,
|
||||
0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xF7, 0x87, 0x9F, 0xFE, 0x3F, 0xF0, 0x3F,
|
||||
0x00, 0x70, 0x0E, 0xF0, 0x3D, 0xE0, 0x79, 0xC0, 0xE3, 0x81, 0xC7, 0x87,
|
||||
0x87, 0x0E, 0x0E, 0x1C, 0x1E, 0x78, 0x1C, 0xE0, 0x39, 0xC0, 0x73, 0x80,
|
||||
0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x70,
|
||||
0x38, 0x1C, 0xE0, 0xF0, 0x79, 0xE1, 0xF0, 0xF3, 0xC3, 0xE1, 0xE3, 0x87,
|
||||
0xC3, 0x87, 0x0F, 0x87, 0x0E, 0x3B, 0x9E, 0x1E, 0x77, 0x38, 0x1C, 0xEE,
|
||||
0x70, 0x39, 0xCC, 0xE0, 0x73, 0x99, 0xC0, 0x6E, 0x3F, 0x00, 0xFC, 0x7E,
|
||||
0x01, 0xF8, 0xFC, 0x03, 0xF0, 0xF8, 0x03, 0xE1, 0xE0, 0x07, 0x83, 0xC0,
|
||||
0x0F, 0x07, 0x80, 0xF0, 0x3C, 0xF0, 0xF9, 0xE1, 0xE1, 0xE7, 0x83, 0xCF,
|
||||
0x03, 0xFC, 0x03, 0xF0, 0x07, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x3F, 0x00,
|
||||
0xFF, 0x01, 0xFE, 0x07, 0x9E, 0x0F, 0x1E, 0x3C, 0x3C, 0xF8, 0x3D, 0xE0,
|
||||
0x78, 0xF0, 0x1E, 0x78, 0x1E, 0x78, 0x3C, 0x3C, 0x3C, 0x3C, 0x78, 0x1E,
|
||||
0x78, 0x0E, 0x70, 0x0F, 0xF0, 0x07, 0xE0, 0x07, 0xE0, 0x03, 0xC0, 0x03,
|
||||
0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03,
|
||||
0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
|
||||
0x00, 0xF8, 0x07, 0x80, 0x78, 0x07, 0x80, 0x7C, 0x03, 0xC0, 0x3C, 0x03,
|
||||
0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFC, 0xF3, 0xCF,
|
||||
0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0xFF,
|
||||
0xC0, 0xC1, 0x81, 0x03, 0x06, 0x04, 0x0C, 0x18, 0x10, 0x30, 0x60, 0x40,
|
||||
0xC1, 0x81, 0x03, 0x06, 0xFF, 0xFF, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3,
|
||||
0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0xFF, 0xFF, 0xC0, 0x0F, 0x00,
|
||||
0xF0, 0x0F, 0x01, 0xF8, 0x1B, 0x83, 0x9C, 0x39, 0xC3, 0x0C, 0x70, 0xE7,
|
||||
0x0E, 0xE0, 0x70, 0xFF, 0xFF, 0xFF, 0xFC, 0xE6, 0x30, 0x1F, 0x83, 0xFF,
|
||||
0x1F, 0xFD, 0xE1, 0xE0, 0x0F, 0x03, 0xF9, 0xFF, 0xDF, 0x1E, 0xF0, 0xF7,
|
||||
0x8F, 0xBF, 0xFC, 0xFF, 0xE3, 0xCF, 0x80, 0xF0, 0x07, 0x80, 0x3C, 0x01,
|
||||
0xE0, 0x0F, 0x00, 0x7B, 0xC3, 0xFF, 0x9F, 0xFE, 0xF8, 0xF7, 0x83, 0xFC,
|
||||
0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xE3, 0xDF, 0xFE, 0xFF, 0xE7, 0xBE,
|
||||
0x00, 0x0F, 0x83, 0xFE, 0x7F, 0xF7, 0x8F, 0xF0, 0x7F, 0x00, 0xF0, 0x0F,
|
||||
0x00, 0xF0, 0x77, 0x8F, 0x7F, 0xF3, 0xFE, 0x0F, 0x80, 0x00, 0x78, 0x03,
|
||||
0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x8F, 0xBC, 0xFF, 0xEF, 0xFF, 0x78, 0xFF,
|
||||
0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3D, 0xE3, 0xEF, 0xFF, 0x3F,
|
||||
0xF8, 0xFB, 0xC0, 0x1F, 0x81, 0xFE, 0x1F, 0xF9, 0xF1, 0xCF, 0x07, 0x7F,
|
||||
0xFB, 0xFF, 0xDE, 0x00, 0xF0, 0x03, 0xC3, 0x9F, 0xFC, 0x7F, 0xC0, 0xF8,
|
||||
0x00, 0x3E, 0xFD, 0xFB, 0xC7, 0x9F, 0xBF, 0x3C, 0x78, 0xF1, 0xE3, 0xC7,
|
||||
0x8F, 0x1E, 0x3C, 0x78, 0xF0, 0x1E, 0x79, 0xFB, 0xDF, 0xFE, 0xF1, 0xFF,
|
||||
0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC7, 0xDF, 0xFE, 0x7F,
|
||||
0xF1, 0xF7, 0x80, 0x3C, 0x01, 0xFF, 0x1E, 0x7F, 0xF0, 0xFE, 0x00, 0xF0,
|
||||
0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x7C, 0xFF, 0xEF, 0xFF, 0xF9,
|
||||
0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0,
|
||||
0xFF, 0x0F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C,
|
||||
0xF3, 0xC0, 0x00, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C,
|
||||
0xF3, 0xCF, 0xFF, 0xFF, 0x80, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0,
|
||||
0x0F, 0x0F, 0xF1, 0xEF, 0x3C, 0xF7, 0x8F, 0xF0, 0xFF, 0x0F, 0xF8, 0xFF,
|
||||
0x8F, 0x3C, 0xF1, 0xCF, 0x1E, 0xF0, 0xEF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x8F, 0x9F, 0xFB, 0xFB, 0xFF, 0xFF,
|
||||
0xFC, 0xF8, 0xFF, 0x1E, 0x1F, 0xE3, 0xC3, 0xFC, 0x78, 0x7F, 0x8F, 0x0F,
|
||||
0xF1, 0xE1, 0xFE, 0x3C, 0x3F, 0xC7, 0x87, 0xF8, 0xF0, 0xFF, 0x1E, 0x1E,
|
||||
0xF7, 0xCF, 0xFE, 0xFF, 0xFF, 0x9F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F,
|
||||
0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xF0, 0x0F, 0x81, 0xFF, 0x1F,
|
||||
0xFC, 0xF1, 0xEF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7B, 0xC7,
|
||||
0x9F, 0xFC, 0x7F, 0xC0, 0xF8, 0x00, 0xF7, 0xC7, 0xFF, 0x3F, 0xFD, 0xF1,
|
||||
0xEF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC7, 0xBF, 0xFD,
|
||||
0xFF, 0xCF, 0x78, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x00,
|
||||
0x0F, 0x79, 0xFF, 0xDF, 0xFE, 0xF1, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE,
|
||||
0x0F, 0xF0, 0x7B, 0xC7, 0xDF, 0xFE, 0x7F, 0xF1, 0xF7, 0x80, 0x3C, 0x01,
|
||||
0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0xF3, 0xF7, 0xFF, 0xF8, 0xF0, 0xF0,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x1F, 0x87, 0xFC, 0xFF, 0xEF,
|
||||
0x0F, 0xF8, 0x0F, 0xF0, 0x7F, 0xE0, 0xFF, 0x01, 0xFF, 0x0F, 0xFF, 0xE7,
|
||||
0xFE, 0x1F, 0x80, 0x79, 0xE7, 0xBF, 0xFD, 0xE7, 0x9E, 0x79, 0xE7, 0x9E,
|
||||
0x7D, 0xF3, 0xC0, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F,
|
||||
0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x1F, 0xFF, 0xF7, 0xFF, 0x3E, 0xF0, 0xF0,
|
||||
0x7B, 0x83, 0x9E, 0x1C, 0xF1, 0xE3, 0x8E, 0x1C, 0x70, 0x77, 0x83, 0xB8,
|
||||
0x1D, 0xC0, 0x7E, 0x03, 0xE0, 0x1F, 0x00, 0x70, 0x00, 0xF0, 0xE1, 0xDC,
|
||||
0x78, 0x77, 0x1F, 0x3D, 0xE7, 0xCF, 0x79, 0xB3, 0x8E, 0x6C, 0xE3, 0xBB,
|
||||
0x38, 0xEE, 0xFC, 0x1F, 0x3F, 0x07, 0xC7, 0xC1, 0xF1, 0xF0, 0x7C, 0x78,
|
||||
0x0E, 0x1E, 0x00, 0x78, 0xF3, 0xC7, 0x8F, 0x78, 0x3B, 0x81, 0xFC, 0x07,
|
||||
0xC0, 0x1E, 0x01, 0xF0, 0x1F, 0xC0, 0xEF, 0x0F, 0x78, 0xF1, 0xE7, 0x87,
|
||||
0x00, 0xF0, 0x7B, 0x83, 0x9E, 0x1C, 0x71, 0xE3, 0x8E, 0x1E, 0x70, 0x73,
|
||||
0x83, 0xB8, 0x1F, 0xC0, 0x7E, 0x03, 0xE0, 0x0F, 0x00, 0x70, 0x03, 0x80,
|
||||
0x3C, 0x07, 0xC0, 0x3E, 0x01, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F,
|
||||
0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0x1C, 0xF3, 0xCE, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0xBC, 0xF0, 0xE3, 0x8E,
|
||||
0x38, 0xE3, 0x8E, 0x3C, 0xF1, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||
0xE3, 0x8F, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x0F, 0x3D, 0xC7, 0x1C,
|
||||
0x71, 0xC7, 0x1C, 0xF3, 0xCE, 0x00, 0x78, 0x0F, 0xE0, 0xCF, 0x30, 0x7F,
|
||||
0x01, 0xE0};
|
||||
|
||||
const GFXglyph FreeSansBold12pt7bGlyphs[] PROGMEM = {
|
||||
{0, 0, 0, 7, 0, 1}, // 0x20 ' '
|
||||
{0, 4, 17, 8, 3, -16}, // 0x21 '!'
|
||||
{9, 10, 6, 11, 1, -17}, // 0x22 '"'
|
||||
{17, 13, 16, 13, 0, -15}, // 0x23 '#'
|
||||
{43, 13, 20, 13, 0, -17}, // 0x24 '$'
|
||||
{76, 19, 17, 21, 1, -16}, // 0x25 '%'
|
||||
{117, 16, 17, 17, 1, -16}, // 0x26 '&'
|
||||
{151, 4, 6, 6, 1, -17}, // 0x27 '''
|
||||
{154, 6, 22, 8, 1, -17}, // 0x28 '('
|
||||
{171, 6, 22, 8, 1, -17}, // 0x29 ')'
|
||||
{188, 7, 8, 9, 1, -17}, // 0x2A '*'
|
||||
{195, 11, 11, 14, 2, -10}, // 0x2B '+'
|
||||
{211, 4, 7, 6, 1, -2}, // 0x2C ','
|
||||
{215, 6, 3, 8, 1, -7}, // 0x2D '-'
|
||||
{218, 4, 3, 6, 1, -2}, // 0x2E '.'
|
||||
{220, 6, 17, 7, 0, -16}, // 0x2F '/'
|
||||
{233, 12, 17, 13, 1, -16}, // 0x30 '0'
|
||||
{259, 7, 17, 14, 3, -16}, // 0x31 '1'
|
||||
{274, 12, 17, 13, 1, -16}, // 0x32 '2'
|
||||
{300, 12, 17, 13, 1, -16}, // 0x33 '3'
|
||||
{326, 11, 17, 13, 1, -16}, // 0x34 '4'
|
||||
{350, 12, 17, 13, 1, -16}, // 0x35 '5'
|
||||
{376, 12, 17, 13, 1, -16}, // 0x36 '6'
|
||||
{402, 11, 17, 13, 1, -16}, // 0x37 '7'
|
||||
{426, 12, 17, 13, 1, -16}, // 0x38 '8'
|
||||
{452, 12, 17, 13, 1, -16}, // 0x39 '9'
|
||||
{478, 4, 12, 6, 1, -11}, // 0x3A ':'
|
||||
{484, 4, 16, 6, 1, -11}, // 0x3B ';'
|
||||
{492, 12, 12, 14, 1, -11}, // 0x3C '<'
|
||||
{510, 12, 9, 14, 1, -9}, // 0x3D '='
|
||||
{524, 12, 12, 14, 1, -11}, // 0x3E '>'
|
||||
{542, 12, 18, 15, 2, -17}, // 0x3F '?'
|
||||
{569, 21, 21, 23, 1, -17}, // 0x40 '@'
|
||||
{625, 16, 18, 17, 0, -17}, // 0x41 'A'
|
||||
{661, 14, 18, 17, 2, -17}, // 0x42 'B'
|
||||
{693, 16, 18, 17, 1, -17}, // 0x43 'C'
|
||||
{729, 15, 18, 17, 2, -17}, // 0x44 'D'
|
||||
{763, 13, 18, 16, 2, -17}, // 0x45 'E'
|
||||
{793, 12, 18, 15, 2, -17}, // 0x46 'F'
|
||||
{820, 16, 18, 18, 1, -17}, // 0x47 'G'
|
||||
{856, 14, 18, 18, 2, -17}, // 0x48 'H'
|
||||
{888, 4, 18, 7, 2, -17}, // 0x49 'I'
|
||||
{897, 11, 18, 14, 1, -17}, // 0x4A 'J'
|
||||
{922, 16, 18, 17, 2, -17}, // 0x4B 'K'
|
||||
{958, 11, 18, 15, 2, -17}, // 0x4C 'L'
|
||||
{983, 17, 18, 21, 2, -17}, // 0x4D 'M'
|
||||
{1022, 15, 18, 18, 2, -17}, // 0x4E 'N'
|
||||
{1056, 17, 18, 19, 1, -17}, // 0x4F 'O'
|
||||
{1095, 14, 18, 16, 2, -17}, // 0x50 'P'
|
||||
{1127, 17, 19, 19, 1, -17}, // 0x51 'Q'
|
||||
{1168, 16, 18, 17, 2, -17}, // 0x52 'R'
|
||||
{1204, 15, 18, 16, 1, -17}, // 0x53 'S'
|
||||
{1238, 12, 18, 15, 2, -17}, // 0x54 'T'
|
||||
{1265, 14, 18, 18, 2, -17}, // 0x55 'U'
|
||||
{1297, 15, 18, 16, 0, -17}, // 0x56 'V'
|
||||
{1331, 23, 18, 23, 0, -17}, // 0x57 'W'
|
||||
{1383, 15, 18, 16, 1, -17}, // 0x58 'X'
|
||||
{1417, 16, 18, 15, 0, -17}, // 0x59 'Y'
|
||||
{1453, 13, 18, 15, 1, -17}, // 0x5A 'Z'
|
||||
{1483, 6, 23, 8, 2, -17}, // 0x5B '['
|
||||
{1501, 7, 17, 7, 0, -16}, // 0x5C '\'
|
||||
{1516, 6, 23, 8, 0, -17}, // 0x5D ']'
|
||||
{1534, 12, 11, 14, 1, -16}, // 0x5E '^'
|
||||
{1551, 15, 2, 13, -1, 4}, // 0x5F '_'
|
||||
{1555, 4, 3, 6, 0, -17}, // 0x60 '`'
|
||||
{1557, 13, 13, 14, 1, -12}, // 0x61 'a'
|
||||
{1579, 13, 18, 15, 2, -17}, // 0x62 'b'
|
||||
{1609, 12, 13, 13, 1, -12}, // 0x63 'c'
|
||||
{1629, 13, 18, 15, 1, -17}, // 0x64 'd'
|
||||
{1659, 13, 13, 14, 1, -12}, // 0x65 'e'
|
||||
{1681, 7, 18, 8, 1, -17}, // 0x66 'f'
|
||||
{1697, 13, 18, 15, 1, -12}, // 0x67 'g'
|
||||
{1727, 12, 18, 14, 2, -17}, // 0x68 'h'
|
||||
{1754, 4, 18, 7, 2, -17}, // 0x69 'i'
|
||||
{1763, 6, 23, 7, 0, -17}, // 0x6A 'j'
|
||||
{1781, 12, 18, 14, 2, -17}, // 0x6B 'k'
|
||||
{1808, 4, 18, 6, 2, -17}, // 0x6C 'l'
|
||||
{1817, 19, 13, 21, 2, -12}, // 0x6D 'm'
|
||||
{1848, 12, 13, 15, 2, -12}, // 0x6E 'n'
|
||||
{1868, 13, 13, 15, 1, -12}, // 0x6F 'o'
|
||||
{1890, 13, 18, 15, 2, -12}, // 0x70 'p'
|
||||
{1920, 13, 18, 15, 1, -12}, // 0x71 'q'
|
||||
{1950, 8, 13, 9, 2, -12}, // 0x72 'r'
|
||||
{1963, 12, 13, 13, 1, -12}, // 0x73 's'
|
||||
{1983, 6, 15, 8, 1, -14}, // 0x74 't'
|
||||
{1995, 12, 13, 15, 2, -12}, // 0x75 'u'
|
||||
{2015, 13, 13, 13, 0, -12}, // 0x76 'v'
|
||||
{2037, 18, 13, 19, 0, -12}, // 0x77 'w'
|
||||
{2067, 13, 13, 13, 0, -12}, // 0x78 'x'
|
||||
{2089, 13, 18, 13, 0, -12}, // 0x79 'y'
|
||||
{2119, 10, 13, 12, 1, -12}, // 0x7A 'z'
|
||||
{2136, 6, 23, 9, 1, -17}, // 0x7B '{'
|
||||
{2154, 2, 22, 7, 2, -17}, // 0x7C '|'
|
||||
{2160, 6, 23, 9, 3, -17}, // 0x7D '}'
|
||||
{2178, 12, 5, 12, 0, -7}}; // 0x7E '~'
|
||||
|
||||
const GFXfont FreeSansBold12pt7b PROGMEM = {
|
||||
(uint8_t *)FreeSansBold12pt7bBitmaps, (GFXglyph *)FreeSansBold12pt7bGlyphs,
|
||||
0x20, 0x7E, 29};
|
||||
|
||||
// Approx. 2858 bytes
|
||||
210
14041130/TestLCD/fonts/FreeSansBold9pt7b.h
Normal file
210
14041130/TestLCD/fonts/FreeSansBold9pt7b.h
Normal file
@@ -0,0 +1,210 @@
|
||||
#pragma once
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
const uint8_t FreeSansBold9pt7bBitmaps[] PROGMEM = {
|
||||
0xFF, 0xFF, 0xFE, 0x48, 0x7E, 0xEF, 0xDF, 0xBF, 0x74, 0x40, 0x19, 0x86,
|
||||
0x67, 0xFD, 0xFF, 0x33, 0x0C, 0xC3, 0x33, 0xFE, 0xFF, 0x99, 0x86, 0x61,
|
||||
0x90, 0x10, 0x1F, 0x1F, 0xDE, 0xFF, 0x3F, 0x83, 0xC0, 0xFC, 0x1F, 0x09,
|
||||
0xFC, 0xFE, 0xF7, 0xF1, 0xE0, 0x40, 0x38, 0x10, 0x7C, 0x30, 0xC6, 0x20,
|
||||
0xC6, 0x40, 0xC6, 0x40, 0x7C, 0x80, 0x39, 0x9C, 0x01, 0x3E, 0x03, 0x63,
|
||||
0x02, 0x63, 0x04, 0x63, 0x0C, 0x3E, 0x08, 0x1C, 0x0E, 0x01, 0xF8, 0x3B,
|
||||
0x83, 0xB8, 0x3F, 0x01, 0xE0, 0x3E, 0x67, 0x76, 0xE3, 0xEE, 0x1C, 0xF3,
|
||||
0xC7, 0xFE, 0x3F, 0x70, 0xFF, 0xF4, 0x18, 0x63, 0x1C, 0x73, 0x8E, 0x38,
|
||||
0xE3, 0x8E, 0x18, 0x70, 0xC3, 0x06, 0x08, 0x61, 0x83, 0x0E, 0x38, 0x71,
|
||||
0xC7, 0x1C, 0x71, 0xC6, 0x38, 0xE3, 0x18, 0x40, 0x21, 0x3E, 0x45, 0x28,
|
||||
0x38, 0x70, 0xE7, 0xFF, 0xE7, 0x0E, 0x1C, 0xFC, 0x9C, 0xFF, 0xC0, 0xFC,
|
||||
0x08, 0xC4, 0x23, 0x10, 0x84, 0x62, 0x11, 0x88, 0x00, 0x3E, 0x3F, 0x9D,
|
||||
0xDC, 0x7E, 0x3F, 0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xDD, 0xCF, 0xE3, 0xE0,
|
||||
0x08, 0xFF, 0xF3, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x80, 0x3E, 0x3F, 0xB8,
|
||||
0xFC, 0x70, 0x38, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x0F, 0xF7, 0xF8,
|
||||
0x3C, 0x7F, 0xE7, 0xE7, 0x07, 0x0C, 0x0E, 0x07, 0x07, 0xE7, 0xE7, 0x7E,
|
||||
0x3C, 0x0E, 0x1E, 0x1E, 0x2E, 0x2E, 0x4E, 0x4E, 0x8E, 0xFF, 0xFF, 0x0E,
|
||||
0x0E, 0x0E, 0x7F, 0x3F, 0x90, 0x18, 0x0D, 0xE7, 0xFB, 0x9E, 0x07, 0x03,
|
||||
0x81, 0xF1, 0xFF, 0xE7, 0xC0, 0x3E, 0x3F, 0x9C, 0xFC, 0x0E, 0xE7, 0xFB,
|
||||
0xDF, 0xC7, 0xE3, 0xF1, 0xDD, 0xEF, 0xE3, 0xE0, 0xFF, 0xFF, 0xC0, 0xE0,
|
||||
0xE0, 0x60, 0x70, 0x30, 0x38, 0x1C, 0x0C, 0x0E, 0x07, 0x03, 0x80, 0x3F,
|
||||
0x1F, 0xEE, 0x3F, 0x87, 0xE3, 0xCF, 0xC7, 0xFB, 0xCF, 0xE1, 0xF8, 0x7F,
|
||||
0x3D, 0xFE, 0x3F, 0x00, 0x3E, 0x3F, 0xBD, 0xDC, 0x7E, 0x3F, 0x1F, 0xDE,
|
||||
0xFF, 0x3B, 0x81, 0xF9, 0xCF, 0xE3, 0xC0, 0xFC, 0x00, 0x07, 0xE0, 0xFC,
|
||||
0x00, 0x07, 0xE5, 0xE0, 0x00, 0x83, 0xC7, 0xDF, 0x0C, 0x07, 0x80, 0xF8,
|
||||
0x1F, 0x01, 0x80, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x70,
|
||||
0x3F, 0x03, 0xE0, 0x38, 0x7D, 0xF1, 0xE0, 0x80, 0x00, 0x3E, 0x3F, 0xB8,
|
||||
0xFC, 0x70, 0x38, 0x1C, 0x1C, 0x1C, 0x1C, 0x0E, 0x00, 0x03, 0x81, 0xC0,
|
||||
0x03, 0xF0, 0x0F, 0xFC, 0x1E, 0x0E, 0x38, 0x02, 0x70, 0xE9, 0x63, 0x19,
|
||||
0xC2, 0x19, 0xC6, 0x11, 0xC6, 0x33, 0xC6, 0x32, 0x63, 0xFE, 0x73, 0xDC,
|
||||
0x3C, 0x00, 0x1F, 0xF8, 0x07, 0xF0, 0x07, 0x00, 0xF0, 0x0F, 0x80, 0xF8,
|
||||
0x1D, 0x81, 0x9C, 0x19, 0xC3, 0x8C, 0x3F, 0xE7, 0xFE, 0x70, 0x66, 0x07,
|
||||
0xE0, 0x70, 0xFF, 0x9F, 0xFB, 0x83, 0xF0, 0x7E, 0x0F, 0xFF, 0x3F, 0xF7,
|
||||
0x06, 0xE0, 0xFC, 0x1F, 0x83, 0xFF, 0xEF, 0xF8, 0x1F, 0x83, 0xFE, 0x78,
|
||||
0xE7, 0x07, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x07, 0x07, 0x78,
|
||||
0xF3, 0xFE, 0x1F, 0x80, 0xFF, 0x8F, 0xFC, 0xE0, 0xEE, 0x0E, 0xE0, 0x7E,
|
||||
0x07, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x0E, 0xE0, 0xEF, 0xFC, 0xFF, 0x80,
|
||||
0xFF, 0xFF, 0xF8, 0x1C, 0x0E, 0x07, 0xFB, 0xFD, 0xC0, 0xE0, 0x70, 0x38,
|
||||
0x1F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF8, 0x1C, 0x0E, 0x07, 0xFB, 0xFD, 0xC0,
|
||||
0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x00, 0x0F, 0x87, 0xF9, 0xE3, 0xB8, 0x3E,
|
||||
0x01, 0xC0, 0x38, 0xFF, 0x1F, 0xE0, 0x6E, 0x0D, 0xE3, 0x9F, 0xD0, 0xF2,
|
||||
0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xFF, 0xFF, 0xFF, 0x07, 0xE0,
|
||||
0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xE7, 0xE7, 0xE7, 0x7E, 0x3C,
|
||||
0xE0, 0xEE, 0x1C, 0xE3, 0x8E, 0x70, 0xEE, 0x0F, 0xC0, 0xFE, 0x0F, 0x70,
|
||||
0xE7, 0x0E, 0x38, 0xE1, 0xCE, 0x0E, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
|
||||
0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xFF, 0xFF, 0xF8, 0x7F, 0xE1,
|
||||
0xFF, 0x87, 0xFE, 0x1F, 0xEC, 0x7F, 0xB3, 0x7E, 0xCD, 0xFB, 0x37, 0xEC,
|
||||
0xDF, 0x9E, 0x7E, 0x79, 0xF9, 0xE7, 0xE7, 0x9C, 0xE0, 0xFE, 0x1F, 0xC3,
|
||||
0xFC, 0x7F, 0xCF, 0xD9, 0xFB, 0xBF, 0x37, 0xE7, 0xFC, 0x7F, 0x87, 0xF0,
|
||||
0xFE, 0x0E, 0x0F, 0x81, 0xFF, 0x1E, 0x3C, 0xE0, 0xEE, 0x03, 0xF0, 0x1F,
|
||||
0x80, 0xFC, 0x07, 0xE0, 0x3B, 0x83, 0x9E, 0x3C, 0x7F, 0xC0, 0xF8, 0x00,
|
||||
0xFF, 0x9F, 0xFB, 0x87, 0xF0, 0x7E, 0x0F, 0xC3, 0xFF, 0xF7, 0xFC, 0xE0,
|
||||
0x1C, 0x03, 0x80, 0x70, 0x0E, 0x00, 0x0F, 0x81, 0xFF, 0x1E, 0x3C, 0xE0,
|
||||
0xEE, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE1, 0xBB, 0x8F, 0x9E, 0x3C,
|
||||
0x7F, 0xE0, 0xFB, 0x80, 0x08, 0xFF, 0x8F, 0xFC, 0xE0, 0xEE, 0x0E, 0xE0,
|
||||
0xEE, 0x0E, 0xFF, 0xCF, 0xFC, 0xE0, 0xEE, 0x0E, 0xE0, 0xEE, 0x0E, 0xE0,
|
||||
0xF0, 0x3F, 0x0F, 0xFB, 0xC7, 0xF0, 0x7E, 0x01, 0xFC, 0x1F, 0xF0, 0x3F,
|
||||
0x00, 0xFC, 0x1D, 0xC7, 0xBF, 0xE1, 0xF8, 0xFF, 0xFF, 0xC7, 0x03, 0x81,
|
||||
0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0xFC,
|
||||
0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F,
|
||||
0xC7, 0xBF, 0xE1, 0xF0, 0x60, 0x67, 0x0E, 0x70, 0xE3, 0x0C, 0x30, 0xC3,
|
||||
0x9C, 0x19, 0x81, 0x98, 0x1F, 0x80, 0xF0, 0x0F, 0x00, 0xF0, 0x06, 0x00,
|
||||
0x61, 0xC3, 0xB8, 0xE1, 0x9C, 0x70, 0xCE, 0x3C, 0xE3, 0x36, 0x71, 0x9B,
|
||||
0x30, 0xED, 0x98, 0x36, 0x7C, 0x1B, 0x3C, 0x0F, 0x1E, 0x07, 0x8F, 0x01,
|
||||
0xC3, 0x80, 0xE1, 0x80, 0x70, 0xE7, 0x8E, 0x39, 0xC1, 0xF8, 0x1F, 0x80,
|
||||
0xF0, 0x07, 0x00, 0xF0, 0x1F, 0x81, 0x9C, 0x39, 0xC7, 0x0E, 0x70, 0xE0,
|
||||
0xE0, 0xFC, 0x39, 0xC7, 0x18, 0xC3, 0xB8, 0x36, 0x07, 0xC0, 0x70, 0x0E,
|
||||
0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0xFF, 0xFF, 0xC0, 0xE0, 0xE0, 0xF0,
|
||||
0x70, 0x70, 0x70, 0x78, 0x38, 0x38, 0x1F, 0xFF, 0xF8, 0xFF, 0xEE, 0xEE,
|
||||
0xEE, 0xEE, 0xEE, 0xEE, 0xEF, 0xF0, 0x86, 0x10, 0x86, 0x10, 0x84, 0x30,
|
||||
0x84, 0x30, 0x80, 0xFF, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x7F, 0xF0,
|
||||
0x18, 0x1C, 0x3C, 0x3E, 0x36, 0x66, 0x63, 0xC3, 0xFF, 0xC0, 0xCC, 0x3F,
|
||||
0x1F, 0xEE, 0x38, 0x0E, 0x3F, 0x9E, 0xEE, 0x3B, 0x9E, 0xFF, 0x9E, 0xE0,
|
||||
0xE0, 0x38, 0x0E, 0x03, 0xBC, 0xFF, 0xBC, 0xEE, 0x1F, 0x87, 0xE1, 0xF8,
|
||||
0x7F, 0x3B, 0xFE, 0xEF, 0x00, 0x1F, 0x3F, 0xDC, 0x7C, 0x0E, 0x07, 0x03,
|
||||
0x80, 0xE3, 0x7F, 0x8F, 0x00, 0x03, 0x81, 0xC0, 0xE7, 0x77, 0xFB, 0xBF,
|
||||
0x8F, 0xC7, 0xE3, 0xF1, 0xFD, 0xEF, 0xF3, 0xB8, 0x3E, 0x3F, 0x9C, 0xDC,
|
||||
0x3F, 0xFF, 0xFF, 0x81, 0xC3, 0x7F, 0x8F, 0x00, 0x3B, 0xDD, 0xFF, 0xB9,
|
||||
0xCE, 0x73, 0x9C, 0xE7, 0x00, 0x3B, 0xBF, 0xDD, 0xFC, 0x7E, 0x3F, 0x1F,
|
||||
0x8F, 0xEF, 0x7F, 0x9D, 0xC0, 0xFC, 0x77, 0xF1, 0xF0, 0xE0, 0x70, 0x38,
|
||||
0x1D, 0xEF, 0xFF, 0x9F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0xFC, 0x7E, 0x38,
|
||||
0xFC, 0x7F, 0xFF, 0xFF, 0xFE, 0x77, 0x07, 0x77, 0x77, 0x77, 0x77, 0x77,
|
||||
0x7F, 0xE0, 0xE0, 0x70, 0x38, 0x1C, 0x7E, 0x77, 0x73, 0xF1, 0xF8, 0xFE,
|
||||
0x77, 0x39, 0xDC, 0x6E, 0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0x7B,
|
||||
0xFF, 0xFE, 0x39, 0xF8, 0xE7, 0xE3, 0x9F, 0x8E, 0x7E, 0x39, 0xF8, 0xE7,
|
||||
0xE3, 0x9F, 0x8E, 0x70, 0xEF, 0x7F, 0xF8, 0xFC, 0x7E, 0x3F, 0x1F, 0x8F,
|
||||
0xC7, 0xE3, 0xF1, 0xC0, 0x1E, 0x1F, 0xE7, 0x3B, 0x87, 0xE1, 0xF8, 0x7E,
|
||||
0x1D, 0xCE, 0x7F, 0x87, 0x80, 0xEF, 0x3F, 0xEF, 0x3B, 0x87, 0xE1, 0xF8,
|
||||
0x7E, 0x1F, 0xCE, 0xFF, 0xBB, 0xCE, 0x03, 0x80, 0xE0, 0x38, 0x00, 0x3B,
|
||||
0xBF, 0xFD, 0xFC, 0x7E, 0x3F, 0x1F, 0x8F, 0xEF, 0x7F, 0x9D, 0xC0, 0xE0,
|
||||
0x70, 0x38, 0x1C, 0xEF, 0xFF, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x80, 0x3E,
|
||||
0x3F, 0xB8, 0xFC, 0x0F, 0xC3, 0xFC, 0x3F, 0xC7, 0xFF, 0x1F, 0x00, 0x73,
|
||||
0xBF, 0xF7, 0x39, 0xCE, 0x73, 0x9E, 0x70, 0xE3, 0xF1, 0xF8, 0xFC, 0x7E,
|
||||
0x3F, 0x1F, 0x8F, 0xC7, 0xFF, 0xBD, 0xC0, 0xE1, 0x98, 0x67, 0x39, 0xCC,
|
||||
0x33, 0x0D, 0xC3, 0xE0, 0x78, 0x1E, 0x07, 0x00, 0xE3, 0x1D, 0x9E, 0x66,
|
||||
0x79, 0x99, 0xE6, 0x77, 0xB8, 0xD2, 0xC3, 0xCF, 0x0F, 0x3C, 0x3C, 0xF0,
|
||||
0x73, 0x80, 0x73, 0x9C, 0xE3, 0xF0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0xFC,
|
||||
0x73, 0x9C, 0xE0, 0xE1, 0xD8, 0x67, 0x39, 0xCE, 0x33, 0x0E, 0xC3, 0xE0,
|
||||
0x78, 0x1E, 0x03, 0x00, 0xC0, 0x70, 0x38, 0x0E, 0x00, 0xFE, 0xFE, 0x0E,
|
||||
0x1C, 0x38, 0x38, 0x70, 0xE0, 0xFF, 0xFF, 0x37, 0x66, 0x66, 0x6E, 0xE6,
|
||||
0x66, 0x66, 0x67, 0x30, 0xFF, 0xFF, 0x80, 0xCE, 0x66, 0x66, 0x67, 0x76,
|
||||
0x66, 0x66, 0x6E, 0xC0, 0x71, 0x8E};
|
||||
|
||||
const GFXglyph FreeSansBold9pt7bGlyphs[] PROGMEM = {
|
||||
{0, 0, 0, 5, 0, 1}, // 0x20 ' '
|
||||
{0, 3, 13, 6, 2, -12}, // 0x21 '!'
|
||||
{5, 7, 5, 9, 1, -12}, // 0x22 '"'
|
||||
{10, 10, 12, 10, 0, -11}, // 0x23 '#'
|
||||
{25, 9, 15, 10, 1, -13}, // 0x24 '$'
|
||||
{42, 16, 13, 16, 0, -12}, // 0x25 '%'
|
||||
{68, 12, 13, 13, 1, -12}, // 0x26 '&'
|
||||
{88, 3, 5, 5, 1, -12}, // 0x27 '''
|
||||
{90, 6, 17, 6, 1, -12}, // 0x28 '('
|
||||
{103, 6, 17, 6, 0, -12}, // 0x29 ')'
|
||||
{116, 5, 6, 7, 1, -12}, // 0x2A '*'
|
||||
{120, 7, 8, 11, 2, -7}, // 0x2B '+'
|
||||
{127, 3, 5, 4, 1, -1}, // 0x2C ','
|
||||
{129, 5, 2, 6, 0, -5}, // 0x2D '-'
|
||||
{131, 3, 2, 4, 1, -1}, // 0x2E '.'
|
||||
{132, 5, 13, 5, 0, -12}, // 0x2F '/'
|
||||
{141, 9, 13, 10, 1, -12}, // 0x30 '0'
|
||||
{156, 5, 13, 10, 2, -12}, // 0x31 '1'
|
||||
{165, 9, 13, 10, 1, -12}, // 0x32 '2'
|
||||
{180, 8, 13, 10, 1, -12}, // 0x33 '3'
|
||||
{193, 8, 13, 10, 2, -12}, // 0x34 '4'
|
||||
{206, 9, 13, 10, 1, -12}, // 0x35 '5'
|
||||
{221, 9, 13, 10, 1, -12}, // 0x36 '6'
|
||||
{236, 9, 13, 10, 0, -12}, // 0x37 '7'
|
||||
{251, 10, 13, 10, 0, -12}, // 0x38 '8'
|
||||
{268, 9, 13, 10, 1, -12}, // 0x39 '9'
|
||||
{283, 3, 9, 4, 1, -8}, // 0x3A ':'
|
||||
{287, 3, 12, 4, 1, -8}, // 0x3B ';'
|
||||
{292, 9, 9, 11, 1, -8}, // 0x3C '<'
|
||||
{303, 9, 6, 11, 1, -6}, // 0x3D '='
|
||||
{310, 9, 9, 11, 1, -8}, // 0x3E '>'
|
||||
{321, 9, 13, 11, 1, -12}, // 0x3F '?'
|
||||
{336, 16, 15, 18, 0, -12}, // 0x40 '@'
|
||||
{366, 12, 13, 13, 0, -12}, // 0x41 'A'
|
||||
{386, 11, 13, 13, 1, -12}, // 0x42 'B'
|
||||
{404, 12, 13, 13, 1, -12}, // 0x43 'C'
|
||||
{424, 12, 13, 13, 1, -12}, // 0x44 'D'
|
||||
{444, 9, 13, 12, 1, -12}, // 0x45 'E'
|
||||
{459, 9, 13, 11, 1, -12}, // 0x46 'F'
|
||||
{474, 11, 13, 14, 1, -12}, // 0x47 'G'
|
||||
{492, 11, 13, 13, 1, -12}, // 0x48 'H'
|
||||
{510, 3, 13, 6, 1, -12}, // 0x49 'I'
|
||||
{515, 8, 13, 10, 1, -12}, // 0x4A 'J'
|
||||
{528, 12, 13, 13, 1, -12}, // 0x4B 'K'
|
||||
{548, 8, 13, 11, 1, -12}, // 0x4C 'L'
|
||||
{561, 14, 13, 16, 1, -12}, // 0x4D 'M'
|
||||
{584, 11, 13, 14, 1, -12}, // 0x4E 'N'
|
||||
{602, 13, 13, 14, 1, -12}, // 0x4F 'O'
|
||||
{624, 11, 13, 12, 1, -12}, // 0x50 'P'
|
||||
{642, 13, 14, 14, 1, -12}, // 0x51 'Q'
|
||||
{665, 12, 13, 13, 1, -12}, // 0x52 'R'
|
||||
{685, 11, 13, 12, 1, -12}, // 0x53 'S'
|
||||
{703, 9, 13, 12, 2, -12}, // 0x54 'T'
|
||||
{718, 11, 13, 13, 1, -12}, // 0x55 'U'
|
||||
{736, 12, 13, 12, 0, -12}, // 0x56 'V'
|
||||
{756, 17, 13, 17, 0, -12}, // 0x57 'W'
|
||||
{784, 12, 13, 12, 0, -12}, // 0x58 'X'
|
||||
{804, 11, 13, 12, 1, -12}, // 0x59 'Y'
|
||||
{822, 9, 13, 11, 1, -12}, // 0x5A 'Z'
|
||||
{837, 4, 17, 6, 1, -12}, // 0x5B '['
|
||||
{846, 5, 13, 5, 0, -12}, // 0x5C '\'
|
||||
{855, 4, 17, 6, 0, -12}, // 0x5D ']'
|
||||
{864, 8, 8, 11, 1, -12}, // 0x5E '^'
|
||||
{872, 10, 1, 10, 0, 4}, // 0x5F '_'
|
||||
{874, 3, 2, 5, 0, -12}, // 0x60 '`'
|
||||
{875, 10, 10, 10, 1, -9}, // 0x61 'a'
|
||||
{888, 10, 13, 11, 1, -12}, // 0x62 'b'
|
||||
{905, 9, 10, 10, 1, -9}, // 0x63 'c'
|
||||
{917, 9, 13, 11, 1, -12}, // 0x64 'd'
|
||||
{932, 9, 10, 10, 1, -9}, // 0x65 'e'
|
||||
{944, 5, 13, 6, 1, -12}, // 0x66 'f'
|
||||
{953, 9, 14, 11, 1, -9}, // 0x67 'g'
|
||||
{969, 9, 13, 11, 1, -12}, // 0x68 'h'
|
||||
{984, 3, 13, 5, 1, -12}, // 0x69 'i'
|
||||
{989, 4, 17, 5, 0, -12}, // 0x6A 'j'
|
||||
{998, 9, 13, 10, 1, -12}, // 0x6B 'k'
|
||||
{1013, 3, 13, 5, 1, -12}, // 0x6C 'l'
|
||||
{1018, 14, 10, 16, 1, -9}, // 0x6D 'm'
|
||||
{1036, 9, 10, 11, 1, -9}, // 0x6E 'n'
|
||||
{1048, 10, 10, 11, 1, -9}, // 0x6F 'o'
|
||||
{1061, 10, 14, 11, 1, -9}, // 0x70 'p'
|
||||
{1079, 9, 14, 11, 1, -9}, // 0x71 'q'
|
||||
{1095, 6, 10, 7, 1, -9}, // 0x72 'r'
|
||||
{1103, 9, 10, 10, 1, -9}, // 0x73 's'
|
||||
{1115, 5, 12, 6, 1, -11}, // 0x74 't'
|
||||
{1123, 9, 10, 11, 1, -9}, // 0x75 'u'
|
||||
{1135, 10, 10, 10, 0, -9}, // 0x76 'v'
|
||||
{1148, 14, 10, 14, 0, -9}, // 0x77 'w'
|
||||
{1166, 10, 10, 10, 0, -9}, // 0x78 'x'
|
||||
{1179, 10, 14, 10, 0, -9}, // 0x79 'y'
|
||||
{1197, 8, 10, 9, 1, -9}, // 0x7A 'z'
|
||||
{1207, 4, 17, 7, 1, -12}, // 0x7B '{'
|
||||
{1216, 1, 17, 5, 2, -12}, // 0x7C '|'
|
||||
{1219, 4, 17, 7, 2, -12}, // 0x7D '}'
|
||||
{1228, 8, 2, 9, 0, -4}}; // 0x7E '~'
|
||||
|
||||
const GFXfont FreeSansBold9pt7b PROGMEM = {(uint8_t *)FreeSansBold9pt7bBitmaps,
|
||||
(GFXglyph *)FreeSansBold9pt7bGlyphs,
|
||||
0x20, 0x7E, 22};
|
||||
|
||||
// Approx. 1902 bytes
|
||||
475
14041130/TestProgram/TestEcu/EC200U-Call.h
Normal file
475
14041130/TestProgram/TestEcu/EC200U-Call.h
Normal file
@@ -0,0 +1,475 @@
|
||||
#ifndef EC200U_AUDIOCALL_H
|
||||
#define EC200U_AUDIOCALL_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// -------------------- تعریف USART3 --------------------
|
||||
HardwareSerial EC200U(USART3);
|
||||
|
||||
// -------------------- تنظیمات --------------------
|
||||
const char* AUDIO_FILE_PATH = "UFS:output.amr";
|
||||
String APN = "mcinet"; // اگر نیاز است تنظیم شود
|
||||
|
||||
// -------------------- تابع ارسال AT --------------------
|
||||
String sendATCommand(String cmd, uint16_t timeout = 5000, bool showCmd = false, bool showResponse = false) {
|
||||
if (showCmd) {
|
||||
Serial1.print(">> ");
|
||||
Serial1.println(cmd);
|
||||
}
|
||||
|
||||
EC200U.println(cmd);
|
||||
|
||||
String response = "";
|
||||
unsigned long start = millis();
|
||||
bool gotOk = false;
|
||||
bool gotError = false;
|
||||
|
||||
while (millis() - start < timeout) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
if (showResponse) Serial1.write(c);
|
||||
}
|
||||
|
||||
if (response.indexOf("OK") != -1) gotOk = true;
|
||||
if (response.indexOf("ERROR") != -1) gotError = true;
|
||||
|
||||
// برای دستورات خاص، منتظر نشانههای دیگر هم باشیم
|
||||
if (response.indexOf("CONNECT") != -1) break;
|
||||
if (response.indexOf("+QHTTPGET:") != -1) break;
|
||||
if (response.indexOf("+QHTTPREADFILE:") != -1) break;
|
||||
|
||||
if (gotOk || gotError) break;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
// -------------------- راهاندازی اینترنت --------------------
|
||||
bool setupInternet() {
|
||||
Serial1.println("\n🌐 راهاندازی اتصال اینترنت");
|
||||
Serial1.println("==========================");
|
||||
|
||||
// 1. تنظیم APN (اگر نیاز است)
|
||||
if (APN.length() > 0) {
|
||||
Serial1.print("[1] تنظیم APN... ");
|
||||
String cmd = "AT+QICSGP=1,1,\"" + APN + "\",\"\",\"\",1";
|
||||
if (sendATCommand(cmd, 5000, false).indexOf("OK") == -1) {
|
||||
Serial1.println("FAIL");
|
||||
return false;
|
||||
}
|
||||
Serial1.println("OK");
|
||||
}
|
||||
|
||||
// 2. فعالسازی زمینه PDP
|
||||
Serial1.print("[2] فعالسازی PDP... ");
|
||||
if (sendATCommand("AT+QIACT=1", 30000, false).indexOf("OK") == -1) {
|
||||
Serial1.println("FAIL - سعی میکنیم از حالت فعلی استفاده کنیم");
|
||||
} else {
|
||||
Serial1.println("OK");
|
||||
}
|
||||
|
||||
// 3. بررسی وضعیت اتصال
|
||||
Serial1.print("[3] بررسی اتصال... ");
|
||||
String resp = sendATCommand("AT+QIACT?", 2000, false);
|
||||
if (resp.indexOf("+QIACT:") != -1) {
|
||||
Serial1.println("CONNECTED");
|
||||
return true;
|
||||
} else {
|
||||
Serial1.println("NO CONNECTION");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- دانلود فایل صوتی از URL --------------------
|
||||
// -------------------- دانلود فایل صوتی از URL --------------------
|
||||
bool downloadAudioFile(String url) {
|
||||
Serial1.println("\n📥 دانلود فایل صوتی");
|
||||
Serial1.println("===================");
|
||||
|
||||
// 1. پاک کردن فایل قدیمی اگر وجود دارد
|
||||
Serial1.print("[1] پاک کردن فایل قدیمی... ");
|
||||
sendATCommand("AT+QFDEL=\"UFS:audio.amr\"", 2000, false);
|
||||
Serial1.println("OK");
|
||||
|
||||
delay(100);
|
||||
|
||||
// 2. تنظیم URL
|
||||
Serial1.print("[2] تنظیم URL... ");
|
||||
int urlLen = url.length();
|
||||
String cmd = "AT+QHTTPURL=" + String(urlLen) + ",80";
|
||||
|
||||
EC200U.println(cmd);
|
||||
|
||||
String response = "";
|
||||
unsigned long start = millis();
|
||||
bool gotConnect = false;
|
||||
|
||||
while (millis() - start < 5000) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
}
|
||||
if (response.indexOf("CONNECT") != -1) {
|
||||
gotConnect = true;
|
||||
break;
|
||||
}
|
||||
if (response.indexOf("ERROR") != -1) {
|
||||
Serial1.println("FAIL - خطای QHTTPURL");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gotConnect) {
|
||||
Serial1.println("FAIL - CONNECT دریافت نشد");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ارسال URL
|
||||
EC200U.print(url);
|
||||
delay(1000);
|
||||
|
||||
response = "";
|
||||
start = millis();
|
||||
while (millis() - start < 3000) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
}
|
||||
if (response.indexOf("OK") != -1) break;
|
||||
}
|
||||
|
||||
if (response.indexOf("OK") == -1) {
|
||||
Serial1.println("FAIL - URL پذیرفته نشد");
|
||||
return false;
|
||||
}
|
||||
Serial1.println("OK");
|
||||
|
||||
// 3. دانلود فایل
|
||||
Serial1.print("[3] دانلود فایل... ");
|
||||
EC200U.println("AT+QHTTPGET=60"); // 60 ثانیه تایماوت
|
||||
|
||||
response = "";
|
||||
start = millis();
|
||||
bool httpSuccess = false;
|
||||
int httpCode = 0;
|
||||
|
||||
while (millis() - start < 65000) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
Serial1.write(c);
|
||||
}
|
||||
|
||||
int qhttpIdx = response.indexOf("+QHTTPGET:");
|
||||
if (qhttpIdx != -1) {
|
||||
String afterQhttp = response.substring(qhttpIdx);
|
||||
int firstComma = afterQhttp.indexOf(',');
|
||||
int secondComma = afterQhttp.indexOf(',', firstComma + 1);
|
||||
|
||||
if (firstComma != -1 && secondComma != -1) {
|
||||
int errorCode = afterQhttp.substring(11, firstComma).toInt();
|
||||
httpCode = afterQhttp.substring(firstComma + 1, secondComma).toInt();
|
||||
|
||||
Serial1.print("کد خطا: ");
|
||||
Serial1.print(errorCode);
|
||||
Serial1.print(", کد HTTP: ");
|
||||
Serial1.print(httpCode);
|
||||
|
||||
if (errorCode == 0 && httpCode >= 200 && httpCode < 300) {
|
||||
httpSuccess = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.indexOf("ERROR") != -1) {
|
||||
Serial1.println("\n❌ HTTP GET ناموفق");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!httpSuccess) {
|
||||
Serial1.println("FAIL");
|
||||
Serial1.print(" کد HTTP: ");
|
||||
Serial1.println(httpCode);
|
||||
return false;
|
||||
}
|
||||
Serial1.println("OK");
|
||||
|
||||
delay(500);
|
||||
// پاک کردن بافر
|
||||
while (EC200U.available()) EC200U.read();
|
||||
|
||||
// 4. ذخیره فایل
|
||||
Serial1.print("[4] ذخیره فایل... ");
|
||||
EC200U.println("AT+QHTTPREADFILE=\"UFS:audio.amr\",80");
|
||||
|
||||
response = "";
|
||||
start = millis();
|
||||
bool saveSuccess = false;
|
||||
|
||||
while (millis() - start < 60000) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
Serial1.write(c);
|
||||
}
|
||||
|
||||
if (response.indexOf("+QHTTPREADFILE: 0") != -1) {
|
||||
saveSuccess = true;
|
||||
break;
|
||||
}
|
||||
if (response.indexOf("ERROR") != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (saveSuccess) {
|
||||
Serial1.println("OK");
|
||||
Serial1.println("✅ فایل صوتی دانلود و ذخیره شد");
|
||||
return true;
|
||||
} else {
|
||||
Serial1.println("FAIL");
|
||||
Serial1.println("❌ ذخیره فایل ناموفق");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- بررسی وضعیت تماس --------------------
|
||||
int getCallState() {
|
||||
EC200U.println("AT+CLCC");
|
||||
delay(300);
|
||||
|
||||
String response = "";
|
||||
unsigned long start = millis();
|
||||
while (millis() - start < 2000) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.indexOf("+CLCC: 0,0,0,0,0") != -1) return 0; // Active
|
||||
if (response.indexOf("+CLCC: 0,0,2,0,0") != -1) return 2; // Dialing
|
||||
if (response.indexOf("+CLCC: 0,0,3,0,0") != -1) return 3; // Ringing
|
||||
if (response.indexOf("NO CARRIER") != -1) return -2; // Disconnected
|
||||
if (response.indexOf("BUSY") != -1) return -3; // Busy
|
||||
|
||||
return -1; // Unknown
|
||||
}
|
||||
|
||||
// -------------------- تابع اصلی تماس و پخش --------------------
|
||||
bool callAndPlayAudio(String phoneNumber) {
|
||||
Serial1.println("\n📞 تماس و پخش فایل صوتی");
|
||||
Serial1.println("========================");
|
||||
|
||||
// 1. برقراری تماس
|
||||
Serial1.print("[1] برقراری تماس... ");
|
||||
String dialCmd = "ATD" + phoneNumber + ";";
|
||||
String resp = sendATCommand(dialCmd, 10000, false, true);
|
||||
|
||||
if (resp.indexOf("OK") == -1 && resp.indexOf("ERROR") != -1) {
|
||||
Serial1.println("FAIL");
|
||||
return false;
|
||||
}
|
||||
Serial1.println("OK");
|
||||
|
||||
// 2. منتظر پاسخ
|
||||
Serial1.print("[2] منتظر پاسخ تماس... ");
|
||||
unsigned long start = millis();
|
||||
bool callConnected = false;
|
||||
|
||||
while (millis() - start < 45000) { // 45 ثانیه منتظر بمان
|
||||
int callState = getCallState();
|
||||
|
||||
switch (callState) {
|
||||
case 0: // Active
|
||||
callConnected = true;
|
||||
Serial1.println("CONNECTED");
|
||||
break;
|
||||
case 2: // Dialing
|
||||
Serial1.print(".");
|
||||
break;
|
||||
case 3: // Ringing
|
||||
Serial1.print("R");
|
||||
break;
|
||||
case -2: // Disconnected
|
||||
Serial1.println("DISCONNECTED");
|
||||
return false;
|
||||
case -3: // Busy
|
||||
Serial1.println("BUSY");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (callConnected) break;
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
if (!callConnected) {
|
||||
Serial1.println("NO ANSWER");
|
||||
sendATCommand("ATH", 2000, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
delay(1000); // کمی صبر بعد از اتصال
|
||||
|
||||
// 3. پخش فایل صوتی
|
||||
Serial1.print("[3] شروع پخش صدا... ");
|
||||
|
||||
// ابتدا حالت پخش را تنظیم کن
|
||||
resp = sendATCommand("AT+QVTCMD=1,0,\"UFS:output.amr\"", 5000, false, true);
|
||||
|
||||
if (resp.indexOf("OK") == -1) {
|
||||
Serial1.println("FAIL - تنظیم پخش");
|
||||
Serial1.println(" پاسخ: " + resp);
|
||||
sendATCommand("ATH", 2000, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// شروع پخش
|
||||
resp = sendATCommand("AT+QVTCMD=3,0", 3000, false, true);
|
||||
|
||||
if (resp.indexOf("OK") == -1) {
|
||||
Serial1.println("FAIL - شروع پخش");
|
||||
sendATCommand("ATH", 2000, false);
|
||||
return false;
|
||||
}
|
||||
Serial1.println("OK");
|
||||
|
||||
// 4. منتظر اتمام پخش
|
||||
Serial1.println("[4] در حال پخش... ");
|
||||
|
||||
bool playbackComplete = false;
|
||||
start = millis();
|
||||
|
||||
while (millis() - start < 120000) { // حداکثر 2 دقیقه
|
||||
// بررسی وضعیت پخش
|
||||
EC200U.println("AT+QVTSTAT?");
|
||||
delay(500);
|
||||
|
||||
String statusResp = "";
|
||||
unsigned long statusStart = millis();
|
||||
while (millis() - statusStart < 2000) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
statusResp += c;
|
||||
}
|
||||
}
|
||||
|
||||
// اگر پخش تمام شده
|
||||
if (statusResp.indexOf("+QVTSTAT: 0,0") != -1) {
|
||||
playbackComplete = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// بررسی وضعیت تماس
|
||||
if (getCallState() != 0) {
|
||||
Serial1.println(" تماس قطع شد");
|
||||
break;
|
||||
}
|
||||
|
||||
Serial1.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
if (playbackComplete) {
|
||||
Serial1.println(" COMPLETE");
|
||||
} else {
|
||||
Serial1.println(" INCOMPLETE");
|
||||
}
|
||||
|
||||
// 5. قطع تماس
|
||||
Serial1.print("[5] پایان تماس... ");
|
||||
resp = sendATCommand("ATH", 3000, false, true);
|
||||
|
||||
if (resp.indexOf("OK") != -1) {
|
||||
Serial1.println("OK");
|
||||
Serial1.println("✅ عملیات کامل شد");
|
||||
return true;
|
||||
} else {
|
||||
Serial1.println("FAIL");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- تابع اصلی یکپارچه --------------------
|
||||
bool downloadAndCall(String phoneNumber, String audioUrl) {
|
||||
Serial1.println("\n🎯 شروع عملیات کامل");
|
||||
Serial1.println("====================");
|
||||
|
||||
Serial1.println("📞 شماره: " + phoneNumber);
|
||||
Serial1.println("🔗 URL: " + audioUrl);
|
||||
|
||||
// 1. راهاندازی اینترنت
|
||||
if (!setupInternet()) {
|
||||
Serial1.println("❌ اتصال اینترنت ناموفق");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. دانلود فایل صوتی
|
||||
if (!downloadAudioFile(audioUrl)) {
|
||||
Serial1.println("❌ دانلود فایل ناموفق");
|
||||
return false;
|
||||
}
|
||||
|
||||
delay(2000);
|
||||
|
||||
// 3. تماس و پخش
|
||||
return callAndPlayAudio(phoneNumber);
|
||||
}
|
||||
|
||||
// -------------------- تابع تست سریع --------------------
|
||||
void testAudioCall() {
|
||||
Serial1.println("\n🧪 تست سریع عملیات تماس صوتی");
|
||||
Serial1.println("==============================");
|
||||
|
||||
// اطلاعات تست (تغییر دهید)
|
||||
String testPhone = "09192530212";
|
||||
String testUrl = "http://ghback.nabaksoft.ir/My_staticFiles/output.amr"; // URL فایل صوتی AMR
|
||||
|
||||
Serial1.println("⚠️ توجه: لطفاً اطلاعات زیر را تنظیم کنید:");
|
||||
Serial1.println(" 1. شماره تلفن: " + testPhone);
|
||||
Serial1.println(" 2. URL فایل صوتی: " + testUrl);
|
||||
Serial1.println(" 3. APN (اگر نیاز است) در کد تنظیم شود");
|
||||
|
||||
// در اینجا میتوانید تست را فعال کنید
|
||||
// bool result = downloadAndCall(testPhone, testUrl);
|
||||
|
||||
Serial1.println("\n📋 دستورات تست دستی:");
|
||||
Serial1.println(" 1. initModule() - راهاندازی ماژول");
|
||||
Serial1.println(" 2. setupInternet() - اتصال اینترنت");
|
||||
Serial1.println(" 3. downloadAudioFile(\"URL\") - دانلود فایل");
|
||||
Serial1.println(" 4. callAndPlayAudio(\"PHONE\") - تماس و پخش");
|
||||
}
|
||||
|
||||
// -------------------- راهاندازی اولیه ماژول --------------------
|
||||
void initModule() {
|
||||
Serial1.begin(115200);
|
||||
EC200U.begin(115200);
|
||||
|
||||
delay(3000);
|
||||
|
||||
Serial1.println("\n🔧 راهاندازی ماژول EC200U");
|
||||
Serial1.println("==========================");
|
||||
|
||||
// تست AT
|
||||
Serial1.print("AT... ");
|
||||
if (sendATCommand("AT", 2000, false).indexOf("OK") != -1) {
|
||||
Serial1.println("OK");
|
||||
} else {
|
||||
Serial1.println("FAIL");
|
||||
return;
|
||||
}
|
||||
|
||||
// غیرفعال کردن اکو
|
||||
sendATCommand("ATE0", 1000, false);
|
||||
|
||||
// تنظیمات صدا
|
||||
sendATCommand("AT+CLVL=5", 1000, false); // سطح صدا
|
||||
sendATCommand("AT+CMUT=0", 1000, false); // غیرفعال کردن mute
|
||||
|
||||
Serial1.println("✅ ماژول آماده است");
|
||||
}
|
||||
|
||||
#endif // EC200U_AUDIOCALL_H
|
||||
434
14041130/TestProgram/TestEcu/EC200U-sms.h
Normal file
434
14041130/TestProgram/TestEcu/EC200U-sms.h
Normal file
@@ -0,0 +1,434 @@
|
||||
#ifndef EC200U_FINAL_H
|
||||
#define EC200U_FINAL_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// -------------------- تعریف USART3 --------------------
|
||||
HardwareSerial EC200U(USART3);
|
||||
|
||||
// -------------------- تابع ارسال AT --------------------
|
||||
bool sendAT(String cmd, uint16_t timeout = 2000, bool showResponse = false) {
|
||||
EC200U.println(cmd);
|
||||
|
||||
String response = "";
|
||||
unsigned long start = millis();
|
||||
|
||||
while (millis() - start < timeout) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
if (showResponse) Serial1.write(c);
|
||||
}
|
||||
|
||||
if (response.indexOf("OK") != -1) return true;
|
||||
if (response.indexOf("ERROR") != -1) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------- تابع ارسال AT با دریافت پاسخ --------------------
|
||||
String sendATWithResponse(String cmd, uint16_t timeout = 2000) {
|
||||
if (cmd.length() > 0) {
|
||||
EC200U.println(cmd);
|
||||
}
|
||||
|
||||
String response = "";
|
||||
unsigned long start = millis();
|
||||
|
||||
while (millis() - start < timeout) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
// -------------------- منتظر ماندن برای پرامپت > --------------------
|
||||
bool waitForPrompt(uint16_t timeout = 5000) {
|
||||
unsigned long startTime = millis();
|
||||
while (millis() - startTime < timeout) {
|
||||
while (EC200U.available()) {
|
||||
if (EC200U.read() == '>') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------- تابع اصلی ارسال SMS (نسخه بهینه) --------------------
|
||||
bool sendSMS(String phoneNumber, String message) {
|
||||
Serial1.println("\n📱 ارسال پیامک");
|
||||
Serial1.println("==============");
|
||||
|
||||
// 1. تنظیم Text Mode
|
||||
if (!sendAT("AT+CMGF=1", 2000)) {
|
||||
Serial1.println("❌ خطا: Text Mode تنظیم نشد");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. تنظیم charset به UTF-8
|
||||
if (!sendAT("AT+CSCS=\"UTF-8\"", 2000)) {
|
||||
Serial1.println("❌ خطا: UTF-8 پشتیبانی نمیشود");
|
||||
Serial1.println("تلاش با UCS2...");
|
||||
if (!sendAT("AT+CSCS=\"UCS2\"", 2000)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. تنظیم پارامترهای SMS با مقدار موفق (17,167,0,8)
|
||||
if (!sendAT("AT+CSMP=17,167,0,8", 2000)) {
|
||||
Serial1.println("⚠️ هشدار: تنظیم CSMP ناموفق، ادامه میدهیم...");
|
||||
}
|
||||
|
||||
// 4. ارسال دستور CMGS
|
||||
EC200U.print("AT+CMGS=\"");
|
||||
EC200U.print(phoneNumber);
|
||||
EC200U.println("\"");
|
||||
|
||||
// 5. منتظر prompt >
|
||||
if (!waitForPrompt(5000)) {
|
||||
Serial1.println("❌ خطا: Prompt دریافت نشد");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 6. ارسال متن (بدون println که خط جدید اضافه کند)
|
||||
EC200U.print(message);
|
||||
|
||||
// 7. ارسال Ctrl+Z (بدون تاخیر اضافی)
|
||||
EC200U.write(26);
|
||||
|
||||
// 8. دریافت پاسخ با تایماوت کوتاهتر
|
||||
unsigned long startTime = millis();
|
||||
String response = "";
|
||||
bool success = false;
|
||||
|
||||
while (millis() - startTime < 10000) { // 10 ثانیه کافی است
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
|
||||
// بررسی سریعتر برای موفقیت
|
||||
if (response.indexOf("+CMGS:") != -1) {
|
||||
success = true;
|
||||
// ادامه میدهیم تا OK هم دریافت شود
|
||||
}
|
||||
|
||||
if (response.indexOf("OK") != -1 && success) {
|
||||
Serial1.println("\n✅ پیامک با موفقیت ارسال شد");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (response.indexOf("ERROR") != -1 || response.indexOf("CMS ERROR") != -1) {
|
||||
Serial1.println("\n❌ خطا در ارسال");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
Serial1.println("\n✅ پیامک ارسال شد (بدون دریافت OK)");
|
||||
return true;
|
||||
}
|
||||
|
||||
Serial1.println("\n❌ ارسال ناموفق - زمان تمام شد");
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------- نسخه بهینه شده با حذف خط خالی --------------------
|
||||
bool sendSMS_Optimized(String phoneNumber, String message) {
|
||||
Serial1.println("\n📱 ارسال پیامک (نسخه بهینه)");
|
||||
Serial1.println("========================");
|
||||
|
||||
// یکجا تنظیمات را ارسال میکنیم
|
||||
EC200U.println("AT+CMGF=1");
|
||||
delay(100);
|
||||
EC200U.println("AT+CSCS=\"UTF-8\"");
|
||||
delay(100);
|
||||
EC200U.println("AT+CSMP=17,167,0,8");
|
||||
delay(100);
|
||||
|
||||
// پاک کردن بافر
|
||||
while (EC200U.available()) EC200U.read();
|
||||
|
||||
// ارسال دستور اصلی
|
||||
EC200U.print("AT+CMGS=\"");
|
||||
EC200U.print(phoneNumber);
|
||||
EC200U.println("\"");
|
||||
|
||||
// منتظر پرامپت
|
||||
unsigned long startTime = millis();
|
||||
bool gotPrompt = false;
|
||||
while (millis() - startTime < 5000) {
|
||||
if (EC200U.available()) {
|
||||
if (EC200U.read() == '>') {
|
||||
gotPrompt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gotPrompt) {
|
||||
Serial1.println("❌ خطا: Prompt دریافت نشد");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ارسال متن و Ctrl+Z بدون فاصله اضافی
|
||||
EC200U.print(message);
|
||||
delay(10); // تاخیر بسیار کم
|
||||
EC200U.write(26);
|
||||
|
||||
// دریافت پاسخ
|
||||
startTime = millis();
|
||||
String response = "";
|
||||
while (millis() - startTime < 8000) {
|
||||
if (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
Serial1.write(c); // نمایش لحظهای پاسخ
|
||||
|
||||
if (response.indexOf("+CMGS:") != -1 && response.indexOf("OK") != -1) {
|
||||
Serial1.println("\n✅ ارسال موفق");
|
||||
return true;
|
||||
}
|
||||
if (response.indexOf("ERROR") != -1) {
|
||||
Serial1.println("\n❌ ارسال ناموفق");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Serial1.println("\n⚠️ نتیجه نامشخص، اما احتمالاً ارسال شده");
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------- نسخه نهایی و ساده --------------------
|
||||
bool sendSMS_Final(String phoneNumber, String message) {
|
||||
// پاکسازی بافر
|
||||
while (EC200U.available()) EC200U.read();
|
||||
|
||||
// تنظیمات سریع
|
||||
EC200U.println("AT+CMGF=1");
|
||||
delay(50);
|
||||
EC200U.println("AT+CSMP=17,167,0,8");
|
||||
delay(50);
|
||||
EC200U.println("AT+CSCS=\"UTF-8\"");
|
||||
delay(50);
|
||||
|
||||
// پاکسازی مجدد
|
||||
while (EC200U.available()) EC200U.read();
|
||||
|
||||
// ارسال دستور
|
||||
EC200U.print("AT+CMGS=\"");
|
||||
EC200U.print(phoneNumber);
|
||||
EC200U.println("\"");
|
||||
|
||||
// انتظار برای پرامپت
|
||||
int timeout = 0;
|
||||
while (timeout < 100) {
|
||||
if (EC200U.available() && EC200U.read() == '>') break;
|
||||
delay(50);
|
||||
timeout++;
|
||||
}
|
||||
|
||||
if (timeout >= 100) {
|
||||
Serial1.println("❌ خطا: Prompt دریافت نشد");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ارسال متن (بدون خط جدید)
|
||||
for (int i = 0; i < message.length(); i++) {
|
||||
EC200U.write(message.charAt(i));
|
||||
}
|
||||
|
||||
// ارسال Ctrl+Z
|
||||
EC200U.write(26);
|
||||
|
||||
// بررسی سریع نتیجه
|
||||
timeout = 0;
|
||||
while (timeout < 50) {
|
||||
if (EC200U.available()) {
|
||||
String resp = EC200U.readString();
|
||||
if (resp.indexOf("+CMGS:") != -1 || resp.indexOf("OK") != -1) {
|
||||
Serial1.println("✅ ارسال موفق");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
delay(100);
|
||||
timeout++;
|
||||
}
|
||||
|
||||
Serial1.println("✅ ارسال انجام شد (نتیجه نامشخص)");
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------- راهاندازی ماژول --------------------
|
||||
void initEC200U(int baud = 115200) {
|
||||
Serial1.begin(115200);
|
||||
EC200U.begin(baud);
|
||||
|
||||
delay(2000);
|
||||
|
||||
Serial1.println("\n🔧 راهاندازی ماژول EC200U");
|
||||
Serial1.println("==========================");
|
||||
|
||||
// بررسی ارتباط
|
||||
for (int i = 0; i < 3; i++) {
|
||||
EC200U.println("AT");
|
||||
delay(100);
|
||||
if (EC200U.find("OK")) {
|
||||
Serial1.println("✅ ماژول پاسخ میدهد");
|
||||
break;
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
|
||||
// غیرفعال کردن اکو
|
||||
EC200U.println("ATE0");
|
||||
delay(100);
|
||||
|
||||
// فعال کردن گزارش خطا
|
||||
EC200U.println("AT+CMEE=1");
|
||||
delay(100);
|
||||
|
||||
// بررسی سیم کارت
|
||||
EC200U.println("AT+CPIN?");
|
||||
delay(100);
|
||||
|
||||
Serial1.println("✅ آماده به کار\n");
|
||||
}
|
||||
|
||||
#endif // EC200U_FINAL_H
|
||||
|
||||
|
||||
// #ifndef EC200U_FINAL_H
|
||||
// #define EC200U_FINAL_H
|
||||
|
||||
// #include <Arduino.h>
|
||||
|
||||
// // -------------------- تعریف USART3 --------------------
|
||||
// HardwareSerial EC200U(USART3);
|
||||
|
||||
// // -------------------- تابع ارسال AT --------------------
|
||||
// bool sendAT(String cmd, uint16_t timeout = 2000, bool showResponse = false) {
|
||||
// EC200U.println(cmd);
|
||||
|
||||
// String response = "";
|
||||
// unsigned long start = millis();
|
||||
|
||||
// while (millis() - start < timeout) {
|
||||
// while (EC200U.available()) {
|
||||
// char c = EC200U.read();
|
||||
// response += c;
|
||||
// if (showResponse) Serial1.write(c);
|
||||
// }
|
||||
|
||||
// if (response.indexOf("OK") != -1) return true;
|
||||
// if (response.indexOf("ERROR") != -1) return false;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // -------------------- تابع اصلی ارسال SMS --------------------
|
||||
// bool sendSMS(String phoneNumber, String message) {
|
||||
// Serial1.println("\n📱 ارسال پیامک");
|
||||
// Serial1.println("==============");
|
||||
|
||||
// // 1. تنظیم Text Mode
|
||||
// if (!sendAT("AT+CMGF=1")) {
|
||||
// Serial1.println("❌ خطا: Text Mode تنظیم نشد");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // 2. تنظیم charset به UTF-8
|
||||
// if (!sendAT("AT+CSCS=\"UTF-8\"")) {
|
||||
// Serial1.println("❌ خطا: UTF-8 پشتیبانی نمیشود");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // 3. تنظیم پارامترهای SMS (اختیاری)
|
||||
// sendAT("AT+CSMP=1,167,0,8");
|
||||
|
||||
// // 4. ارسال دستور CMGS
|
||||
// String cmd = "AT+CMGS=\"" + phoneNumber + "\"";
|
||||
// EC200U.println(cmd);
|
||||
|
||||
// // منتظر prompt >
|
||||
// delay(100);
|
||||
// unsigned long startTime = millis();
|
||||
// bool gotPrompt = false;
|
||||
|
||||
// while (millis() - startTime < 5000) {
|
||||
// while (EC200U.available()) {
|
||||
// if (EC200U.read() == '>') {
|
||||
// gotPrompt = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (gotPrompt) break;
|
||||
// }
|
||||
|
||||
// if (!gotPrompt) {
|
||||
// Serial1.println("❌ خطا: Prompt دریافت نشد");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // 5. ارسال متن UTF-8
|
||||
// EC200U.println(message);
|
||||
// delay(100);
|
||||
|
||||
// // 6. ارسال Ctrl+Z
|
||||
// EC200U.write(26);
|
||||
|
||||
// // 7. دریافت پاسخ
|
||||
// startTime = millis();
|
||||
// String response = "";
|
||||
// bool success = false;
|
||||
|
||||
// while (millis() - startTime < 15000) {
|
||||
// while (EC200U.available()) {
|
||||
// char c = EC200U.read();
|
||||
// response += c;
|
||||
|
||||
// if (response.indexOf("+CMGS:") != -1) success = true;
|
||||
// if (response.indexOf("+CMS ERROR") != -1) return false;
|
||||
// }
|
||||
|
||||
// if (response.indexOf("OK") != -1) break;
|
||||
// if (response.indexOf("ERROR") != -1) break;
|
||||
// }
|
||||
|
||||
// if (success) {
|
||||
// Serial1.println("✅ پیامک ارسال شد");
|
||||
// return true;
|
||||
// } else {
|
||||
// Serial1.println("❌ ارسال ناموفق");
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // -------------------- راهاندازی ماژول --------------------
|
||||
// void initEC200U(int baud = 115200) {
|
||||
// Serial1.begin(115200);
|
||||
// EC200U.begin(baud);
|
||||
|
||||
// delay(2000);
|
||||
|
||||
// Serial1.println("\n🔧 راهاندازی ماژول EC200U");
|
||||
// Serial1.println("==========================");
|
||||
|
||||
// if (!sendAT("AT")) {
|
||||
// Serial1.println("❌ ماژول پاسخ نمیدهد");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// sendAT("ATE0");
|
||||
|
||||
// if (sendAT("AT+CPIN?")) {
|
||||
// Serial1.println("✅ SIM آماده");
|
||||
// }
|
||||
|
||||
// Serial1.println("✅ راهاندازی کامل\n");
|
||||
// }
|
||||
|
||||
// #endif // EC200U_FINAL_H
|
||||
72
14041130/TestProgram/TestEcu/TestEcu.ino
Normal file
72
14041130/TestProgram/TestEcu/TestEcu.ino
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "EC200U-sms.h"
|
||||
|
||||
// void setup() {
|
||||
// راهاندازی اولیه ماژول
|
||||
// initModule();
|
||||
|
||||
// تنظیم APN (اگر نیاز است)
|
||||
// APN = "mtnirancell"; // مثال: برای همراه اول
|
||||
// APN = "mci"; // مثال: برای ایرانسل
|
||||
|
||||
// delay(2000);
|
||||
|
||||
// اجرای عملیات کامل
|
||||
// bool success = downloadAndCall(
|
||||
// "09192530212", // شماره تلفن مقصد
|
||||
// "https://ghback.nabaksoft.ir/My_staticFiles/output.amr" // URL فایل صوتی AMR
|
||||
// );
|
||||
|
||||
// if (success) {
|
||||
// Serial1.println("\n🎉 عملیات با موفقیت انجام شد!");
|
||||
// } else {
|
||||
// Serial1.println("\n❌ عملیات ناموفق بود");
|
||||
// }
|
||||
// }
|
||||
|
||||
// void loop() {
|
||||
// میتوانید کدهای تکرارشونده را اینجا قرار دهید
|
||||
// delay(1000);
|
||||
// }
|
||||
// #include "EC200U-Call.h"
|
||||
|
||||
void setup() {
|
||||
// شماره تلفن مقصد را اینجا تنظیم کن
|
||||
//String TARGET_PHONE = "09192530212"; // شماره خودت را اینجا قرار بده
|
||||
|
||||
// راهاندازی ماژول
|
||||
initEC200U(115200);
|
||||
|
||||
// تاخیر برای اتصال شبکه
|
||||
delay(5000);
|
||||
Serial1.println("شروع");
|
||||
|
||||
sendSMS("09192530212", "سلام1");
|
||||
Serial1.println("----------");
|
||||
delay(2000);
|
||||
//sendSMS_Optimized("09192530212", "سلام2");
|
||||
//delay(5000);
|
||||
Serial1.println("----------");
|
||||
sendSMS_Final("09192530212", "سلام3");
|
||||
Serial1.println("----------");
|
||||
delay(2000);
|
||||
Serial1.println("----------");
|
||||
sendSMS("09212087553", "سلام\nاین یک پیام فارسی است.");
|
||||
Serial1.println("----------");
|
||||
//delay(5000);
|
||||
//sendSMS("09192530212", "سلام\nاین یک پیام فارسی است.");
|
||||
//delay(5000);
|
||||
// sendSMS("09354600904", "سلام\nاین یک پیام فارسی است.");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
// // میتوانید در شرایط خاص پیامک ارسال کنید
|
||||
// // مثال:
|
||||
// // static unsigned long lastSend = 0;
|
||||
// // if (millis() - lastSend > 300000) { // هر 5 دقیقه
|
||||
// // sendPersianSMS("گزارش سیستم: فعال\nزمان: " + String(millis()/1000) + " ثانیه");
|
||||
// // lastSend = millis();
|
||||
// // }
|
||||
|
||||
// delay(1000);
|
||||
// }
|
||||
148
14041130/mq/calibr/Voltage_Reader.h
Normal file
148
14041130/mq/calibr/Voltage_Reader.h
Normal file
@@ -0,0 +1,148 @@
|
||||
#ifndef VOLTAGE_READER_H
|
||||
#define VOLTAGE_READER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define VOLTAGE_DIVIDER_PIN PA0 // پین خواندن ولتاژ
|
||||
#define BATTERY_VOLTAGE_PIN_A3 PA3 // پین جدید برای باتری
|
||||
#define VOLTAGE_DIVIDER_RATIO 2.0 // نسبت تقسیم (R1=R2=10k => نسبت = 2)
|
||||
#define ADC_REF_VOLTAGE 3.3 // ولتاژ مرجع ADC در STM32 (معمولاً 3.3V)
|
||||
#define ADC_RESOLUTION 4096 // رزولوشن ADC 12-bit = 4096
|
||||
|
||||
|
||||
class VoltageReader {
|
||||
private:
|
||||
float filteredVoltage = 0.0;
|
||||
bool firstReading = true; // فلگ برای اولین خواندن
|
||||
const float alpha = 0.3; // ضریب فیلتر را کمی بیشتر کردم
|
||||
|
||||
public:
|
||||
VoltageReader() {
|
||||
init();
|
||||
}
|
||||
|
||||
void init() {
|
||||
pinMode(VOLTAGE_DIVIDER_PIN, INPUT_ANALOG);
|
||||
analogReadResolution(12); // تنظیم رزولوشن ADC به 12-bit
|
||||
delay(100); // کمی بیشتر صبر کن
|
||||
|
||||
// چند بار خواندن برای تخلیه خازنهای داخلی
|
||||
for (int i = 0; i < 10; i++) {
|
||||
analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
// خواندن ولتاژ بدون فیلتر
|
||||
float readRawVoltage() {
|
||||
int samples = 32; // تعداد نمونهها را بیشتر کردم
|
||||
long sum = 0;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
sum += analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
delayMicroseconds(20);
|
||||
}
|
||||
|
||||
int rawValue = sum / samples;
|
||||
|
||||
// تبدیل به ولتاژ
|
||||
float voltageAtPin = (rawValue * ADC_REF_VOLTAGE) / ADC_RESOLUTION;
|
||||
|
||||
// محاسبه ولتاژ اصلی
|
||||
float actualVoltage = voltageAtPin * VOLTAGE_DIVIDER_RATIO;
|
||||
|
||||
return actualVoltage;
|
||||
}
|
||||
|
||||
// خواندن با فیلتر
|
||||
float readVoltage() {
|
||||
float currentVoltage = readRawVoltage();
|
||||
|
||||
// اگر اولین بار است، فیلتر را با مقدار فعلی مقداردهی کن
|
||||
if (firstReading) {
|
||||
filteredVoltage = currentVoltage;
|
||||
firstReading = false;
|
||||
} else {
|
||||
// اعمال فیلتر Low-pass
|
||||
filteredVoltage = (alpha * currentVoltage) + ((1 - alpha) * filteredVoltage);
|
||||
}
|
||||
|
||||
return currentVoltage; // actual voltage برمیگردانیم
|
||||
}
|
||||
|
||||
// دریافت ولتاژ فیلتر شده
|
||||
float getFilteredVoltage() {
|
||||
return filteredVoltage;
|
||||
}
|
||||
|
||||
// تست سلامت مدار
|
||||
bool testCircuit() {
|
||||
Serial1.println("\n🔌 Testing voltage divider circuit...");
|
||||
|
||||
// چند بار خواندن برای اطمینان
|
||||
float sum = 0;
|
||||
int readings = 10;
|
||||
|
||||
for (int i = 0; i < readings; i++) {
|
||||
sum += readRawVoltage();
|
||||
delay(50);
|
||||
}
|
||||
|
||||
float avgVoltage = sum / readings;
|
||||
|
||||
Serial1.print("Average voltage: ");
|
||||
Serial1.print(avgVoltage, 2);
|
||||
Serial1.println("V");
|
||||
|
||||
Serial1.print("Raw ADC value: ");
|
||||
Serial1.println(analogRead(VOLTAGE_DIVIDER_PIN));
|
||||
|
||||
// ولتاژ در پین
|
||||
float pinVoltage = avgVoltage / VOLTAGE_DIVIDER_RATIO;
|
||||
Serial1.print("Voltage at PA0 pin: ");
|
||||
Serial1.print(pinVoltage, 2);
|
||||
Serial1.println("V");
|
||||
|
||||
if (avgVoltage > 4.5 && avgVoltage < 5.5) {
|
||||
Serial1.println("✅ Circuit OK (within expected 5V ±10%)");
|
||||
return true;
|
||||
} else {
|
||||
Serial1.print("❌ Expected ~5V, got ");
|
||||
Serial1.print(avgVoltage, 2);
|
||||
Serial1.println("V");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// نمایش اطلاعات دیباگ
|
||||
void debugInfo() {
|
||||
float rawVoltage = readRawVoltage();
|
||||
int rawADC = analogRead(VOLTAGE_DIVIDER_PIN);
|
||||
float pinVoltage = rawVoltage / VOLTAGE_DIVIDER_RATIO;
|
||||
|
||||
Serial1.println("\n📊 Voltage Debug Info:");
|
||||
Serial1.print("Raw ADC value: ");
|
||||
Serial1.println(rawADC);
|
||||
Serial1.print("Voltage at PA0 pin: ");
|
||||
Serial1.print(pinVoltage, 3);
|
||||
Serial1.println("V");
|
||||
Serial1.print("Actual voltage (raw): ");
|
||||
Serial1.print(rawVoltage, 3);
|
||||
Serial1.println("V");
|
||||
Serial1.print("Filtered voltage: ");
|
||||
Serial1.print(filteredVoltage, 3);
|
||||
Serial1.println("V");
|
||||
}
|
||||
|
||||
// ریست فیلتر
|
||||
void resetFilter() {
|
||||
filteredVoltage = 0.0;
|
||||
firstReading = true;
|
||||
Serial1.println("✅ Voltage filter reset");
|
||||
}
|
||||
};
|
||||
|
||||
// ایجاد نمونه سراسری
|
||||
VoltageReader voltageReader;
|
||||
|
||||
#endif // VOLTAGE_READER_H
|
||||
127
14041130/mq/calibr/calibr.ino
Normal file
127
14041130/mq/calibr/calibr.ino
Normal file
@@ -0,0 +1,127 @@
|
||||
#include <Arduino.h>
|
||||
#include "Voltage_Reader.h"
|
||||
|
||||
// ========== پارامترهای مدار (مقادیر دقیق اندازهگیریشده) ==========
|
||||
#define VREF_ADC 3.3f // ولتاژ مرجع ADC (معمولاً 3.3V)
|
||||
#define ADC_RESOLUTION 4095.0f // رزولوشن ADC (12 بیت)
|
||||
#define R1 2190.0f // مقاومت سری اول (اهم) - اندازهگیری شده
|
||||
#define R2 3270.0f // مقاومت به زمین (اهم) - اندازهگیری شده
|
||||
#define RSERIES 98.0f // مقاومت سری ۱۰۰ اهم (تأثیر ناچیز، میتوان صفر گذاشت)
|
||||
//#define VCC_SENSOR 4.67f // ولتاژ تغذیه سنسور MQ7
|
||||
#define RL_SENSOR 990.0f // مقاومت بار ماژول (معمولاً ۱۰kΩ)
|
||||
#define ADC_PIN A2 // پین ADC (PA2 در STM32)
|
||||
#define NUM_SAMPLES 10 // تعداد نمونه برای میانگینگیری
|
||||
|
||||
|
||||
|
||||
float VCC_SENSOR = 4.67f; // ولتاژ تغذیه سنسور MQ7
|
||||
float MQ7_R0 = 21000.0; // مقدار R0 (پس از کالیبراسیون) – تقریب اولیه ۲۰ کیلواهم
|
||||
bool calibrationComplete = false;
|
||||
unsigned long lastReadTime = 0;
|
||||
const unsigned long readInterval = 3000;
|
||||
|
||||
// ================================================================
|
||||
|
||||
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)
|
||||
float vOut = vAdc * (R1 + R2) / R2;
|
||||
return vOut;
|
||||
}
|
||||
|
||||
float calculateRs(float vOut) {
|
||||
if (vOut <= 0.0f) return 0.0f;
|
||||
return RL_SENSOR * (VCC_SENSOR / vOut - 1.0f);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial1.begin(115200); // راهاندازی Serial1 با نرخ ۱۱۵۲۰۰
|
||||
analogReadResolution(12); // تنظیم ADC روی ۱۲ بیت
|
||||
pinMode(ADC_PIN, INPUT);
|
||||
delay(2000);
|
||||
voltageReader.debugInfo();
|
||||
VCC_SENSOR=voltageReader.readVoltage();
|
||||
|
||||
Serial1.println("MQ7 Calibration Mode");
|
||||
Serial1.print("R1 = "); Serial1.print(R1); Serial1.println(" ohms");
|
||||
Serial1.print("R2 = "); Serial1.print(R2); Serial1.println(" ohms");
|
||||
Serial1.print("VCC_SENSOR = "); Serial1.print(VCC_SENSOR); Serial1.println(" V");
|
||||
Serial1.print("RL_SENSOR = "); Serial1.print(RL_SENSOR); Serial1.println(" ohms");
|
||||
Serial1.println("\nPlace sensor in clean air and wait 2 minutes to stabilize...");
|
||||
delay(120000); // ۲ دقیقه زمان برای پایدار شدن سنسور
|
||||
Serial1.println("Now measuring. Record Rs value as R0 when stable.\n");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
VCC_SENSOR=voltageReader.readVoltage();
|
||||
|
||||
float vOut = readSensorVoltage();
|
||||
float rs = calculateRs(vOut);
|
||||
Serial1.print("Vout_sensor = "); Serial1.print(vOut, 4); Serial1.print(" V, Rs = ");
|
||||
Serial1.print(rs, 1); Serial1.println(" ohms");
|
||||
delay(5000);
|
||||
}
|
||||
// #include <Arduino.h>
|
||||
|
||||
// // ========== پارامترهای مدار (بر اساس آخرین اندازهگیری) ==========
|
||||
// #define VREF_ADC 3.3f // ولتاژ مرجع ADC (معمولاً 3.3V)
|
||||
// #define ADC_RESOLUTION 4095.0f // رزولوشن ADC (12 بیت)
|
||||
// #define R1 2190.0f // مقاومت سری اول (اهم) - اندازهگیری شده
|
||||
// #define R2 3270.0f // مقاومت به زمین (اهم) - اندازهگیری شده
|
||||
// // مقاومت سری ۹۹ اهم تأثیر ناچیزی دارد، در محاسبات لحاظ نمیشود
|
||||
// #define VCC_SENSOR 4.9f // ولتاژ تغذیه سنسور MQ7
|
||||
// #define RL_SENSOR 839.0f // مقاومت بار ماژول (مقاومت بین خروجی آنالوگ و GND)
|
||||
// #define R0 20000.0f // مقدار R0 از کالیبراسیون (بر حسب اهم) – حدود ۲۰ کیلو اهم
|
||||
// #define CO_A 1.9f // ضریب A در فرمول ppm = A * (Rs/R0)^B
|
||||
// #define CO_B -0.6f // ضریب B (معمولاً منفی)
|
||||
// #define ADC_PIN PA2 // پین ADC (PA2 در STM32)
|
||||
// #define NUM_SAMPLES 10 // تعداد نمونه برای میانگینگیری
|
||||
// // ================================================================
|
||||
|
||||
// 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 / R0;
|
||||
// if (ratio <= 0.0f) return 0.0f;
|
||||
// return CO_A * pow(ratio, CO_B);
|
||||
// }
|
||||
|
||||
// void setup() {
|
||||
// Serial1.begin(115200);
|
||||
// analogReadResolution(12);
|
||||
// pinMode(ADC_PIN, INPUT);
|
||||
|
||||
// Serial1.println("MQ7 CO Measurement");
|
||||
// Serial1.print("R0 = "); Serial1.print(R0); Serial1.println(" ohms");
|
||||
// Serial1.println("Starting...\n");
|
||||
// delay(3000);
|
||||
// }
|
||||
|
||||
// void loop() {
|
||||
// float vOut = readSensorVoltage();
|
||||
// float rs = calculateRs(vOut);
|
||||
// float ppm = calculatePPM(rs);
|
||||
// Serial1.print("CO = "); Serial1.print(ppm, 1); Serial1.println(" ppm");
|
||||
// delay(2000);
|
||||
// }
|
||||
57
14041130/mq/ppm/ppm.ino
Normal file
57
14041130/mq/ppm/ppm.ino
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
// ========== پارامترهای مدار ==========
|
||||
#define VREF_ADC 3.3f
|
||||
#define ADC_RESOLUTION 4095.0f
|
||||
#define R1 1448.0f
|
||||
#define R2 1566.0f
|
||||
#define VCC_SENSOR 4.67f
|
||||
#define RL_SENSOR 10000.0f
|
||||
#define R0 139160.0f // ← مقدار R0 بدستآمده از کالیبراسیون (بر حسب اهم)
|
||||
#define CO_A 1.9f // ضریب A در فرمول ppm = A * (Rs/R0)^B
|
||||
#define CO_B -0.6f // ضریب B (معمولاً منفی)
|
||||
#define ADC_PIN A2
|
||||
#define NUM_SAMPLES 10
|
||||
|
||||
// =====================================
|
||||
|
||||
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;
|
||||
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 / R0;
|
||||
if (ratio <= 0.0f) return 0.0f;
|
||||
return CO_A * pow(ratio, CO_B);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial1.begin(115200);
|
||||
analogReadResolution(12);
|
||||
pinMode(ADC_PIN, INPUT);
|
||||
|
||||
Serial1.println("MQ7 CO Measurement");
|
||||
Serial1.print("R0 = "); Serial1.print(R0); Serial1.println(" ohms");
|
||||
Serial1.println("Starting...\n");
|
||||
delay(3000);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float vOut = readSensorVoltage();
|
||||
float rs = calculateRs(vOut);
|
||||
float ppm = calculatePPM(rs);
|
||||
Serial1.print("CO = "); Serial1.print(ppm, 1); Serial1.println(" ppm");
|
||||
delay(2000);
|
||||
}
|
||||
Reference in New Issue
Block a user