خانه » فروشگاه » ماژول فتورزیستور فعال

ماژول فتورزیستور فعال

32,000 تومانهر عدد

ماژول فتورزیستور اکتیو یک سنسور تشخیص نور پیشرفته است که با ترکیب فتورزیستور (LDR) و مدارهای الکترونیکی فعال، قابلیت‌های تشخیص نور را به صورت دیجیتال و آنالوگ ارائه می‌دهد.

این ماژول برخلاف فتورزیستورهای ساده که تنها مقاومت متغیر هستند، دارای مدار مقایسه‌کننده، تنظیم‌کننده حساسیت و خروجی‌های پردازش شده می‌باشد.

تعداد قیمت تخفیف
10-49 31,360 تومان هر عدد 2%
50+ 31,040 تومان هر عدد 3%

5,000,000 تومان را به سبد خرید اضافه کنید و ارسال رایگان دریافت کنید!

موجود در انبار

Size and packaging guidelines

یکا (واحد) علامت اختصاری شرح انگلیسی مقدار
1 متر m Meter 1
1 سانتی متر cm Canti Meter 2-^10
1 میلی متر mm Mili Meter 3-^10
1 اینچ in Inch 2.54cm
2 اینچ in Inch 5.08cm
3 اینچ in Inch 7.62cm
5 اینچ in Inch 12.7cm
10 افرادی که اکنون این محصول را تماشا می کنند!




توضیحات

ماژول فتورزیستور فعال

(Active Photoresistor Module)

سنسور نور هوشمند با مدار پردازشگر داخلی

ماژول فتورزیستور اکتیو یک سنسور تشخیص نور پیشرفته است که با ترکیب فتورزیستور (LDR) و مدارهای الکترونیکی فعال، قابلیت‌های تشخیص نور را به صورت دیجیتال و آنالوگ ارائه می‌دهد. این ماژول برخلاف فتورزیستورهای ساده که تنها مقاومت متغیر هستند، دارای مدار مقایسه‌کننده، تنظیم‌کننده حساسیت و خروجی‌های پردازش شده می‌باشد.


ویژگی‌های کلیدی

  • فتورزیستور با کیفیت: LDR با پاسخ سریع و حساسیت بالا

  • حساسیت قابل تنظیم: پتانسیومتر برای تنظیم دقیق آستانه حساسیت

  • خروجی دوگانه: هم خروجی دیجیتال (تشخیص تاریکی/روشنایی) و هم خروجی آنالوگ (اندازه‌گیری شدت نور)

  • مدار مقایسه‌کننده: مقایسه‌گر LM393 با عملکرد پایدار

  • LED نشانگر: LED نشانگر وضعیت تشخیص

  • فیلتر نوری: پوشش محافظ برای فیلتر کردن نورهای نامناسب

  • نصب آسان: طراحی شده برای نصب روی برد

  • مصرف بهینه: مدار کم مصرف برای پروژه‌های باتری‌دار


مشخصات فنی

  • فتورزیستور: LDR با مقاومت 10KΩ (در تاریکی)

  • ولتاژ کاری: 3.3V – 5V DC

  • جریان مصرف: 5-15mA (بسته به شرایط نوری)

  • محدوده پاسخ‌دهی: 400nm – 800nm (مرئی)

  • مقاومت در تاریکی: 10KΩ – 20MΩ (تیپیکال)

  • مقاومت در نور: 200Ω – 10KΩ (بسته به شدت نور)

  • خروجی دیجیتال: TTL – HIGH/LOW بر اساس آستانه

  • خروجی آنالوگ: 0-VCC (متناسب با شدت نور)

  • زمان پاسخ: 20ms – 50ms

  • دمای کاری: -30°C تا +70°C

  • ابعاد: 32mm × 14mm


اصول کارکرد

                نور
                  ↓
           [فتورزیستور LDR]
                  ↓
        تغییر مقاومت بر اساس شدت نور
                  ↓
    [مدار تقسیم‌کننده ولتاژ + تقویت‌کننده]
                  ↓
     [مقایسه‌کننده LM393 با آستانه قابل تنظیم]
                  ↓
        خروجی دیجیتال (HIGH/LOW)
            +    خروجی آنالوگ

کاربردهای اصلی

  • سیستم‌های روشنایی خودکار (چراغ‌های خیابان، چراغ مطالعه)

  • تشخیص شب/روز برای سیستم‌های زمان‌بندی

  • سیستم‌های امنیتی (تشخیص نور چراغ قوه)

  • ربات‌های دنبال‌کننده خط (تشخیص خط سفید/سیاه)

  • سیستم‌های کشاورزی هوشمند (کنترل نور گلخانه)

  • دستگاه‌های هواشناسی (تشخیص ابری/آفتابی)

  • کنترل کننده‌های نور LCD (تنظیم خودکار روشنایی)

  • پروژه‌های هنری تعاملی (واکنش به نور)


اتصال به آردوینو

ماژول فتورزیستور ← آردوینو
---------------------------------
VCC  → 5V یا 3.3V
GND  → GND
DO   → پایه دیجیتال (مثلاً D2)
AO   → پایه آنالوگ (مثلاً A0)

کد پایه آردوینو (تشخیص ساده نور)

/*
 * تشخیص تاریکی و روشنایی با فتورزیستور
 * اتصال: DO به D2، AO به A0
 */

const int digitalPin = 2;    // خروجی دیجیتال
const int analogPin = A0;    // خروجی آنالوگ
const int ledPin = 13;       // LED داخلی آردوینو
const int relayPin = 8;      // رله کنترل چراغ (اختیاری)

int lightLevel = 0;          // سطح نور (0-1023)
int digitalState = LOW;      // وضعیت دیجیتال
bool isDark = false;         // آیا تاریک است؟
unsigned long darkStartTime = 0;
int darkEvents = 0;

