原理圖
功能描述
??1、基本功能就是如同紅綠燈一般,不做贅述。
??2、紅燈時長和綠燈時長可通過按鍵設(shè)置,即按鍵列中的上面4個,當(dāng)這4個按鍵有一個按下后便進入時長設(shè)置功能,設(shè)置完成后按最下面兩個按鍵(緊急控制按鈕)任意一個便可退出該功能。
??3、有緊急控制功能,按下緊急控制按鈕后,便進入該功能,保持紅燈或綠燈常亮,且關(guān)閉數(shù)碼管,當(dāng)按下時長控制按鈕即最上面的4個按鈕便可退出該功能。
效果展示
代碼
#include <reg52.h>
//數(shù)碼管選擇位
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; //計數(shù),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}; //共陽數(shù)碼管段碼表,仿真中用的是共陰數(shù)碼管,所以使用時需對段碼取反
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; //南北紅綠燈標(biāo)識位 0 紅燈 1 綠燈
bit EW_R_G_flag=0; //東西紅綠燈標(biāo)識位 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() //系統(tǒng)初始化
{
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; //默認(rèn)初始時南北向燈亮紅燈,并賦紅燈時長
EW_second=green_time; //默認(rèn)初始時東西向燈亮綠燈,并賦綠燈時長
yellow_time=red_time-green_time;//黃燈時間為紅燈時間與綠燈時間差
Timer_init();
}
void NS_SMG_drive(char *buff) //南北向數(shù)碼管驅(qū)動
{
//顯示十位
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;
//關(guān)閉南北向數(shù)碼管
NS_1=1;
NS_2=1;
}
void EW_SMG_drive(char *buff) //東西向數(shù)碼管驅(qū)動
{
//顯示十位
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;
//關(guān)閉東西向數(shù)碼管
EW_1=1;
EW_2=1;
}
void data_del(char *buff,char data1,char data2) //數(shù)據(jù)處理
{
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; //計數(shù)值清零
}
}
void R_G_Y_led() //紅綠燈驅(qū)動
{
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() //設(shè)置紅綠燈亮的時長
{
if((add_red_time==0)||(add_green_time==0)||(reduce_red_time==0)||(reduce_green_time==0))//設(shè)置紅綠燈時長時任一設(shè)置按鈕都可觸發(fā)
{
TR0 = 0; //關(guān)閉定時器
P2=0x00; //清零P2寄存器
EW_led=1; //EW_led、NS_led引腳也在P2寄存器內(nèi),但是后面需要這兩個按鈕結(jié)束設(shè)置紅綠燈時長任務(wù),故而這兩個引腳要拉高
NS_led=1;
while(1)
{
data_del(temp_data,red_time,green_time);//顯示當(dāng)前紅綠燈時長
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);//南北向數(shù)碼管顯示紅燈時長
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);//東西向數(shù)碼管顯示綠燈時長
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)) //任一緊急控制按鈕按下則結(jié)束設(shè)置紅路燈時長任務(wù)
{
break;
}
}while((!NS_led)||(!EW_led)); //等待緊急控制按鈕彈起
TR0 = 1; //開啟定時器
yellow_time=red_time-green_time; //更新黃燈時間
}
}
void Urgent() //紅綠燈緊急控制
{
if((NS_led==0)||(EW_led==0)) //任一緊急控制按鈕按下觸發(fā)
{
TR0 = 0; //關(guān)閉定時器
P2=0x00;
EW_led=1;
NS_led=1;
EW_1=1; //關(guān)閉所有數(shù)碼管
EW_2=1;
NS_1=1;
NS_2=1;
while((!NS_led)||(!EW_led)); //判斷緊急控制按鈕按是否彈起
while(1)
{
if(NS_R_G_flag) //根據(jù)NS_R_G_flag狀態(tài)交替亮紅燈或者綠燈
{
NS_green=1;
NS_red=0;
}
else
{
NS_red=1;
NS_green=0;
}
if(EW_R_G_flag) //根據(jù)EW_R_G_flag狀態(tài)交替亮紅燈或者綠燈
{
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狀態(tài)取反
}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狀態(tài)取反
}while(!EW_led); //等待東西向緊急控制按鈕彈起
}
if((add_red_time==0)||(add_green_time==0)||(reduce_red_time==0)||(reduce_green_time==0))//任一紅綠燈設(shè)置時長按鈕按下結(jié)束緊急控制人物
{
TR0 = 1; //開啟定時器
break;
}
}while((!add_red_time)||(!add_green_time)||(!reduce_red_time)||(!reduce_green_time));//等待紅綠燈時間設(shè)置按鈕彈起
P2=0x00;
EW_led=1;
NS_led=1;
}
}
void main()
{
Init();
while(1)
{
Time_del(); //時間處理
data_del(display_data,NS_second,EW_second);//數(shù)據(jù)處理
NS_SMG_drive(display_data); //南北向數(shù)碼管驅(qū)動
EW_SMG_drive(display_data); //東西向數(shù)碼管驅(qū)動
R_G_Y_led(); //紅綠燈驅(qū)動
Set_time(); //紅綠燈時長設(shè)置
Urgent(); //緊急控制
}
}
void Timer0(void) interrupt 1 //定時器中斷
{
TH0 = 0x3C;
TL0 = 0xB0;
count++; //觸發(fā)中斷后計數(shù)值自加,定時器中斷每50ms觸發(fā)一次
}
工程下載
鏈接:https://pan.baidu.com/s/1P0Gj6PmNfffJdsEe5j6JGA
提取碼:0yzj文章來源:http://www.zghlxwxcb.cn/news/detail-504288.html
注
由于后續(xù)發(fā)現(xiàn)了些小問題,程序有所修改,網(wǎng)盤中的代碼由于一些原因暫時不能更新,以本篇博客為準(zhǔn)。文章來源地址http://www.zghlxwxcb.cn/news/detail-504288.html
到了這里,關(guān)于51單片機——交通燈的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!