设计基于Arduino的双向交通灯系统

img


实验具体要求如上图,代码需配有适当注释,以及元件连接示图。。

2301_77573916

来自NewBing和LP的编写:

#include <Adafruit_GFX.h>           // 引入点阵库
#include <Adafruit_LEDBackpack.h>   // 引入点阵库

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();   // 创建点阵对象

const int buttonPin = 2;   // 按键引脚
const int buzzerPin = 3;   // 蜂鸣器引脚

// 定义交通灯引脚
const int northGreenPin = 4;
const int northYellowPin = 5;
const int northRedPin = 6;
const int southGreenPin = 7;
const int southYellowPin = 8;
const int southRedPin = 9;
const int westGreenPin = 10;
const int westYellowPin = 11;
const int westRedPin = 12;
const int eastGreenPin = 13;
const int eastYellowPin = 14;
const int eastRedPin = 15;

// 定义交通灯状态
enum TrafficLightState {
  RED,
  YELLOW,
  GREEN
};

TrafficLightState northSouthState = RED;  // 南北方向的交通灯状态
TrafficLightState eastWestState = GREEN;  // 东西方向的交通灯状态

int countdownTime = 10;  // 初始倒计时时间为10秒
int emergencyState = 0;  // 紧急状态,默认为非紧急状态

void setup() {
  // 初始化点阵显示模块
  matrix.begin(0x70);

  // 设置交通灯引脚为输出模式
  pinMode(northGreenPin, OUTPUT);
  pinMode(northYellowPin, OUTPUT);
  pinMode(northRedPin, OUTPUT);
  pinMode(southGreenPin, OUTPUT);
  pinMode(southYellowPin, OUTPUT);
  pinMode(southRedPin, OUTPUT);
  pinMode(westGreenPin, OUTPUT);
  pinMode(westYellowPin, OUTPUT);
  pinMode(westRedPin, OUTPUT);
  pinMode(eastGreenPin, OUTPUT);
  pinMode(eastYellowPin, OUTPUT);
  pinMode(eastRedPin, OUTPUT);

  // 设置按键引脚为输入模式
  pinMode(buttonPin, INPUT_PULLUP);
  
  // 设置蜂鸣器引脚为输出模式
  pinMode(buzzerPin, OUTPUT);
}

void loop() {
  // 检测按键状态
  if (digitalRead(buttonPin) == LOW) {
    // 按下按键,进入紧急状态
    emergencyState = 1;
  } else {
    // 松开按键,退出紧急状态
    emergencyState = 0;
  }

  // 根据紧急状态和倒计时时间显示交通灯状态和倒计时时间
  if (emergencyState == 1) {
    // 紧急状态下,所有交通灯为红色
    setAllLights(RED);
    countdownTime = 0;  // 紧急状态下,倒计时时间为0
    // 触发蜂鸣器报警
    tone(buzzerPin, 1000, 1000);  
  } else {
    // 非紧急状态下,正常显示交通灯状态和倒计时时间
    // 倒计时时间为0时,切换交通灯方向并重新开始倒计时
    if (countdownTime == 0) {
      switchLights();
      countdownTime = 10;  // 重新开始倒计时
    }

    // 显示交通灯状态和倒计时时间
    displayLights();
    displayCountdown();
    countdownTime--;  // 每秒减少倒计时时间
  }

  delay(1000);  // 延迟1秒
}

// 设置所有交通灯状态
void setAllLights(TrafficLightState state) {
  digitalWrite(northGreenPin, state == GREEN ? HIGH : LOW);
  digitalWrite(northYellowPin, state == YELLOW ? HIGH : LOW);
  digitalWrite(northRedPin, state == RED ? HIGH : LOW);
  digitalWrite(southGreenPin, state == GREEN ? HIGH : LOW);
  digitalWrite(southYellowPin, state == YELLOW ? HIGH : LOW);
  digitalWrite(southRedPin, state == RED ? HIGH : LOW);
  digitalWrite(westGreenPin, state == GREEN ? HIGH : LOW);
  digitalWrite(westYellowPin, state == YELLOW ? HIGH : LOW);
  digitalWrite(westRedPin, state == RED ? HIGH : LOW);
  digitalWrite(eastGreenPin, state == GREEN ? HIGH : LOW);
  digitalWrite(eastYellowPin, state == YELLOW ? HIGH : LOW);
  digitalWrite(eastRedPin, state == RED ? HIGH : LOW);
}

