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);
}
}

#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);
}
}