51交通灯程序

能实现基本功能的交通灯,用到的元件包括74HC138,74HC245D。AT89C51。自己手扣一下午的代码,解释比较详细。

 

 


首先对管脚定以进行解释,从p1.0到p2.3是对东南西北四个路口的红绿灯进行控制,在红绿灯倒计时,满足条件的情况下,实现对灯亮灭的控制。
sbit nanhong=P1^0;
    sbit nanhuang=P1^1;
    sbit nanlv=P1^2;
    sbit beihong=P1^3;
    sbit beihuang=P1^4;
    sbit beilv=P1^5;
    sbit donghong=P1^6;
    sbit donghuang=P1^7;
    sbit donglv=P2^0;
    sbit xihong=P2^1;
    sbit xihuang=P2^2;
    sbit xilv=P2^3;
    
    从2.4到2.4为38译码器的控制线,三根线可以区分出8种不同的状态,从而实现实现对于数码管的片选信号的控制,选择哪些进行亮灭
    sbit LSA=P2^4;//38译码器
    sbit LSB=P2^5;//38译码器
    sbit LSC=P2^6;//38译码器
    sbit flag=P2^7;//设置东西倒计时时间   K1键
    sbit flag1=P3^0;//设置南北倒计时时间   K2键
    sbit flag2=P3^4;//k5键。退出倒计时设置
    u16 mm;   //设置倒计时间,按k3键加按K4键减
mm通过外部中断对其进行数值上的加减,通过按按键3控制外部中断1对mm实现数值上的增加,同理通过按键4通过外部中断2控制mm数值上的减少,再由aaa,和bbb分别寄存东西和南北方向上倒计时的控制从实现红绿灯的亮灭。
    u16 dongxi;  //东西倒计时信号  这个变量为设置的东西倒计时
    u16 nanbei;  //南北倒计时信号
    u16 xxx;  //红绿灯转换标志位  由xxx来判断东西方向上的开关信号,再由yyy一起来控制通行方向
    u16 yyy;   //红绿灯转换标志位  通yyy是一个作用
    u16 aaa;  //东西方向倒计时时间设置标志位 ,暂存倒计时
    u16 bbb;  //南北方向倒计时时间设置标志位,暂存倒计时


void delay(u16 i)
    {
    while(i--);
    }延时函数用于数码管的显示,数码管的显示并不是同时显示,而是依次显示只是两个管脚间的显示时间间隔很小,从而造成视觉上的差异,这是由延时函数来进行控制。


void DigDisplay(u16 i,u16 m){

    switch(i) //位选,选择点亮的数码管,
    {
    case(0):
    LSA=0;LSB=0;LSC=0; break;//显示第 0 位
    case(1):
    LSA=1;LSB=0;LSC=0; break;//显示第 1 位
    case(2):
    LSA=0;LSB=1;LSC=0; break;//显示第 2 位
    case(3):
    LSA=1;LSB=1;LSC=0; break;//显示第 3 位
    case(4):
    LSA=0;LSB=0;LSC=1; break;//显示第 4 位
    case(5):
    LSA=1;LSB=0;LSC=1; break;//显示第 5 位
    case(6):
    LSA=0;LSB=1;LSC=1; break;//显示第 6 位
    case(7):
    LSA=1;LSB=1;LSC=1; break;//显示第 7 位
    }
    P0=smgduan[m];//发送段码
    delay(100000);//间隔一段时间扫描
    
    }
此函数为数码管显示函数,对于一个数码管进行控制,有两个变量分别是片选信号和段选信号,片选信号由3根线进行控制,但需要74HC138进行驱动,这个函数可以控制相应数码管显示相应数字。

void EIRQ0(){
    EA=0;
    IT0=1;
    EX0=1;
    EA=1;
}
void EIRQ1(){
    EA=0;
    IT1=1;
    EX1=1;
    EA=1;
}
两个外部中断初始化,先关掉中断总开关,在选择触发方式,再打开中断标志位,再打开中断总开关。
void QH() interrupt 0 //外部中断 0 的中断函数
{
mm++;
}
void QH1() interrupt 2  //外部中断 0 的中断函数
{
mm--;
}外部中断服务程序,在进行初始化后,然后进入中断函数内,对mm进行控制。

void InitTimer0(){
    EA=0;
    TMOD=0x01;
    TL0=0xb0;
    TH0=0x3c;
    ET0=1;
    EA=1;
    TR0=1;
}同样先关掉中断总开关,再设置为定时器模式再对计数初值进行赋值,保证每一次浸润中断函数是1ms最后打开中断开关,和中断总开关,最后打开定时器。