// 切换交通灯方向
void switchLights() {
  if (northSouthState == RED && eastWestState == GREEN) {
    northSouthState = GREEN;
    eastWestState = RED;
  } else {
    northSouthState = RED;
    eastWestState = GREEN;
  }
}

// 显示交通灯状态
void displayLights() {
  setAllLights(RED);  // 首先将所有交通灯置为红色

  if (northSouthState == GREEN) {
    digitalWrite(northGreenPin, HIGH);
    digitalWrite(southGreenPin, HIGH);
  } else if (northSouthState == YELLOW) {
    digitalWrite(northYellowPin, HIGH);
    digitalWrite(southYellowPin, HIGH);
  } else if (northSouthState == RED) {
    digitalWrite(northRedPin, HIGH);
    digitalWrite(southRedPin, HIGH);
  }

  if (eastWestState == GREEN) {
    digitalWrite(westGreenPin, HIGH);
    digitalWrite(eastGreenPin, HIGH);
  } else if (eastWestState == YELLOW) {
    digitalWrite(westYellowPin, HIGH);
    digitalWrite(eastYellowPin, HIGH);
  } else if (eastWestState == RED) {
    digitalWrite(westRedPin, HIGH);
    digitalWrite(eastRedPin, HIGH);
  }
}

// 显示倒计时时间
void displayCountdown() {
  matrix.clear();  // 清除点阵显示

  // 将倒计时时间转换为字符数组
  char countdownStr[2];
  sprintf(countdownStr, "%d", countdownTime);

  // 在点阵显示上显示倒计时时间
  matrix.print(countdownStr);

  // 刷新显示
  matrix.writeDisplay();
}


用了Adafruit的点阵库,你需要安装Adafruit点阵库.

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,具体的实现思路及完整代码如下。
为了实现上述双向交通灯系统,需要完成以下几个步骤:

1、 连接硬件:将Arduino主板、发光二极管、按键、蜂鸣器、点阵显示模块等硬件按照要求连接起来。连接时需要注意硬件连接的线路和引脚号。

2、 编写程序:编写Arduino程序,包括按键控制、倒计时、方向控制、状态显示等功能。具体实现步骤如下:

  • 定义各个引脚:定义发光二极管、按键、蜂鸣器、点阵显示模块等硬件的引脚号。

  • 初始化引脚:在setup()函数中初始化引脚,将各个硬件的引脚设置为输入或输出。

  • 定义变量:定义需要用到的变量,例如倒计时时间、通行方向、紧急状态等。

  • 控制交通灯:在loop()函数中,根据当前通行方向控制红、黄、绿三个发光二极管的状态。倒计时过程中,通过点阵显示模块显示倒计时时间。

  • 按键控制:通过按键控制倒计时时间、人行道控制以及紧急状态控制。

  • 倒计时功能:使用millis()函数实现倒计时功能,每隔一秒更新倒计时时间,并在点阵显示模块上显示剩余时间。

  • 紧急状态:在紧急状态下,所有发光二极管都点亮,同时蜂鸣器发出警报声。

3、 调试程序:将程序上传到Arduino主板中,进行调试和测试,确保各个功能正常运行。

下面是一个简单的Arduino程序示例,实现了上述要求的基本功能:

// 定义引脚
#define EAST_GREEN_LED 2
#define EAST_YELLOW_LED 3
#define EAST_RED_LED 4
#define WEST_GREEN_LED 5
#define WEST_YELLOW_LED 6
#define WEST_RED_LED 7
#define BUTTON_1 8
#define BUTTON_2 9
#define BUZZER 10
#define MATRIX_CLK 11
#define MATRIX_DIN 12
#define MATRIX_CS 13

