#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <EEPROM.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#define BUZZER_PIN 3
#define LED_PIN 4
#define MQ2_PIN A0
#define ALARM_OFF_BTN 5
#define SET_MODE_BTN 6
#define CONFIRM_BTN 7
// 默认阈值
float tempThreshold = 50.0;
float humThreshold = 20.0;
int gasThreshold = 600;
// 报警状态
bool alarmActive = false;
bool alarmSilenced = false;
bool conditionsMet = false; // 跟踪当前是否满足报警条件
// 设置模式
bool settingMode = false;
byte settingItem = 0; // 0:温度, 1:湿度, 2:气体
// 时间变量
int hours = 10;
int minutes = 26;
// 报警历史记录
const int maxHistory = 5;
String alarmHistory[maxHistory];
int historyIndex = 0;
// 按钮状态跟踪
bool lastAlarmOffState = HIGH;
bool lastSetModeState = HIGH;
bool lastConfirmState = HIGH;
unsigned long lastDebounceTime = 0;
void setup() {
Serial.begin(9600);
// 初始化OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
dht.begin();
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(ALARM_OFF_BTN, INPUT_PULLUP);
pinMode(SET_MODE_BTN, INPUT_PULLUP);
pinMode(CONFIRM_BTN, INPUT_PULLUP);
// 从EEPROM加载阈值
EEPROM.get(0, tempThreshold);
EEPROM.get(sizeof(float), humThreshold);
EEPROM.get(2*sizeof(float), gasThreshold);
// 初始化报警历史
for(int i=0; i<maxHistory; i++) {
alarmHistory[i] = "";
}
display.clearDisplay();
display.display();
}
void loop() {
static unsigned long lastUpdate = 0;
static unsigned long lastMinute = 0;
static unsigned long lastAlarmCheck = 0;
static unsigned long lastButtonCheck = 0;
unsigned long currentMillis = millis();
// 每分钟更新时间
if(currentMillis - lastMinute >= 60000) {
lastMinute = currentMillis;
minutes++;
if(minutes >= 60) {
minutes = 0;
hours++;
if(hours >= 24) {
hours = 0;
}
}
}
// 每2秒更新传感器数据
if(currentMillis - lastUpdate >= 2000 || lastUpdate == 0) {
lastUpdate = currentMillis;
float temp = dht.readTemperature();
float hum = dht.readHumidity();
int gasValue = analogRead(MQ2_PIN);
// 检查报警条件
conditionsMet = (temp > tempThreshold || hum < humThreshold || gasValue > gasThreshold);
if(conditionsMet) {
if(!alarmSilenced) {
alarmActive = true;
}
// 记录报警历史
String record = String(hours) + ":" + (minutes < 10 ? "0" + String(minutes) : String(minutes)) + " ";
record += "T:" + String(temp) + " H:" + String(hum) + " G:" + String(gasValue);
alarmHistory[historyIndex] = record;
historyIndex = (historyIndex + 1) % maxHistory;
} else {
// 环境参数恢复正常,重置报警状态
alarmActive = false;
alarmSilenced = false;
}
// 显示信息
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
if(settingMode) {
displaySettingScreen();
} else {
displayNormalScreen(temp, hum, gasValue);
}
display.display();
}
// 处理报警
if(alarmActive && !alarmSilenced) {
if(currentMillis - lastAlarmCheck >= 100) {
lastAlarmCheck = currentMillis;
triggerAlarm();
}
} else {
noTone(BUZZER_PIN);
digitalWrite(LED_PIN, LOW);
}
// 每100ms检查按钮状态
if(currentMillis - lastButtonCheck >= 100) {
lastButtonCheck = currentMillis;
checkButtons();
}
}
void displayNormalScreen(float temp, float hum, int gasValue) {
// 显示时间
display.setCursor(0, 0);
display.print("Time: ");
display.print(hours);
display.print(":");
if(minutes < 10) display.print("0");
display.print(minutes);
// 显示温度
display.setCursor(0, 16);
display.print("Temp: ");
display.print(temp);
display.print("C");
display.print(" (");
display.print(tempThreshold);
display.print(")");
// 显示湿度
display.setCursor(0, 28);
display.print("Hum: ");
display.print(hum);
display.print("%");
display.print(" (");
display.print(humThreshold);
display.print(")");
// 显示气体浓度
display.setCursor(0, 40);
display.print("Gas: ");
display.print(gasValue);
display.print(" (");
display.print(gasThreshold);
display.print(")");
// 显示报警状态
display.setCursor(0, 52);
if(alarmActive) {
if(alarmSilenced) {
display.print("Alarm silenced");
} else {
display.print("ALARM ACTIVE!");
}
} else {
display.print("System normal");
}
}
void displaySettingScreen() {
display.setCursor(0, 0);
display.print("SETTING MODE");
// 显示当前设置项指示器
display.setCursor(110, 0);
display.print(settingItem + 1);
display.print("/3");
// 确保显示位置正确
display.setCursor(0, 16);
display.print("Temp Threshold:");
display.setCursor(0, 26);
display.print(tempThreshold);
display.print("C");
display.setCursor(0, 36);
display.print("Hum Threshold:");
display.setCursor(0, 46);
display.print(humThreshold);
display.print("%");
display.setCursor(0, 56);
display.print("Gas Threshold:");
display.setCursor(0, 66);
display.print(gasThreshold);
// 高亮当前设置项
switch(settingItem) {
case 0:
display.fillRect(0, 26, 50, 8, WHITE);
display.setTextColor(BLACK);
display.setCursor(0, 26);
display.print(tempThreshold);
display.print("C");
display.setTextColor(WHITE);
break;
case 1:
display.fillRect(0, 46, 50, 8, WHITE);
display.setTextColor(BLACK);
display.setCursor(0, 46);
display.print(humThreshold);
display.print("%");
display.setTextColor(WHITE);
break;
case 2:
display.fillRect(0, 66, 50, 8, WHITE);
display.setTextColor(BLACK);
display.setCursor(0, 66);
display.print(gasThreshold);
display.setTextColor(WHITE);
break;
}
}
void triggerAlarm() {
static int blinkCount = 0;
static bool buzzerState = false;
// LED闪烁模式:快速闪烁3次
if(blinkCount < 6) {
digitalWrite(LED_PIN, blinkCount % 2 == 0);
blinkCount++;
} else {
digitalWrite(LED_PIN, LOW);
blinkCount = 0;
}
// 蜂鸣器警报音
buzzerState = !buzzerState;
if(buzzerState) {
tone(BUZZER_PIN, 1000);
} else {
tone(BUZZER_PIN, 1500);
}
}
void checkButtons() {
// 读取当前按钮状态
bool alarmOffState = digitalRead(ALARM_OFF_BTN);
bool setModeState = digitalRead(SET_MODE_BTN);
bool confirmState = digitalRead(CONFIRM_BTN);
// 报警关闭/开启按钮处理
if(alarmOffState == LOW && lastAlarmOffState == HIGH && millis() - lastDebounceTime > 300) {
lastDebounceTime = millis();
// 切换报警静音状态
alarmSilenced = !alarmSilenced;
Serial.println(alarmSilenced ? "Alarm silenced" : "Alarm enabled");
}
lastAlarmOffState = alarmOffState;
// 设置模式按钮处理
if(setModeState == LOW && lastSetModeState == HIGH && millis() - lastDebounceTime > 300) {
lastDebounceTime = millis();
settingMode = !settingMode;
if(settingMode) {
settingItem = 0; // 进入设置模式时重置为第一个设置项
} else {
// 保存阈值到EEPROM
EEPROM.put(0, tempThreshold);
EEPROM.put(sizeof(float), humThreshold);
EEPROM.put(2*sizeof(float), gasThreshold);
}
}
lastSetModeState = setModeState;
// 确认/调整按钮处理
if(confirmState == LOW && lastConfirmState == HIGH && millis() - lastDebounceTime > 300) {
lastDebounceTime = millis();
if(settingMode) {
// 短按调整参数值
switch(settingItem) {
case 0: // 温度阈值
tempThreshold += 1.0;
if(tempThreshold > 100.0) tempThreshold = 0.0;
break;
case 1: // 湿度阈值
humThreshold += 1.0;
if(humThreshold > 100.0) humThreshold = 0.0;
break;
case 2: // 气体阈值
gasThreshold += 10;
if(gasThreshold > 1023) gasThreshold = 0;
break;
}
// 立即更新显示
displaySettingScreen();
display.display();
}
}
lastConfirmState = confirmState;
// 在设置模式下,长按确认按钮切换设置项
if(settingMode && confirmState == LOW && millis() - lastDebounceTime > 1000) {
settingItem = (settingItem + 1) % 3;
lastDebounceTime = millis();
// 立即更新显示
displaySettingScreen();
display.display();
}
}