基于51单片机四个按键四种方式电亮LED灯,示例中的为代码的主要部分,是实现功能的代码。delay表示延时,是自定义的函数,最终代码可直接运行。
51单片机多种方式点亮LED
方式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();
}