// 定义变量
int direction = 0; // 0:东西方向,1:南北方向
int countdown = 10; // 倒计时时间,单位为秒
bool emergency = false; // 紧急状态

void setup() {
  // 初始化引脚
  pinMode(EAST_GREEN_LED, OUTPUT);
  pinMode(EAST_YELLOW_LED, OUTPUT);
  pinMode(EAST_RED_LED, OUTPUT);
  pinMode(WEST_GREEN_LED, OUTPUT);
  pinMode(WEST_YELLOW_LED, OUTPUT);
  pinMode(WEST_RED_LED, OUTPUT);
  pinMode(BUTTON_1, INPUT_PULLUP);
  pinMode(BUTTON_2, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);
  pinMode(MATRIX_CLK, OUTPUT);
  pinMode(MATRIX_DIN, OUTPUT);
  pinMode(MATRIX_CS, OUTPUT);

  // 初始化点阵显示模块
  matrixInit();
}

void loop() {
  // 检测按键1,调整倒计时时间
  if (digitalRead(BUTTON_1) == LOW) {
    countdown++; // 倒计时时间加1秒
    delay(500); // 延时一段时间,防止按键误触
  }

  // 检测按键2,切换人行道控制、紧急状态控制
  if (digitalRead(BUTTON_2) == LOW) {
    if (emergency) {
      // 取消紧急状态
      emergency = false;
      turnOffAllLeds();
      countdown = 10;
    } else {
      // 进入紧急状态
      emergency = true;
      turnOnAllLeds();
      beep();
    }
    delay(500); // 延时一段时间,防止按键误触
  }

  // 控制交通灯
  if (!emergency) {
    // 倒计时开始,更新点阵显示
    if (countdown > 0) {
      updateMatrix(direction, countdown);
    }

    // 切换方向
    if (countdown == 0) {
      direction = 1 - direction; // 反转方向
      countdown = 10; // 重置倒计时时间
      turnOffAllLeds(); // 关闭所有灯
    }

    // 控制红、黄、绿灯的状态
    if (direction == 0) {
      if (countdown >= 7) {
        digitalWrite(EAST_GREEN_LED, HIGH);
        digitalWrite(WEST_RED_LED, HIGH);
      } else if (countdown >= 4) {
        digitalWrite(EAST_YELLOW_LED, HIGH);
        digitalWrite(WEST_RED_LED, HIGH);
      } else {
        blink(EAST_YELLOW_LED, 3);
        digitalWrite(EAST_RED_LED, HIGH);
        delay(1000);
      }
    } else {
      if (countdown >= 7) {
        digitalWrite(WEST_GREEN_LED, HIGH);
        digitalWrite(EAST_RED_LED, HIGH);
      } else if (countdown >= 4) {
        digitalWrite(WEST_YELLOW_LED, HIGH);
        digitalWrite(EAST_RED_LED, HIGH);
      } else {
        blink(WEST_YELLOW_LED, 3);
        digitalWrite(WEST_RED_LED, HIGH);
        delay(1000);
      }
    }
  } else {
    // 紧急状态下,所有灯都点亮,蜂鸣器发出警报声
    turnOnAllLeds();
    beep();
  }

  delay(1000); // 延时一秒,等待倒计时结束
}

// 控制发光二极管闪烁
void blink(int pin, int times) {
  for (int i = 0; i < times; i++) {
    digitalWrite(pin, HIGH);
    delay(500);
    digitalWrite(pin, LOW);
    delay(500);
  }
}

// 关闭所有灯
void turnOffAllLeds() {
  digitalWrite(EAST_GREEN_LED, LOW);
  digitalWrite(EAST_YELLOW_LED, LOW);
  digitalWrite(EAST_RED_LED, LOW);
  digitalWrite(WEST_GREEN_LED, LOW);
  digitalWrite(WEST_YELLOW_LED, LOW);
  digitalWrite(WEST_RED_LED, LOW);
}

