基于51单片机的LED跑马灯设计实现

题目:        

使用单片机驱动8个LED,2个按键并实现跑马灯功能。

        当按下按键1时,LED 从左至右依次点亮,全亮后再从右至左依次熄灭,全灭后再从左至右依次点亮,依次循环下去。

       当按下按键2 时,LED 从右至左依次点亮,全亮后再从左至右依次熄灭,全灭后再从右至左依次点亮,依次循环下去。

电路部分:

利用Proteus软件搭建的电路图如下:

部分一:AT89C51最小系统电路。

AT89C51最小系统电路其中包括时钟电路和复位电路。

时钟电路:产生像时钟一样准确运动的振荡电路。

复位电路:按键按下可以使程序重新运行。

部分二:从LED-0到LED7接入P2口的八个LED灯电路。

发光二极管:只允许电流单方向通过,并发光。

上拉电阻:降低回路电流,避免元件损坏。

部分三:按钮控制电路

按键按下,P3_2或P3_3口与GND相接,置 0。

按键未按下,P3_2或P3_3口与电阻相接,按键处断开,置 1。

上拉电阻:降低电流,保护电路。

程序部分:

设计思路:

1.先利用两个for循环和延时函数初步实现LED灯延时流水功能。

2.按键部分接入单片机的外部中断0和外部中断1,当按键按下时利用外部中断去打断for循环,从而实现流水灯方向的改变。

跑马灯亮灭思路:

右移亮:

P2=0xFE;
for(i=0;i<7;i++)
{
	DELAY;
	P2<<=1;
}

左移灭:

P2=0x80;
for(i=0;i<7;i++)
{
	DELAY;
	P2=(P2>>1)|0x80;
}

左移亮:

P2=0x7F;
for(i=0;i<7;i++)
{
		DELAY;
		P2>>=1;
}

右移灭:

P2=0x01;
for(i=0;i<7;i++)
{
	DELAY;
	P2=(P2<<1)|0x01;
}

方法一:利用外部中断0、外部中断1和Delay延时函数。

具体代码:

#include <REGX52.H>
#include <intrins.h>
typedef unsigned char u8;
typedef unsigned int  u16;
void Delay300ms();
bit key1_flag = 0;
bit key2_flag = 0;
u8 i =0;
u16 Num;

void main()
{ 
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD=0x01;//设置定时器0为工作方式1
	TH0=(65535-50000)/256;//50MS
	TL0=(65535-50000)%256;	
	ET0=1;
	TR0=1;
 	EA=1;//开总中断
  
	while(1)
	{	
		if(key1_flag)
		{			
			P2 = 0xFE;			
			for(i=0;i<7;i++)  //左移循环亮
			{					
				Delay300ms();
				P2 <<= 1;
			} 
			
			Delay300ms();
			P2 = 0x80;
			
			for(i=0;i<7;i++)//右移循环灭
			{
				Delay300ms();
				P2 = (P2 >> 1) | 0x80;
			}
			Delay300ms();		
		}
		
			if(key2_flag)
			{ 
				P2=0x7F;
				for(i=0;i<7;i++)//右移循环亮
				{
					Delay300ms();
					P2>>=1;
				}			
				Delay300ms();
				P2=0x01;			
				for(i=0;i<7;i++)//左移循环灭
				{
				 Delay300ms();
					P2=(P2<<1)|0x01;		
				}
				Delay300ms();
			}		
	}
}

void exter0() interrupt 0  //外部中断0
{
	key1_flag = 1;	
	key2_flag = 0;	
}

void exint1() interrupt 2  //外部中断1
{     
	key1_flag = 0;
	key2_flag = 1;			
}

//时钟频率为12MHz的300ms的延时函数
void Delay300ms()		//@12.000MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 3;
	j = 72;
	k = 161;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

弊端:

1.浪费CPU资源:因为采用了大量的Delay()函数会导致单片机cpu进行大量的空运算。

2.延时可能不够精准:通过指令周期进行延时会产生误差。

改进的方法二:利用外部中断0、外部中断1和定时器0。

具体代码:

#include <REGX52.H>
#include <intrins.h>
typedef unsigned char u8;
typedef unsigned int  u16;

bit key1_flag = 0;
bit key2_flag = 0;
u8 i =0;
u16 Num = 0;
sbit led = P2^0;

void main()
{ 
	TMOD = 0x01;//设置定时器0为工作方式1
	TH0  = (65535-1000)/256;//设初值1ms
	TL0  = (65535-1000)%256;	 	
	ET0  = 1;//定时器0的溢出允许位
	TR0  = 1;//定时器0的运行控制位
	
  EX0  = 1;//外部中断0的控制位
	EX1  = 1;//外部中断1控制位
	EA   = 1;//开总中断
	
	while(1)
	{			
	}
}

void exter0() interrupt 0 //外部中断0
{
	key1_flag = 1;
	key2_flag = 0;
	i = 0;
}

void exint1() interrupt 2 //外部中断1
{     	
	key1_flag = 0;
	key2_flag = 1;
	i= 0;
}

void tm0_isr() interrupt 1 using 1 //定时器中断0
{
	TH0  = (65535-1000)/256;//设初值1ms
	TL0  = (65535-1000)%256;	 	
	Num++;
		
	if(Num>199)
	{
		Num = 0;
		if(key1_flag)
		{		
			switch(i++)
			{
				case 0:P2 = 0xFE; break;
				case 1:case 2:case 3:case 4:case 5:case 6:case 7:P2 <<= 1;break;
				case 8:P2  = 0x80;break;
				case 9:case 10:case 11:case 12:case 13:case 14:P2 = (P2 >> 1) | 0x80;break;
				case 15:P2 = (P2 >> 1) | 0x80;i=0;break;
			}
		}
		else if(key2_flag)
		{
			switch(i++)
			{
				case 0:P2 = 0x7F; break;
				case 1:case 2:case 3:case 4:case 5:case 6:case 7:P2 >>= 1;break;
				case 8:P2 = 0x01;	break;
				case 9:case 10:case 11:case 12:case 13:case 14:P2 = (P2 << 1) | 0x01;	break;
				case 15:P2 = (P2 << 1) | 0x01;i=0;break;
			}
		}	
	}
}

以上就是我此次对51单片机跑马灯部分的学习,如有错误或者更好的想法,欢迎大家提出。        

物联沃分享整理
物联沃-IOTWORD物联网 » 基于51单片机的LED跑马灯设计实现

发表评论