/* Wokwi 元件配置:
* HC-SR04 Ultrasonic Sensor (Trig: 2, Echo: 3) - 车位1
* HC-SR04 Ultrasonic Sensor (Trig: 4, Echo: 5) - 车位2
* HC-SR04 Ultrasonic Sensor (Trig: 6, Echo: 7) - 车位3
* LCD I2C (0x27) - SDA: A4, SCL: A5
* LED (红色) - 引脚: 8
* LED (绿色) - 引脚: 9
* Pushbutton (进入) - 引脚: 10
* Pushbutton (离开) - 引脚: 11
* Piezo Buzzer - 引脚: 12
*/
/* wokwi-libraries: wire */
/* wokwi-libraries: liquidcrystal-i2c */
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// 传感器引脚定义
#define TRIG1 2
#define ECHO1 3
#define TRIG2 4
#define ECHO2 5
#define TRIG3 6
#define ECHO3 7
// LED和按键引脚
#define RED_LED 8
#define GREEN_LED 9
#define ENTER_BTN 10
#define EXIT_BTN 11
#define BUZZER 12
// 系统参数
#define PARKING_SPACES 3
#define DISTANCE_THRESHOLD 20 // 距离阈值(cm)
#define HOURLY_RATE 5 // 每小时停车费
// 初始化LCD对象
LiquidCrystal_I2C lcd(0x27, 16, 2); // 地址0x27,16列2行
// 车位状态结构体
struct ParkingSpace {
int trigPin;
int echoPin;
bool occupied;
unsigned long entryTime;
};
ParkingSpace spaces[PARKING_SPACES] = {
{TRIG1, ECHO1, false, 0},
{TRIG2, ECHO2, false, 0},
{TRIG3, ECHO3, false, 0}
};
int availableSpaces = PARKING_SPACES;
unsigned long totalRevenue = 0;
// ================== 函数前向声明 ==================
// 解决"was not declared in this scope"错误
void updateLEDs();
void displayStatus();
void vehicleEnter();
void vehicleExit();
void checkParkingSpaces();
bool isVehiclePresent(int trigPin, int echoPin);
// =================================================
void setup() {
// 初始化串口通信
Serial.begin(115200);
// 初始化超声波传感器引脚
for (int i = 0; i < PARKING_SPACES; i++) {
pinMode(spaces[i].trigPin, OUTPUT);
pinMode(spaces[i].echoPin, INPUT);
digitalWrite(spaces[i].trigPin, LOW);
}
// 初始化LED
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
// 初始化按钮
pinMode(ENTER_BTN, INPUT_PULLUP);
pinMode(EXIT_BTN, INPUT_PULLUP);
// 初始化蜂鸣器
pinMode(BUZZER, OUTPUT);
digitalWrite(BUZZER, LOW);
// 初始化LCD
Wire.begin();
lcd.init();
lcd.backlight();
lcd.clear();
// 初始状态显示
updateLEDs();
displayStatus();
Serial.println("智能停车场系统初始化完成");
Serial.println("使用串口监视器查看状态 (波特率: 115200)");
}
void loop() {
// 检测所有车位状态
checkParkingSpaces();
// 处理进入车辆
if (digitalRead(ENTER_BTN) == LOW) {
delay(50); // 消抖
if (digitalRead(ENTER_BTN) == LOW) {
vehicleEnter();
// 等待按钮释放
while(digitalRead(ENTER_BTN) == LOW) delay(10);
}
}
// 处理离开车辆
if (digitalRead(EXIT_BTN) == LOW) {
delay(50); // 消抖
if (digitalRead(EXIT_BTN) == LOW) {
vehicleExit();
// 等待按钮释放
while(digitalRead(EXIT_BTN) == LOW) delay(10);
}
}
// 每2秒更新显示
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate > 2000) {
displayStatus();
lastUpdate = millis();
}
}
// 检测车位状态
void checkParkingSpaces() {
for (int i = 0; i < PARKING_SPACES; i++) {
bool currentState = spaces[i].occupied;
bool newState = isVehiclePresent(spaces[i].trigPin, spaces[i].echoPin);
// 仅当状态改变时更新
if (currentState != newState) {
spaces[i].occupied = newState;
if (newState) {
spaces[i].entryTime = millis();
Serial.print("车位 ");
Serial.print(i+1);
Serial.println(": 车辆停入");
} else {
Serial.print("车位 ");
Serial.print(i+1);
Serial.println(": 车辆离开");
}
// 更新可用车位计数
availableSpaces += newState ? -1 : 1;
updateLEDs();
}
}
}
// 超声波检测函数
bool isVehiclePresent(int trigPin, int echoPin) {
// 发送10微秒脉冲
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 测量回声时间
long duration = pulseIn(echoPin, HIGH, 30000); // 30ms超时
// 计算距离 (cm)
float distance = duration * 0.034 / 2;
// 返回检测结果
return (distance > 0 && distance < DISTANCE_THRESHOLD);
}
// 更新LED状态
void updateLEDs() {
if (availableSpaces == 0) {
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW);
} else {
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
}
}
// 车辆进入处理
void vehicleEnter() {
if (availableSpaces > 0) {
// 更新显示
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("欢迎光临!");
lcd.setCursor(0, 1);
lcd.print("剩余车位: ");
lcd.print(availableSpaces);
// 播放提示音
tone(BUZZER, 1000, 200);
delay(300);
tone(BUZZER, 1500, 200);
Serial.println("车辆进入停车场");
} else {
// 车位已满
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("车位已满!");
lcd.setCursor(0, 1);
lcd.print("请稍后再来");
// 播放错误音
tone(BUZZER, 300, 1000);
Serial.println("尝试进入但车位已满");
}
delay(2000);
displayStatus();
}
// 车辆离开处理
void vehicleExit() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("谢谢惠顾!");
// 查找有车的车位
int occupiedSpace = -1;
for (int i = 0; i < PARKING_SPACES; i++) {
if (spaces[i].occupied) {
occupiedSpace = i;
break;
}
}
if (occupiedSpace != -1) {
// 计算停车时间和费用
unsigned long parkTime = millis() - spaces[occupiedSpace].entryTime;
unsigned long seconds = parkTime / 1000;
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
// 计费规则:不足1小时按1小时计算
int fee = (hours + (minutes > 0 ? 1 : 0)) * HOURLY_RATE;
// 显示费用
lcd.setCursor(0, 1);
lcd.print("费用: $");
lcd.print(fee);
// 更新总收入
totalRevenue += fee;
// 释放车位
spaces[occupiedSpace].occupied = false;
availableSpaces++;
updateLEDs();
// 串口输出
Serial.print("车辆离开,停车时间: ");
Serial.print(hours);
Serial.print("小时 ");
Serial.print(minutes);
Serial.print("分钟,费用: $");
Serial.println(fee);
} else {
// 没有车辆
lcd.setCursor(0, 1);
lcd.print("无车辆离开");
Serial.println("离开按钮按下,但无车辆停放");
}
// 播放提示音
tone(BUZZER, 1500, 200);
delay(300);
tone(BUZZER, 1000, 200);
delay(3000);
displayStatus();
}
// 显示系统状态
void displayStatus() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("可用: ");
lcd.print(availableSpaces);
lcd.print("/");
lcd.print(PARKING_SPACES);
lcd.setCursor(0, 1);
lcd.print("收入: $");
lcd.print(totalRevenue);
}