// 打开所有灯
void turnOnAllLeds() {
  digitalWrite(EAST_GREEN_LED, HIGH);
  digitalWrite(EAST_YELLOW_LED, HIGH);
  digitalWrite(EAST_RED_LED, HIGH);
  digitalWrite(WEST_GREEN_LED, HIGH);
  digitalWrite(WEST_YELLOW_LED, HIGH);
  digitalWrite(WEST_RED_LED, HIGH);
}

// 蜂鸣器发出警报声
void beep() {
  for (int i = 0; i < 10; i++) {
    digitalWrite(BUZZER, HIGH);
    delay(100);
    digitalWrite(BUZZER, LOW);
    delay(100);
  }
}

// 更新点阵显示
void updateMatrix(int direction, int countdown) {
  // 显示通行方向
  matrixDisplay(direction);

  // 显示倒计时时间
  matrixDisplayNumber(countdown);
}

// 初始化点阵显示模块
void matrixInit() {
  matrixWrite(MATRIX_CS, 0x0c); // 打开显示,无游标,无闪烁
  matrixWrite(MATRIX_CS, 0x01); // 清屏
  matrixWrite(MATRIX_CS, 0x06); // 显示模式:左右滚动
  matrixWrite(MATRIX_CS, 0x80); // 设置起始地址为0
}

// 在点阵显示模块上显示通行方向
void matrixDisplay(int direction) {
  matrixWrite(MATRIX_CS, 0x80); // 设置起始地址为0
  if (direction == 0) {
    matrixWrite(MATRIX_CS, 0x7e); // E
    matrixWrite(MATRIX_CS, 0x11); // A
    matrixWrite(MATRIX_CS, 0x11); // A
    matrixWrite(MATRIX_CS, 0x11); // A
    matrixWrite(MATRIX_CS, 0x7e); // E
  } else {
    matrixWrite(MATRIX_CS, 0x3c); // N
    matrixWrite(MATRIX_CS, 0x24); // I
    matrixWrite(MATRIX_CS, 0x24); // I
    matrixWrite(MATRIX_CS, 0x24); // I
    matrixWrite(MATRIX_CS, 0x3c); // N
  }
}

// 在点阵显示模块上显示数字
void matrixDisplayNumber(int number) {
  matrixWrite(MATRIX_CS, 0x40); // 设置起始地址为0x40
  matrixWrite(MATRIX_CS, 0x00); // 数字0
  matrixWrite(MATRIX_CS, 0x7e); // 数字1
  matrixWrite(MATRIX_CS, 0x30); // 数字2
  matrixWrite(MATRIX_CS, 0x5e); // 数字3
  matrixWrite(MATRIX_CS, 0x79); // 数字4
  matrixWrite(MATRIX_CS, 0x6d); // 数字5
  matrixWrite(MATRIX_CS, 0x6f); // 数字6
  matrixWrite(MATRIX_CS, 0x38); // 数字7
  matrixWrite(MATRIX_CS, 0x7f); // 数字8
  matrixWrite(MATRIX_CS, 0x7d); // 数字9

  int n1 = number / 10;
  int n2 = number % 10;

  matrixWrite(MATRIX_CS, n1 == 0 ? 0 : n1 + 1); // 显示十位数
  matrixWrite(MATRIX_CS, n2 + 1); // 显示个位数
}

// 向点阵显示模块写入数据
void matrixWrite(int csPin, byte data) {
  digitalWrite(csPin, LOW);
  shiftOut(MATRIX_DIN, MATRIX_CLK, MSBFIRST, data);
  digitalWrite(csPin, HIGH);
}

需要注意的是,以上代码仅为示例,具体实现可能会因为硬件配置的不同而有所差异。在实际编写代码时,需要根据具体的硬件连接情况和功能需求进行适当地修改和调整。同时,需要注意代码的可读性和注释的完整性,以便后期的维护和修改。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

基于Arduino的双向交通灯系统

