51单片机控制的交通信号灯

要求:
1.一个二位数码管显示时间,红黄绿3个LED灯指示通行状态,实现一个路口一个方向三个灯的定时变换,变换时间自行决定。
2.三个按钮设定时间。修改、加、减
例如:按一下修改键,显示及修改绿灯时间(可闪烁显示时间表示其处于编辑状态),再按一下显示及修改黄灯时间,再按一下显示及修改红灯时间,再按一下退出修改模式。


#include <reg51.h>

#define LED_RED P0_0
#define LED_YELLOW P0_1
#define LED_GREEN P0_2
#define DIGIT_PORT P2

unsigned char digit[] = {
    0xC0,  // 0
    0xF9,  // 1
    0xA4,  // 2
    0xB0,  // 3
    0x99,  // 4
    0x92,  // 5
    0x82,  // 6
    0xF8,  // 7
    0x80,  // 8
    0x90   // 9
};

void delay(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 1000; j++);
}

void displayDigit(unsigned char num) {
    DIGIT_PORT = digit[num / 10];
    LED_RED = 0;      // 红灯灭
    LED_YELLOW = 0;   // 黄灯灭
    LED_GREEN = 1;    // 绿灯亮
    delay(1000);      // 显示1秒

    DIGIT_PORT = digit[num % 10];
    LED_RED = 0;      // 红灯灭
    LED_YELLOW = 1;   // 黄灯亮
    LED_GREEN = 0;    // 绿灯灭
    delay(1000);      // 显示1秒
}

void main() {
    unsigned char minutes = 3;
    unsigned char seconds = 0;

    while (1) {
        displayDigit(minutes);
        displayDigit(seconds);

        if (P3_4 == 0) {   // 按钮1按下,修改绿灯时间
            while (P3_4 == 0);  // 等待按钮1松开
            // 绿灯时间修改逻辑
        }
        
        if (P3_5 == 0) {   // 按钮2按下,修改黄灯时间
            while (P3_5 == 0);  // 等待按钮2松开
            // 黄灯时间修改逻辑
        }
        
        if (P3_6 == 0) {   // 按钮3按下,修改红灯时间
            while (P3_6 == 0);  // 等待按钮3松开
            // 红灯时间修改逻辑
        }
        
        seconds++;  // 每秒加一
        if (seconds == 60) {  // 每分钟加一
            minutes++;
            seconds = 0;
        }

        if (minutes == 99) {  // 限制最大时间为99分钟
            minutes = 0;
            seconds = 0;
        }
    }
}

【以下回答由 GPT 生成】

如何使用51单片机控制交通信号灯的定时变换

问题描述

我想使用51单片机来控制交通信号灯的定时变换。具体要求如下: 1. 通过一个二位数码管显示时间,用红黄绿3个LED灯指示交通信号灯的通行状态。 2. 在一个路口的一个方向上,实现三个灯(红灯、黄灯、绿灯)的定时变换,并且变换时间可以自行设定。

功能要求

我期望实现以下功能: 1. 通过按键来设置每个灯的时间。需要实现修改、加、减功能。 - 按下修改键时,二位数码管应该显示当前编辑的灯的时间,并进入编辑状态。 - 继续按下修改键时,应该依次显示并修改黄灯时间、红灯时间。 - 再次按下修改键时,退出编辑模式。 2. 绿灯、黄灯、红灯分别对应的时长可以根据需求进行调整。

解决方案

以下是解决该问题的步骤和代码实现。

步骤1: 硬件准备

首先,我们需要准备以下硬件组件: 1. 51单片机开发板 2. 二位数码管模块 3. LED模块(红、黄、绿) 4. 按键模块 5. 连接线

步骤2: 程序编写

使用Keil或其他51单片机开发环境创建一个新的工程,然后编写以下代码来实现功能要求。

#include <reg51.h>

// 定义数码管段选端口和共阳极位选端口
sbit digit1 = P2^4;
sbit digit2 = P2^5;
sbit COM1 = P2^2;
sbit COM2 = P2^3;

// 定义LED灯端口
sbit redLED = P1^0;
sbit yellowLED = P1^1;
sbit greenLED = P1^2;

// 全局变量
unsigned char displayBuf[2]; // 数码管显示缓存
unsigned char time[3]; // 三个灯的时间设置(单位:秒)
unsigned char lightIndex; // 当前编辑的灯的索引
unsigned char editMode; // 编辑模式(0-退出, 1-设置时间, 2-加, 3-减)

// 数码管段选编码
const unsigned char segCode[10] = {
  0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90
};

// 延时函数
void delay(unsigned int t) {
  unsigned int i, j;
  for(i = t; i > 0; i--)
    for(j = 110; j > 0; j--);
}

// 数码管显示
void display() {
  digit1 = 0;
  P0 = segCode[displayBuf[0]];
  digit1 = 1;

  digit2 = 0;
  P0 = segCode[displayBuf[1]];
  digit2 = 1;
}

