// 包含必要的库文件
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "DHT.h"
// 定义常量和引脚
#define DHTPIN 2 // DHT11数据引脚
#define DHTTYPE DHT11 // DHT传感器类型
#define MQ2PIN A0 // MQ-2传感器引脚
#define BUZZER_PIN 8 // 蜂鸣器引脚
#define LED_PIN 9 // LED引脚
#define SET_BUTTON_PIN 3 // 设置按键引脚
#define CONFIRM_BUTTON_PIN 4 // 确认按键引脚
#define MODE_BUTTON_PIN 5 // 模式切换按键
#define THRESHOLD_SAVE_ADDR 0 // EEPROM保存地址
// 定义状态
#define STATE_MAIN 0 // 主显示状态
#define STATE_SETTING 1 // 设置状态
#define STATE_ALARM 2 // 报警状态
// 定义阈值和变量
float temperature = 0.0; // 温度
float humidity = 0.0; // 湿度
int smokeLevel = 0; // 烟雾浓度
int tempThreshold = 40; // 温度阈值
int smokeThreshold = 300; // 烟雾阈值
int currentState = STATE_MAIN; // 当前状态
int settingMode = 0; // 设置模式:0-温度阈值,1-烟雾阈值
unsigned long lastButtonPress = 0; // 上次按键时间
unsigned long lastAlarmTime = 0; // 上次报警时间
bool alarmEnabled = true; // 报警启用状态
DHT dht(DHTPIN, DHTTYPE); // DHT传感器对象
// OLED显示屏对象
Adafruit_SSD1306 display(128, 64, &Wire, -1);
// 初始化函数
void setup() {
Serial.begin(9600);
dht.begin();
// 初始化引脚
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(SET_BUTTON_PIN, INPUT_PULLUP);
pinMode(CONFIRM_BUTTON_PIN, INPUT_PULLUP);
pinMode(MODE_BUTTON_PIN, INPUT_PULLUP);
// 从EEPROM加载阈值
loadThresholds();
// 初始化OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while(true); // 无法初始化则循环
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Fire Alarm System");
display.display();
delay(2000);
}
// 主循环函数
void loop() {
// 读取传感器数据
readSensors();
// 处理按键输入
handleButtons();
// 根据当前状态执行不同操作
switch(currentState) {
case STATE_MAIN:
displayMainScreen();
checkAlarmConditions();
break;
case STATE_SETTING:
displaySettingScreen();
break;
case STATE_ALARM:
displayAlarmScreen();
triggerAlarm();
break;
}
delay(100); // 短暂延时,避免CPU占用过高
}
// 读取传感器数据
void readSensors() {
// 读取温湿度
humidity = dht.readHumidity();
temperature = dht.readTemperature();
// 读取烟雾浓度
smokeLevel = analogRead(MQ2PIN);
// 简单的传感器数据校验
if (isnan(humidity) || isnan(temperature)) {
Serial.println(F("Failed to read DHT sensor!"));
}
}
// 处理按键输入
void handleButtons() {
// 去抖动处理
if (millis() - lastButtonPress < 200) return;
// 设置按键:切换主界面和设置界面
if (!digitalRead(SET_BUTTON_PIN)) {
lastButtonPress = millis();
if (currentState == STATE_MAIN) {
currentState = STATE_SETTING;
settingMode = 0; // 默认为温度设置
} else if (currentState == STATE_SETTING) {
currentState = STATE_MAIN;
saveThresholds(); // 保存设置
} else if (currentState == STATE_ALARM) {
alarmEnabled = false; // 关闭报警
currentState = STATE_MAIN;
}
}
// 模式切换按键:在设置界面切换温度/烟雾阈值
if (!digitalRead(MODE_BUTTON_PIN) && currentState == STATE_SETTING) {
lastButtonPress = millis();
settingMode = (settingMode + 1) % 2;
}
// 确认按键:在设置界面调整阈值
if (!digitalRead(CONFIRM_BUTTON_PIN) && currentState == STATE_SETTING) {
lastButtonPress = millis();
if (settingMode == 0) {
tempThreshold = (tempThreshold + 1) % 100; // 温度阈值0-99℃
} else {
smokeThreshold = (smokeThreshold + 50) % 1000; // 烟雾阈值0-950
}
}
}
// 显示主界面
void displayMainScreen() {
display.clearDisplay();
// 显示时间(模拟,实际项目中可添加RTC模块)
display.setTextSize(1);
display.setCursor(0, 0);
display.print("Time: 12:34:56");
// 显示温湿度
display.setCursor(0, 16);
display.print("Temp: ");
display.print(temperature);
display.print(" C ");
display.print("Humi: ");
display.print(humidity);
display.println(" %");
// 显示烟雾浓度
display.setCursor(0, 32);
display.print("Smoke: ");
display.print(smokeLevel);
display.println(" ppm");
// 显示火灾风险等级(扩展功能)
int riskLevel = calculateRiskLevel();
display.setCursor(0, 48);
display.print("Risk: ");
if (riskLevel == 0) {
display.print("LOW");
display.setTextColor(SSD1306_GREEN);
} else if (riskLevel == 1) {
display.print("MEDIUM");
display.setTextColor(SSD1306_YELLOW);
} else {
display.print("HIGH!");
display.setTextColor(SSD1306_RED);
}
display.setTextColor(SSD1306_WHITE);
display.display();
}
// 显示设置界面
void displaySettingScreen() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Setting Thresholds");
if (settingMode == 0) {
display.setCursor(0, 20);
display.print("Temp Threshold: ");
display.print(tempThreshold);
display.println(" C");
display.setCursor(0, 40);
display.println("> Smoke: ");
display.print(smokeThreshold);
display.println(" ppm");
} else {
display.setCursor(0, 20);
display.println("Temp: ");
display.print(tempThreshold);
display.println(" C");
display.setCursor(0, 40);
display.print("> Smoke Threshold: ");
display.print(smokeThreshold);
display.println(" ppm");
}
display.setCursor(0, 56);
display.println("Set: Button1 Mode: Button3");
display.display();
}
// 显示报警界面
void displayAlarmScreen() {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 10);
display.println("ALARM!");
display.setTextSize(1);
display.setCursor(0, 40);
display.print("Temp: ");
display.print(temperature);
display.print(" C ");
display.print("Smoke: ");
display.print(smokeLevel);
display.println(" ppm");
display.setCursor(0, 56);
display.println("Press to Stop");
display.display();
}
// 检查报警条件
void checkAlarmConditions() {
if (temperature > tempThreshold || smokeLevel > smokeThreshold) {
currentState = STATE_ALARM;
lastAlarmTime = millis();
alarmEnabled = true;
}
}
// 触发报警
void triggerAlarm() {
if (!alarmEnabled) return; // 如果报警被禁用,不执行
unsigned long currentTime = millis();
int blinkRate = 300; // 闪烁频率
// LED闪烁报警(每个人可自定义闪烁方式)
if ((currentTime - lastAlarmTime) / blinkRate % 2 == 0) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
// 蜂鸣器报警(每个人可自定义报警声音)
if ((currentTime - lastAlarmTime) / 100 % 4 < 2) {
tone(BUZZER_PIN, 1000); // 1000Hz音调
} else {
noTone(BUZZER_PIN);
}
}
// 计算火灾风险等级(扩展功能)
int calculateRiskLevel() {
// 基于温度和烟雾浓度综合计算风险等级
float tempFactor = temperature / 100.0;
float smokeFactor = smokeLevel / 1000.0;
float risk = tempFactor * 0.6 + smokeFactor * 0.4; // 温度占60%,烟雾占40%
if (risk < 0.3) return 0; // 低风险
else if (risk < 0.7) return 1; // 中风险
else return 2; // 高风险
}
// 保存阈值到EEPROM
void saveThresholds() {
EEPROM.write(THRESHOLD_SAVE_ADDR, tempThreshold);
EEPROM.write(THRESHOLD_SAVE_ADDR + 1, smokeThreshold >> 8);
EEPROM.write(THRESHOLD_SAVE_ADDR + 2, smokeThreshold & 0xFF);
}
// 从EEPROM加载阈值
void loadThresholds() {
tempThreshold = EEPROM.read(THRESHOLD_SAVE_ADDR);
int highByte = EEPROM.read(THRESHOLD_SAVE_ADDR + 1);
int lowByte = EEPROM.read(THRESHOLD_SAVE_ADDR + 2);
smokeThreshold = (highByte << 8) | lowByte;
// 如果EEPROM中没有有效数据,设置默认值
if (tempThreshold == 255) tempThreshold = 40;
if (smokeThreshold == 0) smokeThreshold = 300;
}