使用proteus仿真51单片机来实现十字路口红绿灯

一.实验内容

1.需要仿真的元件:51单片机,一个动态显示的双数码管,六个LED灯。

2.实验要求:做一个十字路口红绿灯,每一向各一个,红绿灯要求能够按照通行的要求来亮灯。南北向红绿灯,红灯亮60秒,东西向的红绿灯亮,红灯亮30秒。

3.要求使用定时器中断来完成。

实验的内容跟我发的上一节是一样的,只不过这里用的不是真的51单片机和其他元器件了,而是仿真出来的。

二.步骤分析

1.首先我们得会初步使用preteus这个软件来实现我们电路的连接

2.了解动态数码管显示的原理

3.我们需要编写程序,让动态数码管显示倒计时,让led正确的亮灭

三.电路的仿真部分

我所绘制的电路图如下:

        在这个电路图中,我们能够知道,我所设计的led都是共阴接法的,而且我所用到这个数码管也是共阴接法的(数码管可能看不出来是共阴的不过你知道就好了),而共阴接法和共阳接法让led和数码管显示是相反的。也就是说,共阴接法,你的引脚给1,led才会亮;而共阳接法,你的引脚给0,led会亮。所以你所写的程序是根据电路图来写的,如果电路图的接法不同,你的程序也得与之对应的发生改变。

        我是把P2.0到P2.5的六给引脚分别给了六个红绿灯,分别代表是,南北路的绿红黄灯(上面的一组),和东西路的绿红黄灯(下面的一组)。这个灯的颜色是可以在它的元件库里挑的,可能当时嫌弃太麻烦就用了一个颜色的灯。

        我把这个数码管的八个用来控制显示的引脚分别用p1.0和p1.7来控制,p1.7引脚控制的是数码管那个小数点的显示,因为用不到,所以我直接全部给的0。至于数码管显示的原理其实很简单,我就不过多阐述了,不知道可以去B站搜个视频看看。

        至于数码管的片选的两个位,我给的是P0.0和P0.1两个引脚来控制,因为这个是两个数码管连在一起的,所以需要片选,什么意思呢,也就是说我们只能选择这两个数码管的其中一个亮,如果让这两个位同时给1,让他俩一起量,那么两个数码管就只能显示一样的数了,那么我们怎么实现让两个数码管一起亮,还能显示不同的数字呢。这就要用到数码管的动态显示了。

四.什么是数码管的动态显示 ,它是如何实现的呢?

        我们都知道人眼识别是有一定范围的,如果我让两个数每一毫秒亮一次,并且让两个灯交替着亮,你看到的现象只会是两个灯一直在亮,而不会看到两个灯交替去亮。而动态数码管显示用的就是这个原理。

        而用程序如何实现,如果我在程序里写让数码管一显示1,然后不加任何延时,接着写让数码管二显示2就可以实现吗?

        其实不行,你还得加一个让数码管清除的语句,也就是说,让数码管一亮,然后让数码管一不亮,然后在让数码管二亮,让数码管二不亮,这样四个语句放在一起才能正常的显示。为什么非得加一个让它不亮的程序呢,在这里干说可能有些同学不理解,我建议你可以试试不加的,再试试加的,对比一下,你就明白了。

五.程序实现部分(切记,如果电路以及使用的电器件不一致,程序照搬照抄肯定是错的)

#include <REG52.H>

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;
typedef unsigned long u32;

//对南北东西两个方向的红绿灯的定义
sbit led1=P2^0;//南北路绿灯
sbit led2=P2^1;//南北路红灯
sbit led3=P2^2;//南北路黄灯

sbit led4=P2^3;//东西路绿灯
sbit led5=P2^4;//东西路红灯
sbit led6=P2^5;//东西路黄灯


void time0_init(void)//定时器0初始化
{
	TMOD|=0X01;//选择为定时器0模式,工作方式1
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;	
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器		
}

void shuma(int a,int b)//两个静态数码管的显示函数,其中a控制的是数码管片选,b控制显示什么数字
{

	if(a==2){P0=0x02;}
	if(a==1){P0=0x01;}
	


	
	switch(b)//表示个位
	{
		case 0: P1=0x3f;break;//个位显示一个0
		case 1: P1=0x06;break;
		case 2: P1=0x5b;break;
		case 3: P1=0x4f;break;
		case 4: P1=0x66;break;
		case 5: P1=0x6d;break;
		case 6: P1=0x7d;break;
		case 7: P1=0x07;break;
		case 8: P1=0x7f;break;
		case 9: P1=0x6f;break;
		case 10: P1=0x00;break;
		default: break;
	}
	
}

int starttime=90,dtime=0;//定义两个用来计时的变量
int c,d;//定义两个变量分别用来储存十位数,和个位数
int sign;//定义一个标志位

void main()
{	
	time0_init();
	led1=0;
	led2=0;
	led3=0;
	led4=0;
	led5=0;
	led6=0;

	while(1)
	{
		
		if(starttime==0)
		{
			sign=0;
			starttime=90;//重置时间周期
		}
		
			//这些标志位的处理,主要是为了倒计时的正常显示
		if(starttime==90) {sign=1;}
		if(sign==1){dtime=starttime-30;}
		if(dtime==0)  {sign=2;}
		if(sign==2) {dtime=starttime;}
		
		if(starttime==90)//开始让南北的红灯亮,东西的绿灯亮
		{
			led2=1;//南北的红绿灯亮灭控制
			led1=0;
			led3=0;
			
			
			led5=0;//东西的红绿黄灯亮灭控制
			led4=1;	
            led6=0;			
		}
		
		if(starttime==30)//让南北的绿灯亮,东西的红灯亮
		{
			led2=0;
			led1=1;
            led3=0;
				
			led5=1;
			led4=0;
			led6=0;	
		}
		
		if(starttime==33)//控制东北黄灯的亮,绿灯灭
		{
			led6=1;	
			led4=0;
            led3=1;	
			led2=0;
		}
		
		if(starttime==3)//控制南北黄灯的灭,绿灯灭
		{
			led3=1;	
			led1=0;
            led6=1;	
			led5=0;
		}
		
		
		c=dtime%10;//个位
		d=dtime/10;//十位
        //在数码管显示红绿灯倒计时
		shuma(2,d);	//让数码管2,显示十位数	
		shuma(2,10);//清除数码管二
		shuma(1,c);	//让数码管1,显示个位数
		shuma(1,10);//清除数码管一
	}	//while
}//main


void time0() interrupt 1 //定时器0中断函数
{
	static u16 i;//定义静态变量i
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;
	i++;
	if(i==1000)//每过一秒钟让starttime减一
	{
		
		i=0;
		starttime--;	
	}						
}

        上面的代码是完整的代码,上面的注释我写的十分详细 ,在这里就不过多阐述了,至于下一篇我打算出一篇使用51单片机控制步进电机的文章,希望大家多多支持,如果哪里有问题可以在评论区留言或者直接私信我即可。    

  • 14
    点赞
  • 151
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翱翔的小鸭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值