51单片机多种方式点亮LED

本文介绍了51单片机通过四种方式控制LED灯的亮灭,包括全亮全熄、依次亮灭、循环移位以及双边向中间亮灭。详细讲解了每种方式的实现原理,如使用移位操作和循环移位,并提到了按键控制思路,包括按键响应的灵敏度问题和解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于51单片机四个按键四种方式电亮LED灯,示例中的为代码的主要部分,是实现功能的代码。delay表示延时,是自定义的函数,最终代码可直接运行。


方式1 全亮和全熄

对于八个LED控制高低电平,可以一次性使用P1=0x**
低电平0则亮,1则熄。
8个LED对应的不同的电平,就比如控制全熄,那么对于的八位二进制数1111 1111

转为16进制则为ff,那么P1=0xff即为8个LED全熄,每个LED对应各自位的二进制数,比如最两边的不亮,1000 0001,转16进制,同理输入即可
P1=~P1即为取反,1变0,0变1, 比如,1000 0001就成了0111 1110

	while(1)
	{
	    delay(500);
		P1 =0x00;
		delay(500);
		P1 = ~P1;
	}

方式2 依次电亮

我们依然可以用之前的16进制输入。不同的是,如果继续直接赋值,对应8个LED,加上每次的延时,意味着程序十几句话,更重要的是后续的打断不方便,因此采用移位的操作,A<<m,表示数据A向左移动m位,空余的位置补0,同时取一定的位数,我们单片机八位二进制,所以只会去取八位:

比如
A=0000 0001 m=2时 移位后 A=0000 0100,原来在第一位的1会到第三位,同时空缺的补0
A=0100 0001 m=2时 移位后 A=0000 0100,最前边的1在移位后超出,不会取到它

同时当移动完

	while(1)
	{	
	    led = 0xfe;
	    P1 = led;
	    for(j=1;j<8;j++)
		{ 
			delay(500);
			led=led<<1;
			P1 = led;
		}		    
		delay(1000);
		led = 0xff;
		j = 1;
		P1 = led;
		delay(500);
	} 

方式3 从上到下,再下到上一次电亮

跟第二个同理
这里的 crol 与cror就是我们上一步说的移位类似,表示循环移位,crol 左移,cror右移,区别在于超出位数的部分会自动跑到最开始的位置,比如第八位循环移位一次,那么经过循环就该到第一位,可以当做他们是圈一样的循环。
比如
A=0100 0001 m=2时 移位后 A=0000 0101

需要头文件#include<intrins.h>
也可以跟我们上一步同样的操作实现

while(1)
{	
	    P1 = 0xfe;
		for(m=1;m<8;m++)
		{	
			led = 0xfe;
			delay(500);
			led = _crol_(led,m);
			P1 = led;	    
		}
		for(n=1;n<8;n++)
		{	 
		    led = 0x7f;				
			delay(500);
			led = _cror_(led,n);				    
			P1 = led;
		}
		m = 1; n = 1;
    }

方式4 两边向中间电亮

此处将两边分开表示即可

	while(1)
	{	
	    led = 0x7e;
	    High=led&0xF0;	
	    Low=led&0x0F;
		for(i=0;i<4;i++)
	    {	
			led=(High&0xF0)|(Low&0x0F);
			P1 = led;
			delay(500); 
		    High=High>>1;	
		    Low=Low<<1;	             
		}
		i = 0;
		P1 = 0xff;
	    delay(500);
	}

补充说明及按键控制思路

对于移位也是可以跟取反一起实现的,有些需求电亮后不熄灭的,可以循环移位,让1补回去,也可以将初始亮的灯定义熄灭0,移位取反,也可以达到与方式三循环移位的效果
P1=~(0x01<<i);

关于按键控制思路
首选最大的问题在于循环的打破,我们的程序初始设置的都是死循环,那么想要打破可以判断条件,不满足则break,这里不能仅仅只动while(1)是因为程序需要更快的打破,while判断是可以打破循环,但是一次循环的过程长了也是带来诸多不变,所以对于函数内的for循环每次也加判断,这样方便更快结束程序