void Timer0() interrupt 1
{
    
static u16 i;
TR0=0;
TH0=0XFC; //给定时器赋初值,定时 1ms
TL0=0X18;
ET0=1;//打开定时器 0 中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
i++;
if(i==100)
{ if(dongxi>0)dongxi--;
    
    if(dongxi==0)
    { 
        yyy=~yyy;
    }
    if(nanbei>0)nanbei--;
    if(nanbei==0)
    {
        xxx=~xxx;
        
    }
    if(dongxi==0&&nanbei==0)
    {
    dongxi=aaa;
    nanbei=bbb;
    }
    i=0;
}

}在定时器中断函数内,首先进行1s的延时,通过定以一个i,当i到100时就为1s之后再对dongxi   nanbei进行减小倒数,如果当其两个都减小到0时对通行标志位xxx和yyy进行取反,从而改变通行方向,实现交通疏导。最后再将倒数值重新赋值给dongxi和nanbei

        while(1)
        { 
            if(flag==0)
            {
              delay(1000);
                if(flag==0)//东西方向倒计时设置,按住k1然后按K3,K4加减东西方向倒计时
                {  aaa=mm;
                    dongxi=aaa;
                }
            }
        
            if(flag1==0)//南北方向倒计时设置,按住k2然后按K3,K4加减东西方向倒计时
            {
                delay(1000);
                if(flag==0)
                { bbb=mm;
                    nanbei=bbb;
                }
            }
        if(flag2==0)
        { 
            delay(1000);
                if(flag2==0)
                { 
                    break;
                }
            
        }
            
            DigDisplay(0,dongxi/10);//东倒计时
            DigDisplay(1,dongxi%10);//东倒计时
            DigDisplay(2,dongxi/10);//西倒计时
            DigDisplay(3,dongxi%10);//西倒计时
            DigDisplay(4,nanbei/10);//南倒计时
            DigDisplay(5,nanbei%10);//南倒计时
            DigDisplay(6,nanbei/10);//北倒计时
            DigDisplay(7,nanbei%10);//北倒计时
        }
在main函数的前一部分,实现的是对于倒计时的设定,和按键控制,按键扫描的常见步骤,先对按键进行消抖,消抖后再对其进行控制控制逻辑是,按下k1键后,再按k3,k4设置dongxi倒计时的设定,同理按下k2键后,再按k3,k4设置南北倒计时的设定,当设置好以后,按下按键5则退出循环从而进行下一步交通灯的控制,和倒计时。

