+无黄灯+紧急
仿真:proteus 7.8
程序编译器:keil 4/keil 5
编程语言:C语言
设计编号:J010
十字路口交通灯由红、绿两色LED显示器组成,LED显示器显示切换倒计时,以秒为单位,每秒更新一次;为确保安全,绿LED计数到0转红,经5秒延时(显示红色0)后,另一道开始绿色倒计时。
(1) 主千道(A道)先通行且通行时间为10s(加5秒红灯延时,共20秒);
(2) 支道(B道)通行时间为7s(加5秒红灯延时,共12秒);
(3) 主道与支道的车辆交错通;
(4) 若遇紧急情况,按开关K1时,主道与支道都为红灯20s;
(5) 根据实时交通堵塞情况人为控制时,按K2时,主道延时30s通行,按K3时,支道延时30s通行;
(6) 具体秒数可在程序改数字实现。
1.A方向绿灯通行,B方向红灯
2.A方向黄灯通行,B方向红灯
3.B方向绿灯通行,A方向红灯
4.B方向黄灯通行,A方向红灯
实时交通堵塞情况人为控制时,按K2时,主道延时30s通行,按K3时,支道延时30s通行;
遇紧急情况,按开关K1时,主道与支道都为红灯20s;
主函数
void main()
{
EA=1; //开总中断
TMOD|= 0X01;
TH0=0X4C;
TL0=0X00;//11.0592M晶振 50ms定时初值
ET0=1; //允许定时器1中断
TR0=1;//启动定时器0
while(1)
{
led_sacn(); //LED和数码管显示,时刻刷新
KeyDriver();
if(flag1s)//正常倒计时模式一秒执行一次
{
flag1s=0;
main_road_time--; //红绿灯倒计时时间减
secondary_road_time--;
}
if(all_one_sec_flag){//紧急模式倒计时
all_one_sec_flag=0;
if(run_mode==1){
sec_20s_cnt--;
if(sec_20s_cnt<=1){//倒计时时间到
run_mode=0;
state=0;
main_road_time=0;
}
}
}
}
}
主要的核心点是倒计时,和LED灯亮灭控制
记住这个点就可以设计软件了。首先要有时间基础,倒计时从哪来呢?
一般两个来源:
1,延时
delay(1000ms);
通过死循环卡主软件的运行来达到延时效果,程序执行效率极低,不可取。
2,定时
通过定时器产生时基。软件设置50ms产生一次定时中断,在中断执行函数中做计数。
EA=1; //开总中断
TMOD|= 0X01;
TH0=0X4C;
TL0=0X00;//11.0592M晶振 50ms定时初值
ET0=1; //允许定时器1中断
TR0=1;//启动定时器0
20ms执行一次中断函数,通过one_sec_flag累加到50判断时间过去了一秒。设置一秒标志位flag1s置一。
TH0=0XBB;
TL0=0X00;
KeyScan();
if(++one_sec_flag<50){
return;//提前结束函数
}
one_sec_flag=0;
all_one_sec_flag=1;
if(run_mode==0){//不是正常运行时,不红绿灯数值不减一
flag1s=1;
}
在主函数while循环里判断标志位,如果是1,则倒计时计数值减一,即完成了倒计时的软件设计思路
if(flag1s)//正常倒计时模式一秒执行一次
{
flag1s=0;
main_road_time--;
//红绿灯倒计时时间减
secondary_road_time--;
}
正常红绿灯运行分有四个模式
1.A方向绿灯通行,B方向红灯
2.A方向黄灯通行,B方向红灯
3.B方向绿灯通行,A方向红灯
4.B方向黄灯通行,A方向红灯
5.执行第一步
if(run_mode==0) //0 正常运行
{
if(main_road_time==0 || secondary_road_time==0)//当A车道或者B车道倒数到0,切换状态。
//这一段程序只有倒计时为0才执行一次,执行完一次等下一次倒计时为0才再执行一次
{
switch(state)//改变红绿灯的状态
{
case 0:
{
state=1;//下次切换到下一个模式
main_road_time=ns_green_cnt;//A车道绿灯通行时间
secondary_road_time=ns_green_cnt+yellow_cnt;
we_red = ON;
we_green = OFF;
ns_red = OFF;
ns_green = ON;
}break;
case 1:
{
state=2;
main_road_time = yellow_cnt;
//A车道红灯延迟时间时间
we_red = ON;
we_green = OFF;
ns_red = ON;
ns_green = OFF;
}break;
case 2:
{
state=3;
main_road_time=we_green_cnt+yellow_cnt;
//B车道绿灯通行时间
secondary_road_time =we_green_cnt;
we_red = OFF;
we_green = ON;
ns_red = ON;
ns_green = OFF;
}break;
case 3:
{
state=0;
secondary_road_time=yellow_cnt;
//B车道红灯延迟时间时间
we_red = ON;
we_green = OFF;
ns_red = ON;
ns_green = OFF;
}break;
default:break;
}
}
seg_disp(main_road_time/10,0);
//显示W0控制的数码管 时刻刷新
seg_disp(main_road_time%10,1);
//显示W1控制的数码管
seg_disp(secondary_road_time/10,2);
//显示W2控制的数码管
seg_disp(secondary_road_time%10,3);
//显示W3控制的数码管
}
实际上倒计时显示就是显示main_road_time–; secondary_road_time–;设计函数通过数码管分别显示A方向的main_road_time和B方向的secondary_road_time即可
seg_disp(main_road_time/10,0);//显示W0控制的数码管 时刻刷新
seg_disp(main_road_time%10,1);//显示W1控制的数码管
seg_disp(secondary_road_time/10,2);//显示W2控制的数码管
seg_disp(secondary_road_time%10,3);//显示W3控制的数码管
uchar keystr[]={1,1,1,1},backup[]={1,1,1,1};
void KeyScan() //键盘扫描
{
static uchar keybuf[4]={0XFF,0XFF,0XFF,0XFF};
uchar i;
keybuf[0]=(keybuf[0]<<1)|KEY1;
keybuf[1]=(keybuf[1]<<1)|KEY2;
keybuf[2]=(keybuf[2]<<1)|KEY3;
for(i=0;i<3;i++)
{
if(keybuf[i]==0X00) keystr[i]=0;
else if(keybuf[i]==0XFF) keystr[i]=1;
}
}
void KeyAction(uchar key) //键盘执行
{
switch(key)
{
case 0: //KEY3按下
if(run_mode==0&&state==3){
if (secondary_road_time<70&&main_road_time<70)//小于70才能+时间,否则超过100,显示错误
{
secondary_road_time=secondary_road_time+30;
main_road_time=main_road_time+30;
}
}
break;
case 1: //KEY2按下
if(run_mode==0&&state==1){
if (secondary_road_time<70&&main_road_time<70)//小于70才能+时间,否则超过100,显示错误
{
secondary_road_time=secondary_road_time+30;
main_road_time=main_road_time+30;
}
}
break;
case 2: KEY1按下
if(run_mode!=1){
run_mode=1;
sec_20s_cnt=20;
}
break;
default:break;
}
}
void KeyDriver() //键盘驱动
{
uchar i;
for(i=0;i<3;i++)
{
if(keystr[i]!=backup[i])
{
if(keystr[i]==0)
KeyAction(i);//这里适当修改程序可以实现组合按键的效果
}
backup[i]=keystr[i];
}
}