100) { noTone(speaker_pin); delay(500); } else if (cmMs > 50) { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(600); } else if (cmMs > 20) { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(200); } else { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(100); } }"> 100) { noTone(speaker_pin); delay(500); } else if (cmMs > 50) { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(600); } else if (cmMs > 20) { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(200); } else { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(100); } }"> 100) { noTone(speaker_pin); delay(500); } else if (cmMs > 50) { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(600); } else if (cmMs > 20) { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(200); } else { tone(speaker_pin, 1000); delay(50); noTone(speaker_pin); delay(100); } }">
#include <Ultrasonic.h>

// p2 p3對應echo 與trig
Ultrasonic ultrasonic_2_3(27, 26);

// p5插蜂鳴器sig
int speaker_pin = 25; 

void setup() {
  Serial.begin(115200);
}

void loop() {
  // 將讀取到的距離數值直接存進 cmMs 變數中
  float cmMs = ultrasonic_2_3.read();

  Serial.print("感測距離(單位cm):");
  Serial.println(String(cmMs));

  // 根據距離改變蜂鳴器的逼逼聲頻率 (越近叫越快)
  if (cmMs > 100) {
    noTone(speaker_pin);
    delay(500); 
  }
  else if (cmMs > 50) {
    tone(speaker_pin, 1000);
    delay(50);
    noTone(speaker_pin);
    delay(600);
  }
  else if (cmMs > 20) {
    tone(speaker_pin, 1000);
    delay(50);
    noTone(speaker_pin);
    delay(200);
  }
  else {
    tone(speaker_pin, 1000);
    delay(50);
    noTone(speaker_pin);
    delay(100);     
  }
}

image.png

#include <ESP32Servo.h>
#include <Ultrasonic.h>
#include "DHT.h" // 引入 DHT 函式庫

// ----- 伺服馬達設定 -----
Servo myservo;
const int Servo_Pin = 33;

// ----- DHT11 溫濕度感測器設定 -----
#define DHTPIN  32
#define DHTTYPE DHT11
DHT dht1(DHTPIN, DHTTYPE);
unsigned long lastDHTTime = 0;
float humidity = 0.0;
float tempC    = 0.0;

// ----- 超音波與蜂鳴器設定 -----
Ultrasonic ultrasonic_2_3(27, 26);
const int speaker_pin = 25;
float cmMs = 100.0;
unsigned long lastSonarTime = 0;

// ----- 蜂鳴器狀態 -----
unsigned long lastBeepTime = 0;
bool isBeeping = false;

// ----- 馬達速度參數 -----
int stepSize = 0;   // 每次跨越的角度 (步伐)
int speedDelay = 0; // 每步之間的停頓時間

void setup() {
  Serial.begin(115200);
  
  // ==========================================
  // ★ 強制分配獨立計時器,防止蜂鳴器讓馬達當機
  // ==========================================
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  myservo.setPeriodHertz(50); // 標準伺服馬達頻率

  // 伺服馬達初始化
  myservo.attach(Servo_Pin, 500, 2400);
  myservo.write(25);  // 初始停在 25 度的安全位置
  
  dht1.begin();
  Serial.println("System Start!");
}

// ==========================================
// 獨立函式:檢查蜂鳴器 (讓馬達轉動時聲音不會斷掉)
// ==========================================
void checkBuzzer() {
  unsigned long currentMillis = millis();
  int beepOffDelay;
  
  // 距離越近,逼逼聲越急促
  if      (cmMs < 5.0)  beepOffDelay = 100;
  else if (cmMs < 10.0) beepOffDelay = 400;
  else                  beepOffDelay = 1000;

  if (isBeeping) {
    if (currentMillis - lastBeepTime >= 50) {
      noTone(speaker_pin);
      isBeeping = false;
      lastBeepTime = currentMillis;
    }
  } else {
    if (currentMillis - lastBeepTime >= beepOffDelay) {
      tone(speaker_pin, 1000);
      isBeeping = true;
      lastBeepTime = currentMillis;
    }
  }
}

// ==========================================
// 主迴圈
// ==========================================
void loop() {
  unsigned long currentMillis = millis();

  // 1. 每 2 秒讀取一次 DHT11 溫濕度
  if (currentMillis - lastDHTTime >= 2000) {
    lastDHTTime = currentMillis;
    
    humidity = dht1.readHumidity();
    tempC    = dht1.readTemperature();

    if (isnan(humidity) || isnan(tempC)) {
      Serial.println("無法從 DHT 感測器讀取資料!");
    } else {
      Serial.print("濕度: "); Serial.print(humidity); Serial.print("% | ");
      Serial.print("溫度: "); Serial.print(tempC);    Serial.println("°C");
      
      // ==========================================
      // ★ 濕度對應馬達轉速 (4 個檔位)
      // ==========================================
      if (humidity >= 80.0) {
        stepSize = 5;       // 步伐最大
        speedDelay = 2;     // 停頓極短 【最快極速】
      } 
      else if (humidity >= 70.0) {
        stepSize = 3; 
        speedDelay = 10;    // 【快速】
      } 
      else if (humidity >= 60.0) {
        stepSize = 2; 
        speedDelay = 15;    // 【中速】
      } 
      else if (humidity >= 50.0) {
        stepSize = 1; 
        speedDelay = 30;    // 【慢速】
      } 
      else {
        stepSize = 0; 
        speedDelay = 0;     // 濕度不足 50,停止
      }
    }
  }

  // 2. 每 0.1 秒讀取一次超音波距離
  if (currentMillis - lastSonarTime >= 100) {
    lastSonarTime = currentMillis;
    cmMs = ultrasonic_2_3.read();
  }

  // 3. 在主迴圈隨時檢查蜂鳴器
  checkBuzzer();

  // 4. 馬達來回掃動邏輯 (安全區間 25度 ~ 100度)
  if (stepSize > 0 && speedDelay > 0) {
    
    // 從 25 度轉到 100 度
    for (int angle = 25; angle <= 100; angle += stepSize) {
      myservo.write(angle);
      checkBuzzer(); // 確保迴圈卡住時蜂鳴器依然正常叫
      delay(speedDelay);
    }

    // 從 100 度轉回 25 度
    for (int angle = 100; angle >= 25; angle -= stepSize) {
      myservo.write(angle);
      checkBuzzer(); // 確保迴圈卡住時蜂鳴器依然正常叫
      delay(speedDelay);
    }
    
  } else {
    // 如果濕度太低,讓馬達乖乖回到 25 度待機
    myservo.write(25);
  }
}