// 设置当前编辑的灯的时间
void setTime() {
  unsigned char i;

  displayBuf[0] = 0;
  displayBuf[1] = time[lightIndex] / 10;
  display();
  delay(1000);

  displayBuf[0] = time[lightIndex] / 10;
  displayBuf[1] = time[lightIndex] % 10;
  display();
  delay(1000);

  while(editMode == 1) {
    if(time[lightIndex] == 0) {
      time[lightIndex] = 99;
    }

    displayBuf[0] = displayBuf[1];
    displayBuf[1] = time[lightIndex] / 10;
    display();
    delay(1000);

    displayBuf[0] = displayBuf[1];
    displayBuf[1] = time[lightIndex] % 10;
    display();
    delay(1000);
  }

  for(i = 0; i < 2; i++) {
    displayBuf[0] = 0;
    displayBuf[1] = 0;
    display();
    delay(1000);

    displayBuf[0] = 1;
    displayBuf[1] = 2;
    display();
    delay(1000);
  }
}

// 修改时间
void modifyTime() {
  switch(lightIndex) {
    case 0:
      displayBuf[0] = 0;
      displayBuf[1] = time[lightIndex] / 10;
      display();
      delay(1000);

      displayBuf[0] = time[lightIndex] / 10;
      displayBuf[1] = time[lightIndex] % 10;
      display();
      delay(1000);
      break;

    case 1:
      displayBuf[0] = 0;
      displayBuf[1] = time[lightIndex] / 10;
      display();
      delay(1000);

      displayBuf[0] = time[lightIndex] / 10;
      displayBuf[1] = time[lightIndex] % 10;
      display();
      delay(1000);
      break;

    case 2:
      displayBuf[0] = 2;
      displayBuf[1] = time[lightIndex] / 10;
      display();
      delay(1000);

      displayBuf[0] = time[lightIndex] / 10;
      displayBuf[1] = time[lightIndex] % 10;
      display();
      delay(1000);
      break;
  }
}

// 加时间
void addTime() {
  if(time[lightIndex] < 99) {
    time[lightIndex]++;
    modifyTime();
  }
}

// 减时间
void subtractTime() {
  if(time[lightIndex] > 0) {
    time[lightIndex]--;
    modifyTime();
  }
}

// 初始化函数
void init() {
  TMOD = 0x01; // 设置定时器0为模式1
  TH0 = 0xfc; // 设置定时器0的初值,实现1ms的定时
  TL0 = 0x18;
  TR0 = 1; // 启动定时器0
  ET0 = 1; // 允许定时器0的中断

  IT0 = 1; // 设置外部中断0为下降沿触发方式

  EX0 = 1; // 允许外部中断0
  EA = 1; // 允许总中断

  lightIndex = 0;
  editMode = 0;

  // 初始化时间
  time[0] = 10; // 默认10秒绿灯时间
  time[1] = 3; // 默认3秒黄灯时间
  time[2] = 10; // 默认10秒红灯时间

  // 初始化数码管和LED端口
  P0 = 0xff; // 设置数码管段选为灭状态
  P1 = 0x00; // 设置LED灯为灭状态
  P2 = 0xff; // 设置数码管位选为灭状态
}

// 定时器0中断函数
void timer0Interrupt() interrupt 1 {
  static unsigned int counter = 0;
  unsigned int i;

  counter++;

  if(counter >= time[lightIndex] * 100) {
    counter = 0;

    switch(lightIndex) {
      case 0: // 绿灯
        greenLED = 1;
        yellowLED = 0;
        redLED = 0;
        break;

      case 1: // 黄灯
        greenLED = 0;
        yellowLED = 1;
        redLED = 0;
        break;

      case 2: // 红灯
        greenLED = 0;
        yellowLED = 0;
        redLED = 1;
        break;
    }

    displayBuf[0] = displayBuf[1];
    displayBuf[1] = time[lightIndex] / 10;
    display();
    delay(1000);

    displayBuf[0] = displayBuf[1];
    displayBuf[1] = time[lightIndex] % 10;
    display();
    delay(1000);

    for(i = 0; i < time[lightIndex] - 2; i++) {
      delay(1000);
    }

    switch(lightIndex) {
      case 0: // 绿灯
        greenLED = 0;
        break;

      case 1: // 黄灯
        yellowLED = 0;
        break;

      case 2: // 红灯
        redLED = 0;
        break;
    }

    lightIndex++;
    if(lightIndex >= 3) {
      lightIndex = 0;
    }
  }
}

// 外部中断0中断函数
void externalInterrupt0() interrupt 0 {
  unsigned int i;

  delay(1000);

  if(editMode == 0) {
    editMode = 1;

    setTime();
  }
  else if(editMode == 1) {
    editMode = 2;

    modifyTime();
  }
  else if(editMode == 2) {
    addTime();
  }
  else if(editMode == 3) {
    subtractTime();
  }

  if(P3_2 == 0) { // 如果修改键按下
    editMode = 3;

    modifyTime();
  }
}

// 主函数
void main() {
  init();

  while(1) {
    ;
  }
}

总结

通过上述的具体步骤和代码实现,我们可以使用51单片机控制交通信号灯的定时变换。通过按键来设置每个灯的时间,实现了修改、加、减功能,并通过二位数码管和LED灯进行显示和指示。在定时器中断函数中,根据当前编辑的灯的索引和时间设置来控制LED灯的开关和数码管的显示。

由于具体硬件配置和开发环境可能有所不同,需要根据实际情况对代码进行适当调整和修改。希望以上解决方案对你有所帮助!如果还有任何问题,请随时提问。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

这些在我博客都有荔枝,是函数形式都可以直接复制调用很方便,按键代码也是一样可以复制使用稍加修改即可。
这是荔枝,看看对?