51单片机制作花式流水灯的三种方式总结与仿真运行

制作流水灯,一共有三种方式,分别是左右移位,延时,与定时器(计数器)方式

其中移位方式较为简便,常与简单的延时一同使用在各类工程中。除此之外,也可以直接操作寄存器改变灯的亮度。

延时方式通过改变占空比控制灯的亮度变化,也就是我们常说的pwm改变灯的亮度,但这种方式不适用于工程领域,需要进一步的优化,在我们这里只是讨论流水灯的制作方式,所以暂时不予考虑。

另外对于呼吸灯来说,也可以利用gpio的方式进行实现

定时器(计数器)方式适用于一些对时间精度要求很高的场合,其中可以使用12MHZ或11.0592MHZ晶振,12MHZ更适用于定时,11.0592MHZ则更适用于通信领域。


首先,我们用移位方式来完成花式流水灯的制作,利用proteus软件进行仿真,代码如下:

#include "reg52.h"
#include 
void delay(unsigned int n)
{
	unsigned int i=0,j=0;
	for(i=0;i>i);
			delay(500);
		}
		delay(1000);
	}
	
	
	
	for(j=0;j<2;j++)
	{
		for(i=0;i<8;i++)
		{
			P0=(0xfe<>i);
			delay(500);
		}
		delay(1000);
	}
	
	
	
	for(j=0;j<2;j++)
	{
		n=0x01;
		m=0x80;
		for(i=0;i<4;i++)
		{
			P0=~(n|m);
			delay(500);
			delay(500);
			n=n<<1;
			m=m>>1;
		}
		n=0x10;
		m=0x08;
		for(i=0;i<4;i++)
		{
			P0=~(n|m);
			delay(500);
			delay(500);
			n=n>>1;
			m=m<<1;
		}
		delay(1000);
	}
	
	
	
	for(j=0;j<2;j++)
	{
		n=0x01;
		m=0x80;
		for(i=0;i<4;i++)
		{
			P0=~(n|m);
			delay(500);
			delay(500);
			n=(n|0x01)<<1;
			m=(m|0x80)>>1;
		}
		n=0x08;
		m=0x10;
		for(i=0;i<4;i++)
		{
			P0=~(n|m);
			delay(500);
			delay(500);
			n=(n|0x08)>>1;
			m=(m|0x10)<<1;
		}
		delay(1000);
	}
	
	
	delay(3000);
	
}
void main()
{
	while(1)
	{
		led();
	}
}

视频可以在我知乎的同名文章中看到:

51单片机制作花式流水灯的三种方式总结与仿真运行 - 知乎 (zhihu.com)

我们可以看出它的效果先是从前到后,然后从后到前,之后叠加点亮,灯先是扩散向两边点亮,然后再聚集回到中间的灯。


之后是延时使用pwm方式,这种方式通过改变占空比改变灯的亮度,也就是我们所说的呼吸灯。程序如下:

#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
void delay(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i++)
		for(j=114;j>0;j--);
}
void PWM(uchar k)
{
	uchar n;
	for(n=0;n<10;n++)
	{
		P0=0xff;
		delay(k);
		P0=0x00;
		delay(10-k);
	}
}
void main()
{
	uchar t;
	while(1)
	{
		for(t=1;t<10;t++)
			PWM(t);
		for(t=9;t>0;t--)
			PWM(t);	
	}
}

这种方式,以100ms作为周期,改变灯的亮度,灯由暗变亮,又由亮变暗

不过proteus貌似仿真不了呼吸灯。。。所以这个暂时没有视频,之后快递邮到会把花式流水灯融合在其他项目里


最后是最精确的定时器方式,代码如下:

其中最大的定时时长是65.536ms,每次定时都是50ms

之所以清零取反两次,是因为每次都要保证50ms的间隔,如果只在开头取反,开头第一次与之后每次的间隔时间是不同的,这在定时计数等应用环境中是不允许出现的现象。

流水灯间隔的时间,为20*50ms=1000ms,也就是1s

#include 
#include 

#define uchar unsigned char;
#define uint unsigned int;
int k=0;
char i,j,n,m;
void main()
{
  TMOD=0x01;
  TH0=(65536-50000)/256;
  TL0=(65536-50000)%256;
  TR0=1;
  P0=0x00;
	
	while(1)
	{
		n=0x01;
		m=0x80;
			for(j=0;j<8;j++)
			{
				P0=~n;
				while(k<20)
				{
						while(TF0==0);
						TH0=(65536-50000)/256;
						TL0=(65536-50000)%256;
						TF0=0;//删除定时的语句
						k++;
				}
				k=0;
				n=n<<1;
			}
			for(j=0;j<8;j++)
			{
				while(k<20)
				{
						while(TF0==0);
						TH0=(65536-50000)/256;
						TL0=(65536-50000)%256;
						TF0=0;//删除定时的语句
						k++;
				}
				k=0;
				P0=~(0x80>>j);
		  }
  }
}

效果其实就是流水灯,不过可以发现这次的间隔时间非常一致

你可能感兴趣的:(数电与模电,物联网与硬件,51单片机,嵌入式硬件,单片机)