思路一,也是最简单粗暴的,直接判断按键,比如结束第2个的循环,
最外的while(!KEY1 || !KEY3|| !KEY4)
for里边的if(KEY1 || KEY3 || KEY4) break; else
但是这样并不灵敏,对于循环以及延时的而言,他们判断按键依然是有一定时间后才执行的,以至于会出现按下没打断,按下打断了但未执行下一个,只有按下足够长的时间才能保证顺利切换

思路二 ,对按键赋值,让按下按键1,会有一个变量A为1,直到按下其他按键,改变A的值,同时也能够保证单片机可以及时扫描到按键按下,改变A,那么在判断的时候,比如程序2,我们只需判断A是否为2,按下3时,A不为2了跳出,同时3进行,这些切换存在的延时以及不需要我们一直按下按键了,这里采用的是定时器每隔50ms(50ms真的很快了,另外时间可以自己设置,50ms真的足够)扫描一下按键。

最终代码

代码如下:

#include<reg52.h>
#include<intrins.h>					
sbit key1=P3^4;
sbit key2=P3^5;
sbit key3=P3^6;
sbit key4=P3^7;	                          
unsigned int i,j,m,n;		    
unsigned char led,High,Low;
char key_s;		                          

void delay(unsigned char x)                          //延时函数,延时x毫秒
{
    unsigned char a,b,c;
	for(c=x;c>0;c--)
        for(b=4;b>0;b--)
            for(a=248;a>0;a--);
}

void delay_1()							             //按键一的延时
{
    if(key_s==1)
	{
	    delay(500);
	}
}

void delay_2()						            	 //按键二的延时
{
    if(key_s==2)
	{
	    delay(500);
	}
}

void delay_3()					             		 //按键三的延时
{
    if(key_s==3)
	{
	    delay(500);
	}
}

void delay_4()						                 //按键四的延时
{
    if(key_s==4)
	{
	    delay(500);
	}
}


void key()								             //各个按键的响应函数
{
    P1 = 0xff;
	while(key_s==1)
	{
	    delay(500);
		P1 = ~P1;
		delay_1();
		P1 = ~P1;
	}
	while(key_s==2)
	{	
	    led = 0xfe;
	    P1 = led;
	    for(j=1;j<8;j++)
		{ 
			delay_2();
			led=led<<1;
			P1 = led;
		}		    
		delay_2();delay_2();
		led = 0xff;
		j = 1;
		P1 = led;
		delay_2();
	} 
	while(key_s==3)
	{	
	    P1 = 0xfe;
		for(m=1;m<8;m++)
		{	
			led = 0xfe;
			delay_3();
			led = _crol_(led,m);
			P1 = led;	    
		}
		for(n=1;n<8;n++)
		{	 
		    led = 0x7f;				
			delay_3();
			led = _cror_(led,n);				    
			P1 = led;
		}
		m = 1; n = 1;
    }   
	while(key_s==4)
	{
	    led = 0x7e;
	    High=led&0xF0;	
	    Low=led&0x0F;
		for(i=0;i<4;i++)
	    {	
			led=(High&0xF0)|(Low&0x0F);
			P1 = led;
			delay_4(); 
		    High=~(~High>>1);	
		    Low=~(~Low<<1);	             
		}
		i = 0;
	}
}   

void key_state()               				         //按键状态
{ 
   	if(key1==0||key2==0||key3==0||key4==0)
	{	
	    delay(10); 
		if(key1==0||key2==0||key3==0||key4==0)
        {
            if(key1==0)
	            {key_s = 1;}
            else if(key2==0)
	            {key_s = 2;}
	        else if(key3==0)
	            {key_s = 3;}
	        else if(key4==0)
	            {key_s = 4;}
		}
	}
}

void main()											 
{   
    TMOD = 0x01;    //选择模式
	EA = 1;       //总中断打开

	//高八位  (65536-50000)/256 转 16 进制数,也可以直接写TH0=(65536-50000)/256 ,这里的50000即5万微秒,就是50毫秒,自定义时间,不要超过65536
	TH0 = 0x3c;    
	TL0 = 0xb0;   //低八位  	同理TL0=(65536-50000)%256
	ET0 = 1;    //定时器中断打开
	TR0 = 1;    //定时器开关打开
	while(1)
	{key();}
}

void Timer0() interrupt 1							 //定时器中断,间隔50ms
{
	TH0=0x3c;
	TL0=0xb0;	
    key_state();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值