#include"LedControl.h"
LedControl lc=LedControl(13,11,12,1);
byte d[8]={
B00001000,
B00000100,
B00000010,
B11111111,
B11111111,
B00000010,
B00000100,
B00001000,};
byte h[8]={
B00010000,
B00100000,
B01000000,
B11111111,
B11111111,
B01000000,
B00100000,
B00010000,};
int k1=0;
int k2=0;
int keypin1=10;
int keypin2=3;
int redpin = 4;
int yellowpin = 5;
int greenpin = 6;
int redpin2 = 7;
int yellowpin2 = 8;
int greenpin2 = 9;
 
void setup()
{
  lc.shutdown(0,false);
  lc.setIntensity(0,3);
 
lc.clearDisplay(0);
  pinMode(keypin1,INPUT);
  pinMode(keypin2,INPUT);
  pinMode(redpin,OUTPUT);
  pinMode(yellowpin,OUTPUT);
  pinMode(greenpin,OUTPUT);
  pinMode(redpin2,OUTPUT);
  pinMode(yellowpin2,OUTPUT);
  pinMode(greenpin2,OUTPUT);
  }
  void loop()
  {
    k2=digitalRead(keypin2);
  if(k2==LOW)
  {
    k1=digitalRead(keypin1);
      if(k1==LOW)
      {
        lc.clearDisplay(0);
        for(int row=0;row<8;row++)
        lc.setRow(0,row,h[row]);
      digitalWrite(redpin,HIGH);
 
 digitalWrite(greenpin2,HIGH);
    delay(7000);
      digitalWrite(redpin,LOW);
      digitalWrite(yellowpin,HIGH);
    delay(500);
      digitalWrite(yellowpin,LOW);
    delay(500);
      digitalWrite(yellowpin,HIGH);
    delay(500);
     digitalWrite(yellowpin,LOW);
    delay(500);
     digitalWrite(yellowpin,HIGH);
    delay(500);
     digitalWrite(yellowpin,LOW);
    delay(500);
        lc.clearDisplay(0);
        for(int row=0;row<8;row++)
        lc.setRow(0,row,d[row]);   
      digitalWrite(greenpin2,LOW);
      digitalWrite(greenpin,HIGH);
      digitalWrite(redpin,LOW);
      digitalWrite(redpin2,HIGH);
      digitalWrite(yellowpin,LOW);
    delay(7000);
      digitalWrite(redpin2,LOW);
     digitalWrite(yellowpin2,HIGH);
    delay(500);
      digitalWrite(yellowpin2,LOW);
    delay(500);
      digitalWrite(yellowpin2,HIGH);
    delay(500);
     digitalWrite(yellowpin2,LOW);
    delay(500);
     digitalWrite(yellowpin2,HIGH);
    delay(500);
     digitalWrite(yellowpin2,LOW);
    delay(500); 
      digitalWrite(yellowpin2,LOW); 
      digitalWrite(greenpin,LOW);
      }
 else if(k1==HIGH)
       {
        lc.clearDisplay(0);
        for(int row=0;row<8;row++)
        lc.setRow(0,row,h[row]);
      digitalWrite(redpin,HIGH); digitalWrite(greenpin2,HIGH);
    delay(15000);
      digitalWrite(redpin,LOW);
      digitalWrite(yellowpin,HIGH);
    delay(500);
      digitalWrite(yellowpin,LOW);
    delay(500);
      digitalWrite(yellowpin,HIGH);
    delay(500);
     digitalWrite(yellowpin,LOW);
    delay(500);
     digitalWrite(yellowpin,HIGH);
    delay(500);
     digitalWrite(yellowpin,LOW);
    delay(500);
        lc.clearDisplay(0);
        for(int row=0;row<8;row++)
        lc.setRow(0,row,d[row]);   
      digitalWrite(greenpin2,LOW);
      digitalWrite(greenpin,HIGH);
      digitalWrite(redpin,LOW);
      digitalWrite(redpin2,HIGH);
      digitalWrite(yellowpin,LOW);
    delay(15000);
      digitalWrite(redpin2,LOW);
     digitalWrite(yellowpin2,HIGH);
    delay(500);
      digitalWrite(yellowpin2,LOW);
    delay(500);
      digitalWrite(yellowpin2,HIGH);
    delay(500);
     digitalWrite(yellowpin2,LOW);
    delay(500);
     digitalWrite(yellowpin2,HIGH);
    delay(500);
     digitalWrite(yellowpin2,LOW);
    delay(500); 
      digitalWrite(yellowpin2,LOW); 
      digitalWrite(greenpin,LOW);
     }
      }
     else if(k2==HIGH)
     
       digitalWrite(redpin,HIGH);
       digitalWrite(redpin2,HIGH);
       delay(5000);
        digitalWrite(redpin,LOW);
       digitalWrite(redpin2,LOW);
     
    
   
    }
 
 
 

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
实验要求:

