#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
// OLED显示屏参数定义
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 传感器引脚定义
int lightSensorPin = A0; // 光照传感器
int pirSensorPin = 4; // PIR运动传感器
int buttonUpPin = 2; // 上调按钮
int buttonDownPin = 3; // 下调按钮
int ledPin = 13; // 主LED灯
int buzzerPin = 14; // 蜂鸣器引脚 (D14 = A0,若A0被占用可改用其他引脚)
// 新增MQ2气体传感器和LED条形图引脚
int mq2SensorPin = A1; // MQ2传感器模拟输入引脚
int gasLedPins[9] = {5, 6, 7, 8, 9, 10, 11, 12, 13}; // LED条形图引脚 (D5-D13对应A1-A9)
// 新增RTC对象 - DS1307
RTC_DS1307 rtc;
// 全局变量
int lightThreshold = 500; // 光照阈值
unsigned long lastMotionTime = 0; // 上次检测到运动的时间
unsigned long motionStartTime = 0; // 运动开始时间
bool isMotionDetected = false; // 当前是否检测到运动
bool wasMotionDetected = false; // 上一次是否检测到运动
unsigned int pedestrianCount = 0; // 行人计数
unsigned long lastButtonPress = 0; // 上次按钮按下时间
int gasThreshold = 300; // 气体浓度阈值
int gasValue = 0; // 当前气体浓度值
bool buzzerState = LOW; // 蜂鸣器状态
unsigned long lastBuzzerTime = 0; // 上次蜂鸣器状态切换时间
const unsigned long BUZZER_INTERVAL = 500; // 蜂鸣器响/停间隔时间(毫秒)
// 初始化函数
void setup() {
pinMode(pirSensorPin, INPUT);
pinMode(buttonUpPin, INPUT_PULLUP);
pinMode(buttonDownPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
pinMode(buzzerPin, OUTPUT); // 初始化蜂鸣器引脚
digitalWrite(ledPin, LOW);
digitalWrite(buzzerPin, LOW); // 初始关闭蜂鸣器
// 初始化MQ2传感器和LED条形图引脚
pinMode(mq2SensorPin, INPUT);
for(int i = 0; i < 9; i++) {
pinMode(gasLedPins[i], OUTPUT);
digitalWrite(gasLedPins[i], LOW);
}
// 初始化RTC
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
// 如果RTC时间未设置,则设置初始时间
if (!rtc.isrunning()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// 初始化OLED显示屏
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println(" Smart Street Light\n");
display.println(" Counter v1.1\n");
display.println(" Welcome ! ");
display.display();
delay(2000);
}
// 主循环函数
void loop() {
int lightValue = analogRead(lightSensorPin);
isMotionDetected = digitalRead(pirSensorPin) == HIGH;
// 读取MQ2气体传感器数据
gasValue = analogRead(mq2SensorPin);
// 更新LED条形图显示
updateLedBarGraph(gasValue);
// 控制蜂鸣器(当气体浓度超过阈值时触发)
controlBuzzer(gasValue);
// 行人计数逻辑
if (isMotionDetected && !wasMotionDetected) {
motionStartTime = millis();
} else if (!isMotionDetected && wasMotionDetected && (millis() - motionStartTime > 500)) {
pedestrianCount++;
}
wasMotionDetected = isMotionDetected;
if (isMotionDetected) {
lastMotionTime = millis();
}
handleButtonInput();
bool shouldTurnOn = false;
if (lightValue < lightThreshold) {
if (isMotionDetected || (millis() - lastMotionTime <= 10000 && lastMotionTime != 0)) {
shouldTurnOn = true;
}
}
digitalWrite(ledPin, shouldTurnOn ? HIGH : LOW);
// 移除气体数据显示,只传递需要的参数
updateDisplay(lightValue, isMotionDetected, lightThreshold, pedestrianCount);
delay(100);
}
// 按键处理函数
void handleButtonInput() {
unsigned long currentTime = millis();
if (digitalRead(buttonUpPin) == LOW && currentTime - lastButtonPress > 200) {
lightThreshold = min(lightThreshold + 50, 1023);
lastButtonPress = currentTime;
}
if (digitalRead(buttonDownPin) == LOW && currentTime - lastButtonPress > 200) {
lightThreshold = max(lightThreshold - 50, 0);
lastButtonPress = currentTime;
}
// 同时按下两个按钮3秒重置计数器
static unsigned long buttonDownTime = 0;
static bool isButtonDown = false;
if (digitalRead(buttonUpPin) == LOW && digitalRead(buttonDownPin) == LOW) {
if (!isButtonDown) {
isButtonDown = true;
buttonDownTime = currentTime;
} else if (currentTime - buttonDownTime > 3000) {
pedestrianCount = 0;
lastButtonPress = currentTime;
isButtonDown = false;
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 24);
display.println("Counter reset!");
display.display();
delay(1000);
}
} else {
isButtonDown = false;
}
}
// 更新LED条形图显示(仅使用A1-A9连接到D5-D13)
void updateLedBarGraph(int gasValue) {
// 关闭所有LED
for(int i = 0; i < 9; i++) {
digitalWrite(gasLedPins[i], LOW);
}
// 根据气体浓度点亮相应的LED
// 将0-1023的模拟值映射到1-9个LED
int ledCount = map(gasValue, 0, 1023, 0, 9);
// 点亮对应的LED
for(int i = 0; i < ledCount; i++) {
digitalWrite(gasLedPins[i], HIGH);
}
}
// 控制蜂鸣器(当气体浓度超过阈值时触发)
void controlBuzzer(int gasValue) {
// 当气体浓度超过阈值时触发蜂鸣器
if (gasValue > gasThreshold) {
unsigned long currentTime = millis();
// 每500ms切换一次蜂鸣器状态
if (currentTime - lastBuzzerTime >= BUZZER_INTERVAL) {
lastBuzzerTime = currentTime;
buzzerState = !buzzerState;
digitalWrite(buzzerPin, buzzerState);
}
} else {
// 气体浓度正常时关闭蜂鸣器
digitalWrite(buzzerPin, LOW);
buzzerState = LOW;
lastBuzzerTime = millis();
}
}
// 更新OLED显示(仅显示时间、光照强度、运动状态、光照阈值和行人计数)
void updateDisplay(int lightValue, bool motionDetected, int lightThreshold, unsigned int count) {
display.clearDisplay();
display.setTextSize(1);
DateTime now = rtc.now();
// 第一行:时间显示
display.setCursor(0, 0);
display.print("T: ");
display.print(now.year(), DEC);
display.print('/');
display.print(now.month(), DEC);
display.print('/');
display.print(now.day(), DEC);
display.print(' ');
display.print(now.hour(), DEC);
display.print(':');
if (now.minute() < 10) display.print('0');
display.print(now.minute(), DEC);
display.print(':');
if (now.second() < 10) display.print('0');
display.print(now.second(), DEC);
// 第二行:光照强度
display.setCursor(0, 12);
display.print("Light: ");
display.print(lightValue);
display.print("");
// 第三行:运动状态
display.setCursor(0, 24);
display.print("Motion: ");
display.print(motionDetected ? "Yes" : "No");
// 第四行:光照阈值
display.setCursor(0, 36);
display.print("Threshold: ");
display.print(lightThreshold);
// 第五行:行人计数
display.setCursor(0, 48);
display.print("People: ");
display.print(count);
display.display();
}