void setup() {
  Serial.begin(9600);
  pinMode(digitalPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(relayPin, OUTPUT);
  
  digitalWrite(relayPin, LOW); // چراغ خاموش
  
  Serial.println("========================================");
  Serial.println("   Active Photoresistor Module Test");
  Serial.println("========================================");
  Serial.println("Light | Analog | Digital | Status");
  Serial.println("------|--------|---------|--------");
}

void loop() {
  // خواندن مقادیر
  lightLevel = analogRead(analogPin);
  digitalState = digitalRead(digitalPin);
  
  // تشخیص تاریکی (دیجیتال LOW = تاریک، HIGH = روشن)
  bool wasDark = isDark;
  isDark = (digitalState == LOW);
  
  // اگر تاریک شروع شد
  if (isDark && !wasDark) {
    darkEvents++;
    darkStartTime = millis();
    
    Serial.print("DARK  | ");
    Serial.print(lightLevel);
    Serial.print("     | LOW     | Event #");
    Serial.println(darkEvents);
    
    // روشن کردن LED و چراغ
    digitalWrite(ledPin, HIGH);
    digitalWrite(relayPin, HIGH);
  }
  
  // اگر روشن شد
  if (!isDark && wasDark) {
    unsigned long darkDuration = millis() - darkStartTime;
    
    Serial.print("LIGHT | ");
    Serial.print(lightLevel);
    Serial.print("     | HIGH    | Was dark for ");
    Serial.print(darkDuration / 1000.0, 1);
    Serial.println("s");
    
    // خاموش کردن LED و چراغ
    digitalWrite(ledPin, LOW);
    digitalWrite(relayPin, LOW);
  }
  
  // نمایش دوره‌ای وضعیت نور
  static unsigned long lastDisplay = 0;
  if (millis() - lastDisplay > 2000) {
    String status = isDark ? "DARK" : "LIGHT";
    String lux = estimateLux(lightLevel);
    
    Serial.print(status);
    Serial.print(" | ");
    Serial.print(lightLevel);
    Serial.print("     | ");
    Serial.print(digitalState == LOW ? "LOW" : "HIGH");
    Serial.print("     | ~");
    Serial.print(lux);
    Serial.println(" lux");
    
    lastDisplay = millis();
  }
  
  delay(100);
}

// تخمین لوکس از مقدار آنالوگ (تقریبی)
String estimateLux(int analogValue) {
  if (analogValue > 900) return ">2000";    // نور مستقیم خورشید
  if (analogValue > 700) return "1000-2000"; // روز ابری
  if (analogValue > 500) return "500-1000";  // روشنایی دفتر
  if (analogValue > 300) return "200-500";   // روشنایی خانه
  if (analogValue > 100) return "50-200";    // نور کم
  if (analogValue > 50) return "10-50";      // تاریکی نسبی
  return "<10";                             // تاریکی کامل
}

کد پیشرفته: سیستم روشنایی خودکار

/*
 * سیستم روشنایی هوشمند با فتورزیستور
 * با قابلیت تنظیم آستانه و تأخیر
 */

#include <EEPROM.h>

const int analogPin = A0;
const int digitalPin = 2;
const int relayPin = 9;
const int buttonPin = 3;        // دکمه تنظیم
const int potPin = A1;          // پتانسیومتر تنظیم آستانه
const int buzzerPin = 10;       // بوق تأیید

// تنظیمات سیستم
int lightThreshold = 300;       // آستانه تاریکی (0-1023)
int hysteresis = 50;            // هیسترزیس برای جلوگیری از نوسان
int turnOnDelay = 1000;         // تأخیر روشن شدن (ms)
int turnOffDelay = 5000;        // تأخیر خاموش شدن (ms)

// متغیرهای حالت
bool lightOn = false;
bool overrideMode = false;
unsigned long darkTime = 0;
unsigned long lightTime = 0;
int currentLightLevel = 0;

// برای ذخیره تنظیمات در EEPROM
const int EEPROM_THRESHOLD = 0;
const int EEPROM_HYSTERESIS = 2;
const int EEPROM_ON_DELAY = 4;
const int EEPROM_OFF_DELAY = 6;

void setup() {
  Serial.begin(9600);
  
  pinMode(digitalPin, INPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buzzerPin, OUTPUT);
  
  digitalWrite(relayPin, LOW);
  
  // بارگذاری تنظیمات از EEPROM
  loadSettings();
  
  Serial.println("========================================");
  Serial.println("   Smart Lighting Control System");
  Serial.println("========================================");
  Serial.println("Commands:");
  Serial.println("  TXXX - Set threshold (XXX = 0-1023)");
  Serial.println("  HXX  - Set hysteresis (XX = 0-100)");
  Serial.println("  ON   - Manual ON");
  Serial.println("  OFF  - Manual OFF");
  Serial.println("  AUTO - Auto mode");
  Serial.println("  SAVE - Save settings");
  Serial.println("  ?    - Show help");
  Serial.println("----------------------------------------");
  
  displayCurrentSettings();
}

void loop() {
  // خواندن سطح نور
  currentLightLevel = readLightLevel();
  
  // بررسی دکمه تنظیم
  checkButton();
  
  // بررسی دستورات سریال
  checkSerialCommands();
  
  // کنترل خودکار (اگر در حالت override نباشد)
  if (!overrideMode) {
    autoLightControl();
  }
  
  // نمایش وضعیت
  displayStatus();
  
  delay(100);
}

int readLightLevel() {
  // میانگین‌گیری برای کاهش نویز
  static int samples[5];
  static int index = 0;
  
  samples[index] = analogRead(analogPin);
  index = (index + 1) % 5;
  
  long sum = 0;
  for (int i = 0; i < 5; i++) {
    sum += samples[i];
  }
  
  return sum / 5;
}

void autoLightControl() {
  if (!lightOn) {
    // اگر چراغ خاموش است، بررسی کن آیا باید روشن شود
    if (currentLightLevel < lightThreshold) {
      // تاریک است
      if (darkTime == 0) {
        darkTime = millis();
      }
      
      // اگر به مدت کافی تاریک بود
      if (millis() - darkTime >= turnOnDelay) {
        turnLightOn();
      }
    } else {
      // به اندازه کافی روشن است
      darkTime = 0;
    }
  } else {
    // اگر چراغ روشن است، بررسی کن آیا باید خاموش شود
    if (currentLightLevel > lightThreshold + hysteresis) {
      // به اندازه کافی روشن است
      if (lightTime == 0) {
        lightTime = millis();
      }
      
      // اگر به مدت کافی روشن بود
      if (millis() - lightTime >= turnOffDelay) {
        turnLightOff();
      }
    } else {
      // هنوز تاریک است
      lightTime = 0;
    }
  }
}

void turnLightOn() {
  if (!lightOn) {
    digitalWrite(relayPin, HIGH);
    lightOn = true;
    
    Serial.print("Light turned ON - Level: ");
    Serial.println(currentLightLevel);
    
    // بوق تأیید کوتاه
    beep(1000, 100);
  }
}

void turnLightOff() {
  if (lightOn) {
    digitalWrite(relayPin, LOW);
    lightOn = false;
    
    Serial.print("Light turned OFF - Level: ");
    Serial.println(currentLightLevel);
    
    // بوق تأیید کوتاه
    beep(800, 100);
  }
}

void checkButton() {
  static unsigned long lastPress = 0;
  
  if (digitalRead(buttonPin) == LOW && millis() - lastPress > 300) {
    // تغییر حالت override
    overrideMode = !overrideMode;
    
    if (overrideMode) {
      Serial.println("OVERRIDE MODE: Manual control");
      // روشن کردن چراغ در حالت override
      turnLightOn();
    } else {
      Serial.println("AUTO MODE: Automatic control");
    }
    
    beep(1500, 200);
    lastPress = millis();
  }
}

void checkSerialCommands() {
  if (Serial.available()) {
    String command = Serial.readStringUntil('\n');
    command.trim();
    
    if (command.startsWith("T")) {
      // تنظیم آستانه
      int newThreshold = command.substring(1).toInt();
      if (newThreshold >= 0 && newThreshold <= 1023) {
        lightThreshold = newThreshold;
        Serial.print("Threshold set to: ");
        Serial.println(lightThreshold);
        beep(1200, 100);
      }
    }
    else if (command.startsWith("H")) {
      // تنظیم هیسترزیس
      int newHysteresis = command.substring(1).toInt();
      if (newHysteresis >= 0 && newHysteresis <= 100) {
        hysteresis = newHysteresis;
        Serial.print("Hysteresis set to: ");
        Serial.println(hysteresis);
        beep(1200, 100);
      }
    }
    else if (command == "ON") {
      overrideMode = true;
      turnLightOn();
      Serial.println("Manual ON");
    }
    else if (command == "OFF") {
      overrideMode = true;
      turnLightOff();
      Serial.println("Manual OFF");
    }
    else if (command == "AUTO") {
      overrideMode = false;
      Serial.println("Auto mode");
    }
    else if (command == "SAVE") {
      saveSettings();
      Serial.println("Settings saved to EEPROM");
    }
    else if (command == "?") {
      showHelp();
    }
  }
}

void displayStatus() {
  static unsigned long lastDisplay = 0;
  
  if (millis() - lastDisplay > 1000) {
    Serial.print("Light: ");
    Serial.print(currentLightLevel);
    Serial.print(" | Threshold: ");
    Serial.print(lightThreshold);
    Serial.print(" | State: ");
    Serial.print(lightOn ? "ON " : "OFF");
    Serial.print(" | Mode: ");
    Serial.println(overrideMode ? "MANUAL" : "AUTO");
    
    lastDisplay = millis();
  }
}

void displayCurrentSettings() {
  Serial.println("\n=== Current Settings ===");
  Serial.print("Threshold: ");
  Serial.println(lightThreshold);
  Serial.print("Hysteresis: ");
  Serial.println(hysteresis);
  Serial.print("Turn On Delay: ");
  Serial.print(turnOnDelay);
  Serial.println("ms");
  Serial.print("Turn Off Delay: ");
  Serial.print(turnOffDelay);
  Serial.println("ms");
  Serial.println("=======================\n");
}

void showHelp() {
  Serial.println("\n=== Available Commands ===");
  Serial.println("TXXX  - Set light threshold (0-1023)");
  Serial.println("       Example: T300 sets threshold to 300");
  Serial.println("HXX   - Set hysteresis value (0-100)");
  Serial.println("       Example: H50 sets hysteresis to 50");
  Serial.println("ON    - Manually turn light ON");
  Serial.println("OFF   - Manually turn light OFF");
  Serial.println("AUTO  - Switch to automatic mode");
  Serial.println("SAVE  - Save current settings to EEPROM");
  Serial.println("?     - Show this help");
  Serial.println("\nCurrent light levels guide:");
  Serial.println("0-100   : Dark night");
  Serial.println("100-300 : Dim room");
  Serial.println("300-700 : Normal room light");
  Serial.println("700-900 : Bright office");
  Serial.println("900-1023: Direct sunlight");
  Serial.println("===========================\n");
}

void beep(int frequency, int duration) {
  tone(buzzerPin, frequency, duration);
  delay(duration);
  noTone(buzzerPin);
}

void saveSettings() {
  EEPROM.put(EEPROM_THRESHOLD, lightThreshold);
  EEPROM.put(EEPROM_HYSTERESIS, hysteresis);
  EEPROM.put(EEPROM_ON_DELAY, turnOnDelay);
  EEPROM.put(EEPROM_OFF_DELAY, turnOffDelay);
  
  beep(2000, 50);
  delay(50);
  beep(2000, 50);
}

void loadSettings() {
  EEPROM.get(EEPROM_THRESHOLD, lightThreshold);
  EEPROM.get(EEPROM_HYSTERESIS, hysteresis);
  EEPROM.get(EEPROM_ON_DELAY, turnOnDelay);
  EEPROM.get(EEPROM_OFF_DELAY, turnOffDelay);
  
  // مقادیر پیش‌فرض اگر EEPROM خالی باشد
  if (lightThreshold > 1023 || lightThreshold < 0) {
    lightThreshold = 300;
  }
  if (hysteresis > 100 || hysteresis < 0) {
    hysteresis = 50;
  }
}

کد سنسور نور محیطی با کالیبراسیون

/*
 * سنسور نور محیطی با کالیبراسیون خودکار
 * و قابلیت تشخیص تغییرات ناگهانی نور
 */

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

const int analogPin = A0;
const int digitalPin = 2;
const int calibButton = 3;
const int modeButton = 4;

// حالت‌های سیستم
enum Mode { NORMAL, CALIBRATION, ALARM };
Mode currentMode = NORMAL;

// متغیرهای کالیبراسیون
int darkCalibration = 0;    // کالیبراسیون تاریکی کامل
int lightCalibration = 1023; // کالیبراسیون نور کامل
int currentLux = 0;         // لوکس محاسبه شده
int rawValue = 0;           // مقدار خام آنالوگ

// برای تشخیص تغییرات ناگهانی
int lastValues[10];
int valueIndex = 0;
unsigned long lastSuddenChange = 0;
bool alarmActive = false;

// آستانه‌ها
const int SUDDEN_CHANGE_THRESHOLD = 300; // تغییر ناگهانی 300 واحد
const int ALARM_DURATION = 10000;        // مدت هشدار 10 ثانیه

void setup() {
  Serial.begin(9600);
  
  pinMode(digitalPin, INPUT);
  pinMode(calibButton, INPUT_PULLUP);
  pinMode(modeButton, INPUT_PULLUP);
  
  // راه‌اندازی LCD
  lcd.init();
  lcd.backlight();
  
  // مقداردهی اولیه آرایه
  for (int i = 0; i < 10; i++) {
    lastValues[i] = 512; // مقدار میانه
  }
  
  Serial.println("========================================");
  Serial.println("   Ambient Light Sensor with Calibration");
  Serial.println("========================================");
  Serial.println("Press CALIB button to enter calibration");
  Serial.println("Press MODE button to change display");
  Serial.println("----------------------------------------");
  
  displayWelcome();
}

void loop() {
  // خواندن مقادیر
  rawValue = analogRead(analogPin);
  int digitalState = digitalRead(digitalPin);
  
  // ذخیره در تاریخچه برای تشخیص تغییرات
  lastValues[valueIndex] = rawValue;
  valueIndex = (valueIndex + 1) % 10;
  
  // محاسبه لوکس با کالیبراسیون
  currentLux = calculateLux(rawValue);
  
  // بررسی دکمه‌ها
  checkButtons();
  
  // اجرای منطق بر اساس حالت
  switch (currentMode) {
    case NORMAL:
      normalModeOperation();
      break;
    case CALIBRATION:
      calibrationMode();
      break;
    case ALARM:
      alarmMode();
      break;
  }
  
  // بررسی تغییرات ناگهانی
  checkSuddenChanges();
  
  // به‌روزرسانی نمایش
  updateDisplay();
  
  delay(200);
}

void normalModeOperation() {
  // اینجا می‌توانید منطق کنترل اضافه کنید
  // مثلاً کنترل LED یا رله بر اساس نور
  
  static unsigned long lastLog = 0;
  if (millis() - lastLog > 5000) {
    Serial.print("Light: ");
    Serial.print(rawValue);
    Serial.print(" (");
    Serial.print(currentLux);
    Serial.println(" lux)");
    lastLog = millis();
  }
}

void calibrationMode() {
  static unsigned long calibStart = 0;
  static int calibStep = 0; // 0=آماده, 1=تاریکی, 2=نور
  
  if (calibStart == 0) {
    calibStart = millis();
    calibStep = 0;
    
    lcd.clear();
    lcd.print("Calibration Mode");
    lcd.setCursor(0, 1);
    lcd.print("Step 1: Cover LDR");
    
    Serial.println("=== Calibration Mode ===");
    Serial.println("Step 1: Completely cover the LDR");
    Serial.println("Then press CALIB button");
  }
  
  // بررسی دکمه برای پیشرفت در مراحل
  if (digitalRead(calibButton) == LOW) {
    delay(300); // Debouncing
    
    if (calibStep == 0) {
      // مرحله ۱: کالیبراسیون تاریکی
      darkCalibration = rawValue;
      calibStep = 1;
      
      lcd.clear();
      lcd.print("Dark calibrated:");
      lcd.setCursor(0, 1);
      lcd.print(darkCalibration);
      
      Serial.print("Dark calibration: ");
      Serial.println(darkCalibration);
      Serial.println("Step 2: Expose to bright light");
      Serial.println("Then press CALIB button");
      
      delay(1000);
    }
    else if (calibStep == 1) {
      // مرحله ۲: کالیبراسیون نور
      lightCalibration = rawValue;
      calibStep = 2;
      
      lcd.clear();
      lcd.print("Light calibrated:");
      lcd.setCursor(0, 1);
      lcd.print(lightCalibration);
      
      Serial.print("Light calibration: ");
      Serial.println(lightCalibration);
      Serial.println("Calibration complete!");
      
      // ذخیره در EEPROM
      saveCalibration();
      
      delay(2000);
      
      // بازگشت به حالت نرمال
      currentMode = NORMAL;
      calibStart = 0;
      
      lcd.clear();
      lcd.print("Calibration");
      lcd.setCursor(0, 1);
      lcd.print("Saved!");
      
      delay(1000);
    }
  }
  
  // خروج خودکار پس از 30 ثانیه
  if (millis() - calibStart > 30000) {
    currentMode = NORMAL;
    calibStart = 0;
    
    lcd.clear();
    lcd.print("Calibration");
    lcd.setCursor(0, 1);
    lcd.print("Timeout!");
    
    delay(1000);
  }
}

void alarmMode() {
  // حالت هشدار - چشمک زدن و بوق
  static bool alarmState = false;
  static unsigned long lastToggle = 0;
  
  if (millis() - lastToggle > 500) {
    alarmState = !alarmState;
    
    if (alarmState) {
      lcd.backlight();
      tone(8, 1000, 400);
    } else {
      lcd.noBacklight();
    }
    
    lastToggle = millis();
  }
  
  // پایان خودکار هشدار
  if (millis() - lastSuddenChange > ALARM_DURATION) {
    alarmActive = false;
    currentMode = NORMAL;
    lcd.backlight();
    noTone(8);
    
    Serial.println("Alarm deactivated");
  }
}

void checkSuddenChanges() {
  // محاسبه میانگین 5 مقدار آخر
  int recentAvg = 0;
  for (int i = 0; i < 5; i++) {
    int idx = (valueIndex - i - 1 + 10) % 10;
    recentAvg += lastValues[idx];
  }
  recentAvg /= 5;
  
  // محاسبه میانگین 5 مقدار قبل از آن
  int olderAvg = 0;
  for (int i = 5; i < 10; i++) {
    int idx = (valueIndex - i - 1 + 10) % 10;
    olderAvg += lastValues[idx];
  }
  olderAvg /= 5;
  
  // بررسی تغییر ناگهانی
  int change = abs(recentAvg - olderAvg);
  
  if (change > SUDDEN_CHANGE_THRESHOLD && !alarmActive) {
    alarmActive = true;
    lastSuddenChange = millis();
    currentMode = ALARM;
    
    Serial.println("!!! SUDDEN LIGHT CHANGE DETECTED !!!");
    Serial.print("Change: ");
    Serial.println(change);
    
    lcd.clear();
    lcd.print("ALERT!");
    lcd.setCursor(0, 1);
    lcd.print("Light changed!");
  }
}

int calculateLux(int raw) {
  // تبدیل خطی بر اساس کالیبراسیون
  if (raw <= darkCalibration) return 0;
  if (raw >= lightCalibration) return 2000;
  
  // تبدیل خطی به لوکس
  float ratio = (float)(raw - darkCalibration) / (lightCalibration - darkCalibration);
  return (int)(ratio * 2000.0);
}

void checkButtons() {
  static unsigned long lastCalibPress = 0;
  static unsigned long lastModePress = 0;
  
  // دکمه کالیبراسیون
  if (digitalRead(calibButton) == LOW && millis() - lastCalibPress > 500) {
    if (currentMode == NORMAL) {
      currentMode = CALIBRATION;
    } else if (currentMode == CALIBRATION) {
      currentMode = NORMAL;
    }
    
    lastCalibPress = millis();
  }
  
  // دکمه تغییر حالت نمایش
  if (digitalRead(modeButton) == LOW && millis() - lastModePress > 500) {
    // تغییر بین نمایش مقدار خام و لوکس
    static bool showLux = true;
    showLux = !showLux;
    
    lcd.clear();
    if (showLux) {
      lcd.print("Light Level:");
      lcd.setCursor(0, 1);
      lcd.print(currentLux);
      lcd.print(" lux");
    } else {
      lcd.print("Raw Value:");
      lcd.setCursor(0, 1);
      lcd.print(rawValue);
      lcd.print("/1023");
    }
    
    lastModePress = millis();
  }
}

void updateDisplay() {
  static int displayMode = 0;
  static unsigned long lastDisplayChange = 0;
  
  if (currentMode != NORMAL) return;
  
  // تغییر خودکار نمایش هر 5 ثانیه
  if (millis() - lastDisplayChange > 5000) {
    displayMode = (displayMode + 1) % 3;
    lastDisplayChange = millis();
  }
  
  lcd.clear();
  
  switch (displayMode) {
    case 0:
      lcd.print("Light:");
      lcd.setCursor(0, 1);
      lcd.print(currentLux);
      lcd.print(" lux");
      break;
      
    case 1:
      lcd.print("Raw:");
      lcd.setCursor(0, 1);
      lcd.print(rawValue);
      lcd.print("/1023");
      break;
      
    case 2:
      lcd.print("Status:");
      lcd.setCursor(0, 1);
      if (currentLux < 50) {
        lcd.print("Dark");
      } else if (currentLux < 200) {
        lcd.print("Dim");
      } else if (currentLux < 500) {
        lcd.print("Normal");
      } else if (currentLux < 1000) {
        lcd.print("Bright");
      } else {
        lcd.print("Very Bright");
      }
      break;
  }
}

void displayWelcome() {
  lcd.clear();
  lcd.print("Light Sensor");
  lcd.setCursor(0, 1);
  lcd.print("Ready...");
  delay(2000);
}

void saveCalibration() {
  // ذخیره در EEPROM
  EEPROM.write(0, darkCalibration >> 8);
  EEPROM.write(1, darkCalibration & 0xFF);
  EEPROM.write(2, lightCalibration >> 8);
  EEPROM.write(3, lightCalibration & 0xFF);
  
  Serial.println("Calibration saved to EEPROM");
}

void loadCalibration() {
  // بارگذاری از EEPROM
  darkCalibration = (EEPROM.read(0) << 8) | EEPROM.read(1);
  lightCalibration = (EEPROM.read(2) << 8) | EEPROM.read(3);
  
  // اگر EEPROM خالی بود، مقادیر پیش‌فرض
  if (darkCalibration > 1023 || lightCalibration > 1023 || 
      darkCalibration >= lightCalibration) {
    darkCalibration = 50;
    lightCalibration = 900;
  }
}

کد ربات دنبال‌کننده خط با فتورزیستور

/*
 * ربات دنبال‌کننده خط با استفاده از فتورزیستورهای اکتیو
 * 5 سنسور برای تشخیص خط سیاه روی زمینه سفید
 */

// پایه‌های سنسورها (فتورزیستورهای دیجیتال)
const int sensorPins[] = {A0, A1, A2, A3, A4}; // خروجی آنالوگ سنسورها
const int sensorThresholds[] = {500, 500, 500, 500, 500}; // آستانه هر سنسور

// پایه‌های موتورها (L298N Driver)
const int motorLeftSpeed = 5;   // PWM
const int motorLeftDir1 = 6;
const int motorLeftDir2 = 7;
const int motorRightSpeed = 10;  // PWM
const int motorRightDir1 = 8;
const int motorRightDir2 = 9;

// پایه‌های کنترلی
const int startButton = 2;
const int calibrateButton = 3;
const int modeSwitch = 4;

// متغیرهای ربات
bool robotRunning = false;
int sensorValues[5];
int sensorStates[5]; // 0=خط سیاه, 1=زمینه سفید
int linePosition = 0; // -2 تا +2 (چپ به راست)
int lastLinePosition = 0;
unsigned long lastSensorRead = 0;

// PID کنترل
float Kp = 0.8;
float Ki = 0.01;
float Kd = 0.2;
float error = 0;
float lastError = 0;
float integral = 0;
float derivative = 0;
int baseSpeed = 150; // سرعت پایه (0-255)
int correction = 0;

// حالت‌های سیستم
enum RobotMode { STOPPED, CALIBRATING, RUNNING };
RobotMode currentMode = STOPPED;

void setup() {
  Serial.begin(9600);
  
  // تنظیم پایه‌های موتور
  pinMode(motorLeftSpeed, OUTPUT);
  pinMode(motorLeftDir1, OUTPUT);
  pinMode(motorLeftDir2, OUTPUT);
  pinMode(motorRightSpeed, OUTPUT);
  pinMode(motorRightDir1, OUTPUT);
  pinMode(motorRightDir2, OUTPUT);
  
  // تنظیم پایه‌های کنترلی
  pinMode(startButton, INPUT_PULLUP);
  pinMode(calibrateButton, INPUT_PULLUP);
  pinMode(modeSwitch, INPUT_PULLUP);
  
  // توقف موتورها
  stopMotors();
  
  Serial.println("========================================");
  Serial.println("   Line Following Robot");
  Serial.println("   with Active Photoresistors");
  Serial.println("========================================");
  Serial.println("Press CALIB to calibrate sensors");
  Serial.println("Press START to begin/stop");
  Serial.println("----------------------------------------");
}

void loop() {
  // خواندن دکمه‌ها
  readButtons();
  
  // اجرای منطق بر اساس حالت
  switch (currentMode) {
    case STOPPED:
      stoppedMode();
      break;
    case CALIBRATING:
      calibratingMode();
      break;
    case RUNNING:
      runningMode();
      break;
  }
  
  // نمایش اطلاعات
  displayInfo();
  
  delay(20);
}

void readButtons() {
  static unsigned long lastStartPress = 0;
  static unsigned long lastCalibPress = 0;
  
  // دکمه شروع/توقف
  if (digitalRead(startButton) == LOW && millis() - lastStartPress > 500) {
    if (currentMode == STOPPED) {
      currentMode = RUNNING;
      Serial.println("Robot STARTED");
    } else if (currentMode == RUNNING) {
      currentMode = STOPPED;
      stopMotors();
      Serial.println("Robot STOPPED");
    }
    lastStartPress = millis();
  }
  
  // دکمه کالیبراسیون
  if (digitalRead(calibrateButton) == LOW && millis() - lastCalibPress > 500) {
    if (currentMode == STOPPED) {
      currentMode = CALIBRATING;
      Serial.println("Calibration STARTED");
    }
    lastCalibPress = millis();
  }
}

void stoppedMode() {
  // فقط نمایش مقادیر سنسورها
  readSensors();
  calculateLinePosition();
}

void calibratingMode() {
  Serial.println("=== Sensor Calibration ===");
  Serial.println("Place robot over WHITE surface");
  Serial.println("Then press START button");
  Serial.println("---------------------------");
  
  // انتظار برای فشار دکمه
  while (digitalRead(startButton) == HIGH) {
    delay(10);
  }
  delay(300);
  
  // خواندن مقادیر سفید
  int whiteValues[5];
  readSensors();
  for (int i = 0; i < 5; i++) {
    whiteValues[i] = sensorValues[i];
  }
  
  Serial.println("White values saved");
  Serial.print("W: ");
  for (int i = 0; i < 5; i++) {
    Serial.print(whiteValues[i]);
    Serial.print(" ");
  }
  Serial.println();
  
  Serial.println("Now place robot over BLACK line");
  Serial.println("Then press START button");
  Serial.println("---------------------------");
  
  // انتظار برای فشار دکمه
  while (digitalRead(startButton) == HIGH) {
    delay(10);
  }
  delay(300);
  
  // خواندن مقادیر سیاه
  int blackValues[5];
  readSensors();
  for (int i = 0; i < 5; i++) {
    blackValues[i] = sensorValues[i];
  }
  
  Serial.println("Black values saved");
  Serial.print("B: ");
  for (int i = 0; i < 5; i++) {
    Serial.print(blackValues[i]);
    Serial.print(" ");
  }
  Serial.println();
  
  // محاسبه آستانه‌ها (میانگین سفید و سیاه)
  for (int i = 0; i < 5; i++) {
    sensorThresholds[i] = (whiteValues[i] + blackValues[i]) / 2;
  }
  
  Serial.println("Calibration complete!");
  Serial.print("Thresholds: ");
  for (int i = 0; i < 5; i++) {
    Serial.print(sensorThresholds[i]);
    Serial.print(" ");
  }
  Serial.println();
  
  // بازگشت به حالت توقف
  currentMode = STOPPED;
  delay(1000);
}

void runningMode() {
  // خواندن سنسورها
  readSensors();
  
  // محاسبه موقعیت خط
  calculateLinePosition();
  
  // محاسبه PID
  calculatePID();
  
  // کنترل موتورها
  controlMotors();
  
  // بررسی از دست دادن خط
  checkLineLost();
}

void readSensors() {
  for (int i = 0; i < 5; i++) {
    sensorValues[i] = analogRead(sensorPins[i]);
    
    // تبدیل به حالت دیجیتال بر اساس آستانه
    if (sensorValues[i] < sensorThresholds[i]) {
      sensorStates[i] = 0; // خط سیاه
    } else {
      sensorStates[i] = 1; // زمینه سفید
    }
  }
  
  lastSensorRead = millis();
}

void calculateLinePosition() {
  // محاسبه موقعیت خط بر اساس الگوی سنسورها
  // وزن‌دهی: -2, -1, 0, +1, +2
  
  int sum = 0;
  int count = 0;
  
  for (int i = 0; i < 5; i++) {
    if (sensorStates[i] == 0) { // اگر روی خط است
      sum += (i - 2); // -2, -1, 0, 1, 2
      count++;
    }
  }
  
  if (count > 0) {
    lastLinePosition = linePosition;
    linePosition = sum;
  } else {
    // خط پیدا نشد
    linePosition = 0;
  }
}

void calculatePID() {
  error = -linePosition; // منفی برای تصحیح جهت
  
  integral += error;
  integral = constrain(integral, -100, 100); // محدود کردن انتگرال
  
  derivative = error - lastError;
  lastError = error;
  
  correction = (Kp * error) + (Ki * integral) + (Kd * derivative);
}

void controlMotors() {
  int leftSpeed = baseSpeed + correction;
  int rightSpeed = baseSpeed - correction;
  
  // محدود کردن سرعت‌ها
  leftSpeed = constrain(leftSpeed, 0, 255);
  rightSpeed = constrain(rightSpeed, 0, 255);
  
  // اعمال سرعت به موتورها
  setMotorSpeed(leftSpeed, rightSpeed);
  
  // جهت‌ها برای حرکت به جلو
  digitalWrite(motorLeftDir1, HIGH);
  digitalWrite(motorLeftDir2, LOW);
  digitalWrite(motorRightDir1, HIGH);
  digitalWrite(motorRightDir2, LOW);
}

void setMotorSpeed(int left, int right) {
  analogWrite(motorLeftSpeed, left);
  analogWrite(motorRightSpeed, right);
}

void stopMotors() {
  digitalWrite(motorLeftDir1, LOW);
  digitalWrite(motorLeftDir2, LOW);
  digitalWrite(motorRightDir1, LOW);
  digitalWrite(motorRightDir2, LOW);
  analogWrite(motorLeftSpeed, 0);
  analogWrite(motorRightSpeed, 0);
}

void checkLineLost() {
  // اگر همه سنسورها سفید باشند (خط گم شده)
  bool allWhite = true;
  for (int i = 0; i < 5; i++) {
    if (sensorStates[i] == 0) {
      allWhite = false;
      break;
    }
  }
  
  if (allWhite) {
    // خط گم شده - جستجو
    searchForLine();
  }
}

void searchForLine() {
  Serial.println("Line lost! Searching...");
  
  // چرخش به چپ
  digitalWrite(motorLeftDir1, LOW);
  digitalWrite(motorLeftDir2, HIGH);
  digitalWrite(motorRightDir1, HIGH);
  digitalWrite(motorRightDir2, LOW);
  setMotorSpeed(150, 150);
  
  unsigned long searchStart = millis();
  bool lineFound = false;
  
  while (millis() - searchStart < 1000 && !lineFound) {
    readSensors();
    for (int i = 0; i < 5; i++) {
      if (sensorStates[i] == 0) {
        lineFound = true;
        break;
      }
    }
    delay(10);
  }
  
  if (!lineFound) {
    // اگر در چپ پیدا نشد، به راست بچرخ
    digitalWrite(motorLeftDir1, HIGH);
    digitalWrite(motorLeftDir2, LOW);
    digitalWrite(motorRightDir1, LOW);
    digitalWrite(motorRightDir2, HIGH);
    
    searchStart = millis();
    while (millis() - searchStart < 2000 && !lineFound) {
      readSensors();
      for (int i = 0; i < 5; i++) {
        if (sensorStates[i] == 0) {
          lineFound = true;
          break;
        }
      }
      delay(10);
    }
  }
  
  if (lineFound) {
    Serial.println("Line found! Resuming...");
  } else {
    Serial.println("Line not found. Stopping.");
    currentMode = STOPPED;
    stopMotors();
  }
}

void displayInfo() {
  static unsigned long lastDisplay = 0;
  
  if (millis() - lastDisplay > 200) {
    Serial.print("Sensors: ");
    for (int i = 0; i < 5; i++) {
      Serial.print(sensorStates[i]);
      Serial.print("(");
      Serial.print(sensorValues[i]);
      Serial.print(") ");
    }
    
    Serial.print("| Pos: ");
    Serial.print(linePosition);
    
    if (currentMode == RUNNING) {
      Serial.print(" | Error: ");
      Serial.print(error, 2);
      Serial.print(" | Corr: ");
      Serial.print(correction);
    }
    
    Serial.println();
    
    lastDisplay = millis();
  }
}

نکات فنی و تنظیمات

تنظیم حساسیت:

  1. پتانسیومتر روی ماژول را در وسط قرار دهید

  2. در نور محیط معمولی، LED باید خاموش باشد

  3. سنسور را بپوشانید – LED باید روشن شود

  4. برای تنظیم دقیق‌تر، از خروجی آنالوگ استفاده کنید

انتخاب فیلتر نوری:

  • بدون فیلتر: حساسیت به کل طیف مرئی

  • فیلتر قرمز: کاهش حساسیت به نورهای مصنوعی

  • فیلتر سبز: برای تشخیص گیاهان و طبیعت

  • فیلتر آبی: برای آب و آسمان

مقاومت سری با LDR:

// فرمول محاسبه مقاومت سری بهینه:
// R_series = √(R_dark × R_light)
// برای LDR معمولی: R_dark=1MΩ, R_light=1kΩ
// R_series = √(1,000,000 × 1,000) ≈ 31.6kΩ

کاهش نویز:

// فیلتر نرم‌افزاری
float filteredRead(int pin) {
  static float filtered = 512.0;
  const float alpha = 0.1;
  
  int raw = analogRead(pin);
  filtered = alpha * raw + (1 - alpha) * filtered;
  return filtered;
}

پروژه‌های پیشنهادی

1. سیستم تنظیم خودکار کرکره

// باز و بست کرکره بر اساس شدت نور خورشید

2. مزرعه هوشمند نورپردازی

// کنترل LED‌های رشد گیاه با الگوی شب/روز

3. گالری هنری تعاملی

// تغییر نورپردازی آثار بر اساس حضور بازدیدکنندگان

4. سیستم هشدار نوری

// تشخیص نور چراغ قوه در محیط‌های امنیتی

5. کلید لمسی نوری

// فعال‌سازی با ایجاد سایه روی سنسور

جدول مقایسه با سنسورهای نوری دیگر

سنسوردقتقیمتمصرف انرژیکاربرد
فتورزیستور اکتیومتوسطارزانکمعمومی، آموزشی
فتورزیستور سادهپایینبسیار ارزانکمپروژه‌های ساده
سنسور نور دیجیتالبالامتوسطکمدقیق، صنعتی
سنسور طیف‌سنجبسیار بالاگرانمتوسطتحقیقاتی
سنسور UVتخصصیگرانکمپزشکی، صنعت

پکیج خرید

پکیج پایه:

  • 1x ماژول فتورزیستور اکتیو

  • 1x کابل ارتباطی 3 پین

  • 1x هدر پین نری

  • راهنمای نصب فارسی

پکیج توسعه‌دهنده:

  • 3x ماژول فتورزیستور اکتیو

  • 3x فیلتر رنگی (قرمز، سبز، آبی)

  • 1x برد آزمایشی

  • 10x مقاومت‌های سری مختلف

  • کتابچه پروژه‌های نوری

پکیج رباتیک:

  • 5x ماژول فتورزیستور اکتیو (برای خط‌یاب)

  • 1x برد مونتاژ شده خط‌یاب

  • 1x کیت ربات متحرک

  • 1x نقشه مسیر آزمایش

  • نرم‌افزار شبیه‌ساز


گارانتی و پشتیبانی

  • پشتیبانی: رایگان از طریق واتس‌اپ
  • آموزش: ویدیوهای تنظیم و کالیبراسیون

  • جامعه: دسترسی به گروه پروژه‌های نوری


سؤالات متداول

Q1: تفاوت این ماژول با فتورزیستور معمولی چیست؟
این ماژول دارای مدار مقایسه‌کننده و خروجی دیجیتال آماده است. فتورزیستور معمولی فقط مقاومت متغیر است.

Q2: آیا در نور خورشید مستقیم کار می‌کند؟
بله، اما ممکن است به اشباع برود. برای نور مستقیم خورشید از مقاومت سری کوچک‌تر استفاده کنید.

Q3: چگونه برای نور مصنوعی تنظیم کنم؟
پتانسیومتر را طوری تنظیم کنید که در نور معمولی اتاق، LED خاموش باشد.

Q4: حداقل تغییر نور قابل تشخیص چقدر است؟
حدود 5-10 لوکس در حالت آنالوگ، بسته به تنظیمات.

Q5: آیا می‌توان برای تشخیص رنگ استفاده کرد؟
خیر، برای تشخیص رنگ به سنسور RGB یا طیف‌سنج نیاز دارید.


توجه: این ماژول برای کاربردهای عمومی نورسنجی طراحی شده است. برای اندازه‌گیری‌های دقیق علمی از لوکس‌مترهای کالیبره شده استفاده کنید. برای مشاوره فنی درباره پروژه‌های مبتنی بر نور با کارشناسان ما تماس بگیرید.

توضیحات تکمیلی
ابعاد 2 × 2 × 2 سانتیمتر
ساختار محصول تعیین نوع محصول فیزیکی و مجازی ( شامل نقشه ی شماتیک، مدار چاپی و .. بصورت دانلودی )

لایه های مدارچاپی

نوع مدار

کشور سازنده

نظرات (0)
0 بررسی
0
0
0
0
0

هیچ دیدگاهی برای این محصول نوشته نشده است.

.فقط مشتریانی که این محصول را خریداری کرده اند و وارد سیستم شده اند میتوانند برای این محصول دیدگاه ارسال کنند.

حمل و نقل و تحویل

در تهران فقط

پیک موتوری

تحویل حضوری

روشهای ارسال تهران و شهرستان ها

اداره پست جمهوری اسلامی ایران

پست سفارشی، پیشتاز، بین‌المللی، تیپاکس و پست پیشتاز خارج از کشور

در حال حاضر امکان رهگیری مرسوله های پستی با کد مرسوله، دریافت گواهی کد پستی، مشاهده تعرفه های پستی به صورت آنلاین و ... در سایت شرکت ملی پست جمهوری اسلامی ایران فراهم شده است. تمامی مردم می توانند با ورود به این سایت، از خدمات مربوط به شرکت و اداره پست استفاده کنند.

در اداره پست جمهوری اسلامی ایران، برای ارسال مرسولات، روش‌های مختلفی وجود دارد که عبارتند از:

۱. پست سفارشی: این روش برای ارسال کالاهای کوچک و سبک و با ارزش کمتر از ۱۰۰ هزار تومان استفاده می‌شود. در این روش، هزینه ارسال بر اساس وزن و مسافت محاسبه می‌شود و زمان تحویل ۳ تا ۷ روز کاری است.

۲. پیشتاز: این روش برای ارسال کالاهایی با ارزش بیشتر از ۱۰۰ هزار تومان و یا کالاهایی که به سرعت باید تحویل داده شوند، استفاده می‌شود. در این روش، هزینه ارسال بر اساس وزن و مسافت محاسبه می‌شود و زمان تحویل ۱ تا ۳ روز کاری است.

۳. بین‌المللی: این روش برای ارسال کالاهایی به خارج از کشور استفاده می‌شود. در این روش، هزینه ارسال بر اساس وزن و مسافت و هزینه گمرکی محاسبه می‌شود و زمان تحویل بسته به مقصد و روش ارسال، متفاوت است.

۴. تیپاکس: این روش برای ارسال کالاهایی است که به سرعت باید تحویل داده شوند. در این روش، هزینه ارسال بر اساس وزن و مسافت و زمان تحویل مورد نظر مشتری محاسبه می‌شود.

۵. پست پیشتاز خارج از کشور: این روش برای ارسال کالاها به خارج از کشور استفاده می‌شود و هزینه ارسال بر اساس وزن و مسافت و هزینه گمرکی محاسبه می‌شود.

در کل، برای ارسال مرسوله در اداره پست جمهوری اسلامی ایران، می‌توانید یکی از روش‌های فوق را انتخاب کنید که بسته به نیاز و شرایط شما، مناسب‌تر است.