设计一个基于Arduino的双向交通灯系统。系统有两组LED灯,每组LED灯分别表示不同方向的车辆通行状态。在一组LED灯亮起的时候,交通灯另一组LED灯则必须处于关闭状态。同时,要设置红绿灯反转的倒计时计时器功能。

实验具体步骤:

1.准备材料

Arduino开发板
面包板
7个 jumper wires
4个 LED灯(绿灯和红灯各两个,标注灯不一定需要)
4个 220 Ω电阻
1个蜂鸣器
1个按键开关
1个 10K Ω电阻

2.连接电路

将4个LED灯和一个蜂鸣器连接到面包板上,按照以下电路图连接。

image.png

3.编写程序

程序实现的具体功能点:

通过按键开关控制交通灯,一组亮起时另一组自动关闭。
通过倒计时计时器功能,使每组交通灯的红绿灯反转。

代码如下:

int ButtonPin = 2;         //定义按键引脚
int DL1Green = 3;      //定义一组交通灯绿灯引脚
int DL1Red = 4;        //定义一组交通灯红灯引脚
int DL2Green = 5;          //定义二组交通灯绿灯引脚
int DL2Red = 6;            //定义二组交通灯红灯引脚
int AlarmPin = 9;         //定义蜂鸣器引脚
int TimeCount = 15;       //设置默认倒计时计时器值 
long StartTime = 0;        //设置变量用于储存倒计时开始时间
int CurrentCount = 0;       //设置变量用于储存当前倒计时值 

void setup() {  
  pinMode(ButtonPin, INPUT_PULLUP);      //设置按键引脚为输入模式
  pinMode(DL1Green, OUTPUT);            //设置一组交通灯绿灯引脚为输出模式
  pinMode(DL1Red, OUTPUT);              //设置一组交通灯红灯引脚为输出模式 
  pinMode(DL2Green, OUTPUT);            //设置二组交通灯绿灯引脚为输出模式
  pinMode(DL2Red, OUTPUT);              //设置二组交通灯红灯引脚为输出模式    
  pinMode(AlarmPin, OUTPUT);            //设置蜂鸣器引脚为输出模式 
  Serial.begin(9600);                 //初始化串口通信
}

void loop() {
  digitalWrite(DL1Green, HIGH);            //一组交通灯绿灯亮
  digitalWrite(DL1Red, LOW);            //一组交通灯红灯暗
  digitalWrite(DL2Green, LOW);            //二组交通灯绿灯暗
  digitalWrite(DL2Red, HIGH);            //二组交通灯红灯亮
  if(digitalRead(ButtonPin)==LOW){     //如果按键被按下
    digitalWrite(DL1Green, LOW);            //一组交通灯绿灯暗
    digitalWrite(DL1Red, HIGH);         //一组交通灯红灯亮
    digitalWrite(DL2Green, HIGH);            //二组交通灯绿灯亮
    digitalWrite(DL2Red, LOW);            //二组交通灯红灯暗
    StartTime = millis();            //记录倒计时开始时间
    CurrentCount = TimeCount;         //将默认倒计时计时器值赋给当前倒计时值      
    while(CurrentCount > -1){     //倒计时循环
      Serial.println(CurrentCount);         //将当前倒计时值输出到串口监视器中
      digitalWrite(AlarmPin, HIGH);         //蜂鸣器响
      delay(300);             //延时以控制蜂鸣器响声长度
      digitalWrite(AlarmPin, LOW);         //蜂鸣器停止响
      delay(700);             //延时以控制蜂鸣器响声长度
      CurrentCount--;           //将当前倒计时值减1
    }
  }
  delay(100);               //延时以减少系统占用
}

