void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32!");
}
void loop() {
// put your main code here, to run repeatedly:
delay(10); // this speeds up the simulation
}
#include <LiquidCrystal_I2C.h>
#include <DHTesp.h>
// 组件引脚定义
#define DHTPIN 4
#define RELAY_PIN 25
#define ENCODER_CLK 34
#define ENCODER_DT 35
#define ENCODER_SW 32
// 系统参数
const float MIN_TEMP = 10.0;
const float MAX_TEMP = 40.0;
volatile float setTemp = 25.0; // 初始设定温度
float currentTemp = 0.0;
bool relayState = false;
// 组件初始化
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C地址0x27或0x3F
DHTesp dhtSensor;
// 旋转编码器变量
volatile int8_t encoderDirection = 0;
volatile bool encoderChanged = false;
volatile bool buttonPressed = false;
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
// 防抖定时器
unsigned long lastEncoderTime = 0;
unsigned long lastButtonTime = 0;
const unsigned long DEBOUNCE_DELAY = 50;
// 温度更新定时器
unsigned long lastTempUpdate = 0;
const unsigned long TEMP_UPDATE_INTERVAL = 2000;
// 旋转编码器中断服务程序
void IRAM_ATTR encoderISR() {
portENTER_CRITICAL_ISR(&mux);
static uint8_t prevState = 3; // 初始状态 (CLK=1, DT=1)
uint8_t clkState = digitalRead(ENCODER_CLK);
uint8_t dtState = digitalRead(ENCODER_DT);
uint8_t currentState = (clkState << 1) | dtState;
uint8_t stateChange = (prevState << 2) | currentState;
// 检测旋转方向 (状态机)
if (stateChange == 0b0011 || stateChange == 0b1000 ||
stateChange == 0b1110 || stateChange == 0b0101) {
encoderDirection = 1; // 顺时针
encoderChanged = true;
}
else if (stateChange == 0b1011 || stateChange == 0b1101 ||
stateChange == 0b0110 || stateChange == 0b0000) {
encoderDirection = -1; // 逆时针
encoderChanged = true;
}
prevState = currentState;
portEXIT_CRITICAL_ISR(&mux);
}
// 按钮中断服务程序
void IRAM_ATTR buttonISR() {
if (millis() - lastButtonTime > DEBOUNCE_DELAY) {
buttonPressed = true;
lastButtonTime = millis();
}
}
// 更新LCD显示
void updateDisplay() {
lcd.clear();
// 第一行: 当前温度
lcd.setCursor(0, 0);
lcd.print("Cur: ");
lcd.print(currentTemp, 1);
lcd.print("C");
// 右上角显示继电器状态
lcd.setCursor(12, 0);
lcd.print(relayState ? "ON " : "OFF");
// 第二行: 设定温度
lcd.setCursor(0, 1);
lcd.print("Set: ");
lcd.print(setTemp, 1);
lcd.print("C");
}
void setup() {
// 初始化串口
Serial.begin(115200);
// 初始化LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Initializing...");
// 初始化传感器
dhtSensor.setup(DHTPIN, DHTesp::DHT22);
// 配置引脚
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
pinMode(ENCODER_CLK, INPUT_PULLUP);
pinMode(ENCODER_DT, INPUT_PULLUP);
pinMode(ENCODER_SW, INPUT_PULLUP);
// 附加中断
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), encoderISR, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_DT), encoderISR, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_SW), buttonISR, FALLING);
// 初始温度读取
TempAndHumidity data = dhtSensor.getTempAndHumidity();
currentTemp = data.temperature;
delay(2000); // 等待传感器稳定
updateDisplay();
}
void loop() {
// 处理旋转编码器变化
if (encoderChanged && millis() - lastEncoderTime > DEBOUNCE_DELAY) {
portENTER_CRITICAL(&mux);
setTemp += encoderDirection * 0.5; // 每次变化0.5°C
// 应用温度限制
if (setTemp < MIN_TEMP) setTemp = MIN_TEMP;
if (setTemp > MAX_TEMP) setTemp = MAX_TEMP;
encoderChanged = false;
portEXIT_CRITICAL(&mux);
updateDisplay();
lastEncoderTime = millis();
}
// 处理按钮按下
if (buttonPressed) {
setTemp = 25.0; // 重置为默认温度
buttonPressed = false;
updateDisplay();
}
// 定时更新温度
if (millis() - lastTempUpdate >= TEMP_UPDATE_INTERVAL) {
lastTempUpdate = millis();
// 读取温度
TempAndHumidity data = dhtSensor.getTempAndHumidity();
if (!isnan(data.temperature)) {
currentTemp = data.temperature;
}
// 控制继电器
bool newRelayState = (currentTemp < setTemp);
if (newRelayState != relayState) {
relayState = newRelayState;
digitalWrite(RELAY_PIN, relayState ? HIGH : LOW);
}
// 更新显示
updateDisplay();
// 调试输出
Serial.print("Current: ");
Serial.print(currentTemp);
Serial.print("C, Set: ");
Serial.print(setTemp);
Serial.print("C, Relay: ");
Serial.println(relayState ? "ON" : "OFF");
}
}