while(1)
        { 
            DigDisplay(0,dongxi/10);//东倒计时
            DigDisplay(1,dongxi%10);//东倒计时
            DigDisplay(2,dongxi/10);//西倒计时
            DigDisplay(3,dongxi%10);//西倒计时
            DigDisplay(4,nanbei/10);//南倒计时
            DigDisplay(5,nanbei%10);//南倒计时
            DigDisplay(6,nanbei/10);//北倒计时
            DigDisplay(7,nanbei%10);//北倒计时
            if(xxx==0&&yyy==1)//南北通行
            {   nanhong=0;
                  nanhuang=0;
                  nanlv=1;
                  beihong=0;
                  beihuang=0;
                  beilv=1;
                  donghong=1;
                donghuang=0;
                donglv=0;
                xihong=1;
                xihuang=0;
                xilv=0;
                
            }
            if(xxx==1&&yyy==0)//东西通行
            {
            
               nanhong=1;
                  nanhuang=0;
                  nanlv=0;
                  beihong=1;
                  beihuang=0;
                  beilv=0;
                  donghong=0;
                donghuang=0;
                donglv=1;
                xihong=0;
                xihuang=0;
                xilv=1;
            
            }
最后用while循环一直显示倒计时的情况,同时由在中断服务函数内的xxx和yyy通行标志位控制这各个路口灯的亮灭,从而实现了数码管显示和交通信号灯的功能。

 

下面附上源码,可直接运行。

 

 

#include<reg52.h>
    typedef unsigned int u16; //对数据类型进行声明定义
    typedef unsigned char u8;
    sbit nanhong=P1^0;
    sbit nanhuang=P1^1;
    sbit nanlv=P1^2;
    sbit beihong=P1^3;
    sbit beihuang=P1^4;
    sbit beilv=P1^5;
    sbit donghong=P1^6;
    sbit donghuang=P1^7;
    sbit donglv=P2^0;
    sbit xihong=P2^1;
    sbit xihuang=P2^2;
    sbit xilv=P2^3;
    
    //38译码器位选信号。
    sbit LSA=P2^4;//38译码器
    sbit LSB=P2^5;//38译码器
    sbit LSC=P2^6;//38译码器
    sbit flag=P2^7;//设置东西倒计时时间   K1键
    sbit flag1=P3^0;//设置南北倒计时时间   K2键
    sbit flag2=P3^4;//k5键。退出倒计时设置
    u16 mm;   //设置倒计时间,按k3键加按K4键减
    u16 dongxi;  //东西倒计时信号
    u16 nanbei;  //南北倒计时信号
    u16 xxx;  //红绿灯转换标志位
    u16 yyy;   //红绿灯转换标志位
    u16 aaa;  //东西方向倒计时时间设置标志位 ,暂存倒计时
    u16 bbb;  //南北方向倒计时时间设置标志位,暂存倒计时
    u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
    0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
    // 显 示0~F 的值
    /****************************************************************
    ***************
    * 函 数 名 : delay
    * 函数功能 : 延时函数,i=1 时,大约延时 10us
    *****************************************************************
    **************/
    void delay(u16 i)
    {
    while(i--);
    }
    /****************************************************************
    ***************
    * 函 数 名 : DigDisplay
    * 函数功能 : 数码管动态扫描函数,循环扫描 8 个数码管显示
    *****************************************************************
    **************/
    void DigDisplay(u16 i,u16 m){

    switch(i) //位选,选择点亮的数码管,
    {
    case(0):
    LSA=0;LSB=0;LSC=0; break;//显示第 0 位
    case(1):
    LSA=1;LSB=0;LSC=0; break;//显示第 1 位
    case(2):
    LSA=0;LSB=1;LSC=0; break;//显示第 2 位
    case(3):
    LSA=1;LSB=1;LSC=0; break;//显示第 3 位
    case(4):
    LSA=0;LSB=0;LSC=1; break;//显示第 4 位
    case(5):
    LSA=1;LSB=0;LSC=1; break;//显示第 5 位
    case(6):
    LSA=0;LSB=1;LSC=1; break;//显示第 6 位
    case(7):
    LSA=1;LSB=1;LSC=1; break;//显示第 7 位
    }
    P0=smgduan[m];//发送段码
    delay(100000);//间隔一段时间扫描
    
    }


//外部中断0初始化函数
void EIRQ0(){
    EA=0;
    IT0=1;
    EX0=1;
    EA=1;
}
void EIRQ1(){
    EA=0;
    IT1=1;
    EX1=1;
    EA=1;
}

void QH() interrupt 0 //外部中断 0 的中断函数
{
mm++;
}
void QH1() interrupt 2  //外部中断 0 的中断函数
{
mm--;
}

void InitTimer0(){
    EA=0;
    TMOD=0x01;
    TL0=0xb0;
    TH0=0x3c;
    ET0=1;
    EA=1;
    TR0=1;
}

//定时器0中断函数用来控制定时时间
void Timer0() interrupt 1
{
    
static u16 i;
TR0=0;
TH0=0XFC; //给定时器赋初值,定时 1ms
TL0=0X18;
ET0=1;//打开定时器 0 中断允许
EA=1;//打开总中断

i++;
if(i==100)
{ if(dongxi>0)dongxi--;
    
    if(dongxi==0)
    { 
        yyy=~yyy;
    }
    if(nanbei>0)nanbei--;
    if(nanbei==0)
    {
        xxx=~xxx;
        
    }
    if(dongxi==0&&nanbei==0)
    {
    dongxi=aaa;
    nanbei=bbb;
    }
    i=0;
}
TR0=1;//打开定时器
}


void main()
    { 
        P0=0x00;
        mm=0;
        aaa=0;
        bbb=0;
      
      EIRQ0();
        EIRQ1();
        flag=1;
        flag1=1;
        flag2=1;
        xxx=0;
        yyy=1;
        while(1)
        { 
            if(flag==0)
            {
              delay(1000);
                if(flag==0)//东西方向倒计时设置,按住k1然后按K3,K4加减东西方向倒计时
                {  aaa=mm;
                    dongxi=aaa;
                }
            }
        
            if(flag1==0)//南北方向倒计时设置,按住k2然后按K3,K4加减东西方向倒计时
            {
                delay(1000);
                if(flag==0)
                { bbb=mm;
                    nanbei=bbb;
                }
            }
        if(flag2==0)
        { 
            delay(1000);
                if(flag2==0)
                { 
                    break;
                }
            
        }
            
            DigDisplay(0,dongxi/10);//东倒计时
            DigDisplay(1,dongxi%10);//东倒计时
            DigDisplay(2,dongxi/10);//西倒计时
            DigDisplay(3,dongxi%10);//西倒计时
            DigDisplay(4,nanbei/10);//南倒计时
            DigDisplay(5,nanbei%10);//南倒计时
            DigDisplay(6,nanbei/10);//北倒计时
            DigDisplay(7,nanbei%10);//北倒计时
        }
        InitTimer0();
        while(1)
        { 
            DigDisplay(0,dongxi/10);//东倒计时
            DigDisplay(1,dongxi%10);//东倒计时
            DigDisplay(2,dongxi/10);//西倒计时
            DigDisplay(3,dongxi%10);//西倒计时
            DigDisplay(4,nanbei/10);//南倒计时
            DigDisplay(5,nanbei%10);//南倒计时
            DigDisplay(6,nanbei/10);//北倒计时
            DigDisplay(7,nanbei%10);//北倒计时
            if(xxx==0&&yyy==1)//南北通行
            {   nanhong=0;
                  nanhuang=0;
                  nanlv=1;
                  beihong=0;
                  beihuang=0;
                  beilv=1;
                  donghong=1;
                donghuang=0;
                donglv=0;
                xihong=1;
                xihuang=0;
                xilv=0;
                
            }
            if(xxx==1&&yyy==0)//东西通行
            {
            
               nanhong=1;
                  nanhuang=0;
                  nanlv=0;
                  beihong=1;
                  beihuang=0;
                  beilv=0;
                  donghong=0;
                donghuang=0;
                donglv=1;
                xihong=0;
                xihuang=0;
                xilv=1;
            
            }
            
        }
    
}

🤔🤔

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值