4.运行程序

将Arduino开发板连接到计算机上,上传程序并运行。

5.实验效果

在程序运行时,按下按键开关,交通灯会按照一定时间间隔亮起、熄灭,同时每当倒计时计时器响时,蜂鸣器会发出短促的鸣叫声。
如果我的回答解决了您的问题,请采纳!

使用了Adafruit_GFX库,需要先安装相关的库才可以编译


#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

const int buttonPin = 2;
const int emergencyPin = 3;
const int buzzerPin = 4;

const int greenNorthSouthPin = 5;
const int yellowNorthSouthPin = 6;
const int redNorthSouthPin = 7;

const int greenEastWestPin = 8;
const int yellowEastWestPin = 9;
const int redEastWestPin = 10;

const int pedestrianGreenPin = 11;
const int pedestrianRedPin = 12;

unsigned long lastStateChangeTime = 0;
unsigned long countdownStartTime = 0;
unsigned long countdownDuration = 10000; // 默认通行时间为10秒
bool emergencyMode = false;

void setup() {
  matrix.begin(0x70);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(emergencyPin, INPUT_PULLUP);
  pinMode(buzzerPin, OUTPUT);
  pinMode(greenNorthSouthPin, OUTPUT);
  pinMode(yellowNorthSouthPin, OUTPUT);
  pinMode(redNorthSouthPin, OUTPUT);
  pinMode(greenEastWestPin, OUTPUT);
  pinMode(yellowEastWestPin, OUTPUT);
  pinMode(redEastWestPin, OUTPUT);
  pinMode(pedestrianGreenPin, OUTPUT);
  pinMode(pedestrianRedPin, OUTPUT);
  
  // 初始状态设置
  setLights(NORTH_SOUTH, RED);
  setLights(EAST_WEST, GREEN);
  setPedestrianLights(RED);
}

enum Direction {
  NORTH_SOUTH,
  EAST_WEST
};

enum LightState {
  RED,
  YELLOW,
  GREEN
};

void loop() {
  // 检查是否按下调整通行时间的按钮
  if (digitalRead(buttonPin) == LOW) {
    adjustCountdownDuration();
  }

  // 检查是否按下紧急状态按钮
  if (digitalRead(emergencyPin) == LOW) {
    setEmergencyMode(true);
  } else {
    setEmergencyMode(false);
  }

  // 更新交通灯状态
  updateLights();

  // 更新倒计时显示
  updateCountdownDisplay();
}

void setLights(Direction direction, LightState state) {
  if (direction == NORTH_SOUTH) {
    digitalWrite(greenNorthSouthPin, LOW);
    digitalWrite(yellowNorthSouthPin, LOW);
    digitalWrite(redNorthSouthPin, LOW);

    switch (state) {
      case RED:
        digitalWrite(redNorthSouthPin, HIGH);
        break;
      case YELLOW:
        digitalWrite(yellowNorthSouthPin, HIGH);
        break;
      case GREEN:
        digitalWrite(greenNorthSouthPin, HIGH);
        break;
    }
  } else if (direction == EAST_WEST) {
    digitalWrite(greenEastWestPin, LOW);
    digitalWrite(yellowEastWestPin, LOW);
    digitalWrite(redEastWestPin, LOW);

    switch (state) {
      case RED:
        digitalWrite(redEastWestPin, HIGH);
        break;
      case YELLOW:
        digitalWrite(yellowEastWestPin, HIGH);
       
        break;
      case GREEN:
        digitalWrite(greenEastWestPin, HIGH);
        break;
    }
  }
}

