奶爸业余单片机学习之:用数码管及LED实现交通灯(初版)

时间:2024-03-18 08:16:32

/*

* 人行道交通灯程序:LED2(红灯)、LED3(黄灯)、LED4(绿灯)
* 红灯30秒,绿灯3秒,绿灯15秒,倒计时
灯亮时间显示在数码管上
* 晶振11.0592MHz,LED、数码管由三八译码器控制,T0中断

*程序思路:由于三八译码器每次只能输出一个低电平,因此必须用动态扫描方式点亮数码管及LED,中断间隔1ms

*亮灯时间倒数,红灯60秒,绿灯20秒,黄灯3秒,顺序:红 - 绿 -黄 -红循环,因此每经历1000次中断,实现数字递减。

*/

#include<reg52.h>
unsigned char K;//1s定时标志
unsigned char SMG_BUFFER[2]={0xff,0xff};//数码管显示缓冲

unsigned char RED,YELLOW,GREEN;
sbit LED2_RED = P0^0; //红灯接口
sbit LED3_YELLOW = P0^1;//黄灯接口
sbit LED4_GREEN = P0^2; //绿灯接口

//三八译码器控制数码管,个位:01000,十位:01001
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED1 = P1^4;

//数码管0~9
unsigned char code SMG[10]=
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

//数码管显示
void SMG_DISPLAY()
{
  unsigned char SHIJIAN;//灯亮时间
  static unsigned char color = 0;//颜色标志:0:红灯,1:黄灯,2:绿灯 ,默认从红灯开始
  if(SHIJIAN <= 1)//倒数到1秒时,开始变化,
  {
    switch(color)
    {
    case 0:color = 2;SHIJIAN = 60;RED = 1;break;//红灯60秒,结束后红转绿,红灯标志位置1
    case 1:color = 0;SHIJIAN = 3;YELLOW = 1;break;//黄灯3秒,结束后黄转红,黄灯标志位置1
    case 2:color = 1;SHIJIAN = 20;GREEN = 1;break;//;绿灯20秒,结束后绿转黄,绿灯标志位置1
    default:break;
    }
  }
  else SHIJIAN--; //时间递减
  if(SHIJIAN == 1)//直到1,时间发生变化
  {
    RED = 0;YELLOW = 0; GREEN = 0;//各标志位置0
  }
  SMG_BUFFER[0] = SMG[SHIJIAN % 10];//数码管显示,个位
  SMG_BUFFER[1] = SMG[SHIJIAN / 10 % 10]; //十位
}

//定时器配置
void config_interruptime0()
{
  TMOD = TMOD & 0XF0;
  TMOD = TMOD | 0X01;
  TH0 = 0XFC;
  TL0 = 0X66;
  EA = 1;
  ET0 = 1;
  TR0 = 1;
}

void init()
{
  ADDR3 = 1;
  ENLED1 = 0;
}
int main()
{
  init();
  config_interruptime0();
  while(1)
  {
    if(K == 1)//检查1秒定时时间是否达到
    {
      K = 0;//K重置
      SMG_DISPLAY();//刷新显示
    }
  }
  return 0;
}

void interruptime0() interrupt 1
{
  static unsigned int cnt = 0;
  static unsigned int i = 0;
  TH0 = 0XFC; //1ms初值
  TL0 = 0X66;
  cnt++;

  switch(i)
  {
    case 0:P0 = 0XFF; ADDR0 = 0; ADDR1 = 0; ADDR2 = 0; i++; P0 = SMG_BUFFER[0];break;//数码管个位显示
    case 1:P0 = 0XFF; ADDR0 = 1; ADDR1 = 0; ADDR2 = 0; i++; P0 = SMG_BUFFER[1];break;//数码管十位显示
    case 2:P0 = 0XFF; ADDR0 = 0; ADDR1 = 1; ADDR2 = 1; i=0; //LED显示
    if(RED == 1)
    {
      LED2_RED = 0;
    }
    if(YELLOW == 1)
    {
      LED3_YELLOW = 0;
    }
    if(GREEN == 1)
    {
      LED4_GREEN = 0;
    }
    break;
  }
  if(cnt == 1000)
  {
    K = 1;//1秒时间达到时,K = 1
    cnt = 0;
  }
}