能实现基本功能的交通灯,用到的元件包括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;
}
}
}
🤔🤔