void setPedestrianLights(LightState state) {
  digitalWrite(pedestrianGreenPin, LOW);
  digitalWrite(pedestrianRedPin, LOW);

  switch (state) {
    case RED:
      digitalWrite(pedestrianRedPin, HIGH);
      break;
    case GREEN:
      digitalWrite(pedestrianGreenPin, HIGH);
      break;
  }
}

void setEmergencyMode(bool state) {
  emergencyMode = state;

  if (emergencyMode) {
    setLights(NORTH_SOUTH, RED);
    setLights(EAST_WEST, RED);
    setPedestrianLights(RED);
    activateBuzzer();
  } else {
    deactivateBuzzer();
  }
}

void updateLights() {
  unsigned long currentTime = millis();

  if (emergencyMode) {
    return;
  }

  // 每隔 10 秒钟切换一个方向
  if (currentTime - lastStateChangeTime >= countdownDuration) {
    if (getLightsState(NORTH_SOUTH) == GREEN) {
      setLights(NORTH_SOUTH, YELLOW);
      setPedestrianLights(GREEN);
      lastStateChangeTime = currentTime;
      countdownStartTime = currentTime;
    } else if (getLightsState(NORTH_SOUTH) == YELLOW) {
      setLights(NORTH_SOUTH, RED);
      setPedestrianLights(GREEN);
      lastStateChangeTime = currentTime;
    } else if (getLightsState(NORTH_SOUTH) == RED) {
      setLights(EAST_WEST, GREEN);
      setPedestrianLights(RED);
      lastStateChangeTime = currentTime;
      countdownStartTime = currentTime;
    }
  }

  // 绿灯亮之前黄灯开始闪烁三次结束
  if (getLightsState(NORTH_SOUTH) == YELLOW) {
    unsigned long elapsedTime = currentTime - lastStateChangeTime;
    int blinkCount = elapsedTime / 500;

    if (blinkCount < 3) {
      if (blinkCount % 2 == 0) {
        setLights(NORTH_SOUTH, YELLOW);
      } else {
        setLights(NORTH_SOUTH, RED);
      }
    } else {
      setLights(NORTH_SOUTH, RED);
    }
  }
}

LightState getLightsState(Direction direction) {
  if (direction == NORTH_SOUTH) {
    if (digitalRead(greenNorthSouthPin) == HIGH) {
      return GREEN;
    } else if (digitalRead(yellowNorthSouthPin) == HIGH) {
      return YELLOW;
    } else {
      return RED;
    }
  } else if (direction == EAST_WEST) {
    if (digitalRead(greenEastWestPin) == HIGH) {
      return GREEN;
    } else if (digitalRead(yellowEastWestPin) == HIGH) {
      return YELLOW;
    } else {
      return RED;
    }
  }

  return RED;
}

void updateCountdownDisplay() {
  unsigned long currentTime = millis();

  if (emergencyMode) {
    matrix.clear();
    matrix.writeDisplay();
    return;
  }

  // 计算倒计时时间
  unsigned long elapsedTime = currentTime - countdownStartTime;
  unsigned long remainingTime = countdownDuration - elapsedTime;

  // 显示当前正在通行的方向
  if (getLightsState(NORTH_SOUTH) == GREEN) {
    matrix.clear();
    matrix.drawChar(0, 0, 'N', LED_ON);
    matrix.drawChar(7, 0,
'E', LED_ON);
  } else if (getLightsState(EAST_WEST) == GREEN) {
    matrix.clear();
    matrix.drawChar(0, 0, 'E', LED_ON);
    matrix.drawChar(7, 0, 'W', LED_ON);
  }
  
  // 显示倒计时时间
  matrix.setCursor(3, 3);
  matrix.print(remainingTime / 1000);

  // 更新LED点阵显示
  matrix.writeDisplay();
}

void activateBuzzer() {
  digitalWrite(buzzerPin, HIGH);
}

void deactivateBuzzer() {
  digitalWrite(buzzerPin, LOW);
}

void adjustCountdownDuration() {
  // 根据实际需求,实现按键调整通行时间的逻辑
  // 可以使用 millis() 函数和按钮状态来实现按键检测和倒计时调整逻辑
  // 在此处添加代码
}