51单片机——交通灯
·
原理图
功能描述
1、基本功能就是如同红绿灯一般,不做赘述。
2、红灯时长和绿灯时长可通过按键设置,即按键列中的上面4个,当这4个按键有一个按下后便进入时长设置功能,设置完成后按最下面两个按键(紧急控制按钮)任意一个便可退出该功能。
3、有紧急控制功能,按下紧急控制按钮后,便进入该功能,保持红灯或绿灯常亮,且关闭数码管,当按下时长控制按钮即最上面的4个按钮便可退出该功能。
效果展示
代码
#include <reg52.h>
//数码管选择位
sbit EW_1=P1^0;
sbit EW_2=P1^1;
sbit NS_1=P1^2;
sbit NS_2=P1^3;
sbit add_red_time=P1^4; //加红灯时间按钮
sbit add_green_time=P1^5; //加绿灯时间按钮
sbit reduce_red_time=P1^6; //减红灯时间按钮
sbit reduce_green_time=P1^7; //减绿灯时间按钮
sbit NS_led=P2^6; //南北向灯紧急控制按钮
sbit EW_led=P2^7; //东西向灯紧急控制按钮
sbit EW_red=P2^0; //东西向红灯
sbit EW_green=P2^1; //东西向绿灯
sbit EW_yellow=P2^2; //东西向黄灯
sbit NS_red=P2^3; //南北向红灯
sbit NS_green=P2^4; //南北向绿灯
sbit NS_yellow=P2^5; //南北向黄灯
char count=0; //计数,count=20表示1s
char red_time=30; //红灯停留时间
char green_time=25; //绿灯停留时间
char yellow_time=0; //黄灯停留时间
char NS_second=0; //南北红绿灯秒计时
char EW_second=0; //东西红绿灯秒计时
char code smgduan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //共阳数码管段码表,仿真中用的是共阴数码管,所以使用时需对段码取反
char display_data[4]={0}; //show_data[0]显示南北计时十位,show_data[1]显示南北计时个位,show_data[2]显示东西计时十位,show_data[3]显示东西计时个位
char temp_data[4]={0};
char NS_R_G_mode=0; //南北红绿灯亮模式 0 红灯 1 绿灯 2 黄灯
char EW_R_G_mode=1; //东西红绿灯亮模式 0 红灯 1 绿灯 2 黄灯
bit NS_R_G_flag=0; //南北红绿灯标识位 0 红灯 1 绿灯
bit EW_R_G_flag=0; //东西红绿灯标识位 0 红灯 1 绿灯
void delay(unsigned int i) //简单延时
{
while(i--);
}
void Timer_init() //定时器初始化
{
//定时50ms
TMOD = 0x01; //定时器方式1
TH0 = 0x3C; //定时器赋初值
TL0 = 0xB0;
EA = 1; //开启总中断
ET0 = 1; //开启定时器中断
TR0 = 1; //开启定时器
}
void Init() //系统初始化
{
P0=0x00;
P2=0x00;
EW_1=1;
EW_2=1;
NS_1=1;
NS_2=1;
NS_led=1;
EW_led=1;
NS_second=red_time; //默认初始时南北向灯亮红灯,并赋红灯时长
EW_second=green_time; //默认初始时东西向灯亮绿灯,并赋绿灯时长
yellow_time=red_time-green_time;//黄灯时间为红灯时间与绿灯时间差
Timer_init();
}
void NS_SMG_drive(char *buff) //南北向数码管驱动
{
//显示十位
NS_1=0;
NS_2=1;
P0=~smgduan[buff[0]]; //段码取反
delay(5); //间隔一段时间扫描
P0=0x00; //消隐
//显示个位
NS_1=1;
NS_2=0;
P0=~smgduan[buff[1]];
delay(5);
P0=0x00;
//关闭南北向数码管
NS_1=1;
NS_2=1;
}
void EW_SMG_drive(char *buff) //东西向数码管驱动
{
//显示十位
EW_1=0;
EW_2=1;
P0=~smgduan[buff[2]]; //段码取反
delay(5); //间隔一段时间扫描
P0=0x00; //消隐
//显示个位
EW_1=1;
EW_2=0;
P0=~smgduan[buff[3]];
delay(5);
P0=0x00;
//关闭东西向数码管
EW_1=1;
EW_2=1;
}
void data_del(char *buff,char data1,char data2) //数据处理
{
buff[0]=data1/10; //取data1的十位
buff[1]=data1%10; //取data1的个位
buff[2]=data2/10; //取data2的十位
buff[3]=data2%10; //取data2的个位
}
void Time_del() //计时处理
{
if(count>=20) //判断是否满1s
{
NS_second--; //南北向灯计时自减
EW_second--; //东北向灯计时自减
switch(NS_R_G_mode) //南北向灯
{
case 0: //红灯
{
if(NS_second<0)
{
NS_second=green_time; //开始绿灯倒计时
NS_R_G_mode=1; //红灯亮完绿灯亮
}
}break;
case 1: //绿灯
{
if(NS_second<0)
{
NS_second=yellow_time; //开始黄灯倒计时
NS_R_G_mode=2; //绿灯亮完黄灯亮
}
}break;
case 2: //黄灯
{
if(NS_second<0)
{
NS_second=red_time; //开始红灯到计时
NS_R_G_mode=0; //黄灯亮完红灯亮
}
}break;
default:break;
}
switch(EW_R_G_mode) //东西向灯
{
case 0: //红灯
{
if(EW_second<0)
{
EW_second=green_time; //开始绿灯倒计时
EW_R_G_mode=1; //红灯亮完绿灯亮
}
}break;
case 1: //绿灯
{
if(EW_second<0)
{
EW_second=yellow_time; //开始黄灯倒计时
EW_R_G_mode=2; //绿灯亮完黄灯亮
}
}break;
case 2: //黄灯
{
if(EW_second<0)
{
EW_second=red_time; //开始红灯倒计时
EW_R_G_mode=0; //黄灯亮完红灯亮
}
}break;
default:break;
}
count=0; //计数值清零
}
}
void R_G_Y_led() //红绿灯驱动
{
switch(NS_R_G_mode) //南北向
{
case 0: //红灯
{
NS_yellow=0; //黄灯灭
NS_red=1; //红灯亮
}break;
case 1: //绿灯
{
NS_red=0; //红灯灭
NS_green=1; //绿灯亮
}break;
case 2: //黄灯
{
NS_green=0; //绿灯灭
if(count<10) //黄灯以1hz频率闪烁
NS_yellow=1;
else
NS_yellow=0;
}break;
default:break;
}
switch(EW_R_G_mode) //东西向
{
case 0: //红灯
{
EW_yellow=0; //黄灯灭
EW_red=1; //红灯亮
}break;
case 1: //绿灯
{
EW_red=0; //红灯灭
EW_green=1; //绿灯亮
}break;
case 2: //黄灯
{
EW_green=0; //绿灯灭
if(count<10) //黄灯以1hz频率闪烁
EW_yellow=1;
else
EW_yellow=0;
}break;
default:break;
}
}
void Set_time() //设置红绿灯亮的时长
{
if((add_red_time==0)||(add_green_time==0)||(reduce_red_time==0)||(reduce_green_time==0))//设置红绿灯时长时任一设置按钮都可触发
{
TR0 = 0; //关闭定时器
P2=0x00; //清零P2寄存器
EW_led=1; //EW_led、NS_led引脚也在P2寄存器内,但是后面需要这两个按钮结束设置红绿灯时长任务,故而这两个引脚要拉高
NS_led=1;
while(1)
{
data_del(temp_data,red_time,green_time);//显示当前红绿灯时长
NS_SMG_drive(temp_data);
EW_SMG_drive(temp_data);
if(add_red_time==0) //判断加红灯时间按钮是否按下
{
delay(5); //消抖
if(add_red_time==0)
{
red_time++; //红灯时间自加
if(red_time>99) //限制红灯时间最大值为99
red_time=99;
data_del(temp_data,red_time,red_time);//南北向数码管显示红灯时长
NS_SMG_drive(temp_data);
}while(!add_red_time); //等待加红灯时间按钮弹起
}
if(add_green_time==0) //判断加绿灯时间按钮是否按下
{
delay(5);
if(add_green_time==0)
{
green_time++; //绿灯时间自加
if(green_time>95) //限制绿灯时间最大值95
green_time=95;
data_del(temp_data,green_time,green_time);//东西向数码管显示绿灯时长
EW_SMG_drive(temp_data);
}while(!add_green_time); //等待加绿灯时间按钮弹起
}
if(reduce_red_time==0) //判断减红灯时间按钮是否按下
{
delay(5);
if(reduce_red_time==0)
{
red_time--; //红灯时间自减
if(red_time<10) //限制红灯时间最小值10
red_time=10;
data_del(temp_data,red_time,red_time);
NS_SMG_drive(temp_data);
}while(!reduce_red_time); //等待减红灯时间按钮弹起
}
if(reduce_green_time==0) //判断减绿灯时间按钮是否按下
{
delay(5);
if(reduce_green_time==0)
{
green_time--; //绿灯时间自减
if(green_time<5) //限制绿灯时间最小值5
green_time=5;
data_del(temp_data,green_time,green_time);
EW_SMG_drive(temp_data);
}while(!reduce_green_time); //等待减绿灯时间按钮弹起
}
if((NS_led==0)||(EW_led==0)) //任一紧急控制按钮按下则结束设置红路灯时长任务
{
break;
}
}while((!NS_led)||(!EW_led)); //等待紧急控制按钮弹起
TR0 = 1; //开启定时器
yellow_time=red_time-green_time; //更新黄灯时间
}
}
void Urgent() //红绿灯紧急控制
{
if((NS_led==0)||(EW_led==0)) //任一紧急控制按钮按下触发
{
TR0 = 0; //关闭定时器
P2=0x00;
EW_led=1;
NS_led=1;
EW_1=1; //关闭所有数码管
EW_2=1;
NS_1=1;
NS_2=1;
while((!NS_led)||(!EW_led)); //判断紧急控制按钮按是否弹起
while(1)
{
if(NS_R_G_flag) //根据NS_R_G_flag状态交替亮红灯或者绿灯
{
NS_green=1;
NS_red=0;
}
else
{
NS_red=1;
NS_green=0;
}
if(EW_R_G_flag) //根据EW_R_G_flag状态交替亮红灯或者绿灯
{
EW_green=1;
EW_red=0;
}
else
{
EW_red=1;
EW_green=0;
}
if(NS_led==0) //判断南北向紧急控制按钮是否按下
{
delay(5);
if(NS_led==0)
{
NS_R_G_flag=!NS_R_G_flag; //NS_R_G_flag状态取反
}while(!NS_led); //等待南北向紧急控制按钮弹起
}
if(EW_led==0) //判断东西向紧急控制按钮是否按下
{
delay(5);
if(EW_led==0)
{
EW_R_G_flag=!EW_R_G_flag; //EW_R_G_flag状态取反
}while(!EW_led); //等待东西向紧急控制按钮弹起
}
if((add_red_time==0)||(add_green_time==0)||(reduce_red_time==0)||(reduce_green_time==0))//任一红绿灯设置时长按钮按下结束紧急控制人物
{
TR0 = 1; //开启定时器
break;
}
}while((!add_red_time)||(!add_green_time)||(!reduce_red_time)||(!reduce_green_time));//等待红绿灯时间设置按钮弹起
P2=0x00;
EW_led=1;
NS_led=1;
}
}
void main()
{
Init();
while(1)
{
Time_del(); //时间处理
data_del(display_data,NS_second,EW_second);//数据处理
NS_SMG_drive(display_data); //南北向数码管驱动
EW_SMG_drive(display_data); //东西向数码管驱动
R_G_Y_led(); //红绿灯驱动
Set_time(); //红绿灯时长设置
Urgent(); //紧急控制
}
}
void Timer0(void) interrupt 1 //定时器中断
{
TH0 = 0x3C;
TL0 = 0xB0;
count++; //触发中断后计数值自加,定时器中断每50ms触发一次
}
工程下载
链接:https://pan.baidu.com/s/1P0Gj6PmNfffJdsEe5j6JGA
提取码:0yzj
注
由于后续发现了些小问题,程序有所修改,网盘中的代码由于一些原因暂时不能更新,以本篇博客为准。
更多推荐
已为社区贡献4条内容
所有评论(0)