单片机(AT89C51)按钮控制LED灯实现流水灯,闪烁流水灯
目录
前言
好久没有写单片机系列了,话不多说,直接进入正题吧!本次要讲解和分享的实验是一个比较著名的流水灯实验,但这个实验是通过自己点击按钮实现“流水”的,和我的一篇(单片机(AT89C51)的仿真实验——流水灯和逐一闪烁灯(输入与输出))Blog有所不同,对于纯编码的流水灯有兴趣的也可以去看看这篇文章。还有我推出了一系列的单片机知识点总结和实验分享:单片机大全,对此有兴趣的也可以关注一下,方便后续的学习。
实验要求和目的
-
实验一:每按一次独立键盘的S1键,与P1口相连的八个发光二极管中点亮一个往下移动一位
-
实验二:上电的时候,L1接在P1.0管脚上的发光二极管在闪烁,按下一次开关,使得下一个灯开始闪烁点亮,如此循环。
-
实验三:实现不同开关按钮操作的时候有不同的效果,自己设计了一个实验实现了两个不同按钮按下的时候出现不同的效果,对上面两个实验加以结合,得到了——按下第一个按钮的时候正常的跳到下一个LED灯(不闪烁),按下第二个按钮的时候跳到下一个LED灯并且闪烁。
实验电路图
本实验主要有单片机、发光二极管、1K排阻组成,实现电路如下:
实验过程
实验一
实验分析:实验过程中需要注意的就是分为两个部分来写函数,一个识别按键是否按下的函数key()和执行流水灯循环的move()函数。在key函数中有一个全局变量会自加,主要是为了在move函数中的移位操作。
实验代码:
#include<reg51.h>
sbit BY1=P3^4; //定义按键的输入端S建
unsigned char count; //按键计数,每按一次加1
unsigned char temp;
unsigned char a,b;
void delay10ms(void) //延时程序
{
unsigned char i,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
key() //判断按键是否按下
{
if(BY1==0) //判断是否按下按钮
{
delay10ms(); //延时去抖动
if(BY1==0) //确认按键是否按下
{
count++; //按键计数加1
if(count==8)
{
count=0;
}
}
while(BY1==0); //按键锁定,每按一次count+1
}
}
move()
{
a=temp<<count;
b=temp>>(8-count);
P1=a|b;
}
main()
{
count=0;
temp=0xfe;
P1=0xff;
P1=temp;
while(1) //永远循环,扫描判断按键是否按下
{
key(); //调用按键识别函数
move(); //调用移动函数
}
}
截图看不出动态的效果,但又传不了视频。这里建议CSDN修改一下机制,可以让我们自己录的视频也可以上传,关心关心我们这些小众博主
实验二
实验二和实验的有所不同的就是要实现灯的闪烁嘛,然后开关移位的操作还是和前面的实验一模一样,我们就需要把move()函数进行修改即可,为了对比性我把move函数重写成了move1()函数。
实验的完整代码:
#include<reg51.h>
sbit BY1=P3^4; //定义按键的输入端S建
unsigned char count; //按键计数,每按一次加1
unsigned char temp;
unsigned char a,b;
void delay10ms(void) //延时程序
{
unsigned char i,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
key() //判断按键是否按下
{
if(BY1==0) //判断是否按下按钮
{
delay10ms(); //延时去抖动
if(BY1==0) //确认按键是否按下
{
count++; //按键计数加1
if(count==8)
{
count=0;
}
}
while(BY1==0); //按键锁定,每按一次count+1
}
}
move()
{
a=temp<<count;
b=temp>>(8-count);
P1=a|b;
}
//带闪烁的移动
move1()
{
a=temp<<count;
b=temp>>(8-count);
while(1) //进入死循环,按键按下时跳出
{
P1=a|b;
delay10ms(); //延时
P1=P1|0xff; //使得LED的状态相反
delay10ms(); //延时
if(BY1==0) //按键按下的时候跳出循环,进入执行key()函数
break;
}
}
main()
{
count=0;
temp=0xfe;
P1=0xff;
P1=temp;
while(1) //永远循环,扫描判断按键是否按下
{
key(); //调用按键识别函数
//move(); //调用移动函数
move1(); //使用移动加闪烁函数
}
}
move1()函数详解:
//带闪烁的移动
move1()
{
a=temp<<count;
b=temp>>(8-count);
while(1) //进入死循环,按键按下时跳出
{
P1=a|b;
delay10ms(); //延时
P1=P1|0xff; //使得LED的状态相反
delay10ms(); //延时
if(BY1==0) //按键按下的时候跳出循环,进入执行key()函数
break;
}
}
前面对a和b的赋值就是为了使相应的灯亮起来,举一个例子:
当按下按钮第一次的时候,count就被赋值为了1,那么a就等于0xfe(temp)左移一位,那么a用二进制表示就是1111 1100,同理可得b用二进制表示就是:0000 0001 ,那么P1的初值就是a|b,用二进制表示就是:1111 1101 对应于电路图就是第二盏灯亮,延时10ms,P1=P1|0xff的操作是让当前亮的灯取反。如此往复的在死循环中,就会出现闪烁的效果,当有按钮按下的时候就会跳出循环,执行其他代码就可以实现实验目的。
实验三
综合前面的两个实验内容我们不难得出第三个实验就需要改变key函数实现连个按钮的控制 ,再加上一些代码的微调。
实验代码:
#include<reg51.h>
sbit BY1=P3^4; //定义按键的输入端S建
sbit BY2=P3^5;
unsigned char count; //按键计数,每按一次加1
unsigned char temp;
unsigned char a,b;
void delay10ms(void) //延时程序
{
unsigned char i,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
key() //判断按键是否按下
{
if(BY1==0) //判断是否按下按钮
{
delay10ms(); //延时去抖动
if(BY1==0) //确认按键是否按下
{
count++; //按键计数加1
if(count==8)
{
count=0;
}
}
while(BY1==0); //按键锁定,每按一次count+1
}
}
key2() //判断按键是否按下
{
if(BY2==0) //判断是否按下按钮
{
delay10ms(); //延时去抖动
if(BY2==0) //确认按键是否按下
{
count++; //按键计数加1
if(count==8)
{
count=0;
}
}
while(BY2==0); //按键锁定,每按一次count+1
}
}
move()
{
a=temp<<count;
b=temp>>(8-count);
P1=a|b;
while(1) //加入循环使得这个状态持续
{
if(BY1==0||BY2==0) //按键按下的时候跳出循环,进入执行key()函数
break;
}
}
//带闪烁的移动
move1()
{
a=temp<<count;
b=temp>>(8-count);
while(1) //进入死循环,按键按下时跳出
{
P1=a|b;
delay10ms(); //延时
P1=P1|0xff; //使得LED的状态相反
delay10ms(); //延时
if(BY1==0||BY2==0) //按键按下的时候跳出循环,进入执行key()函数
break;
}
}
main()
{
count=0;
temp=0xfe;
P1=0xff;
P1=temp;
while(1) //永远循环,扫描判断按键是否按下
{
key(); //调用按键识别函数
move(); //调用移动函数
key2();
move1(); //使用移动加闪烁函数
}
}
key2()函数和key()函数基本一样就改了最基本的参数。重点和上面不同的就是move函数中加了一个死循环使得可以在不闪烁的时候可以持续的点亮灯泡,不然会有点小问题。
实验总结
本次实验主要讲解了怎么通过外部的一个按钮指令来控制我们的LED灯的亮灭,实现了流水灯的运行,实验代码比较的简单,相信你可以看的透彻。毕竟进来的都不算凡人,都是高手。
后言
本次实验可能有更加简便的方法实现,希望可以得到大佬的指点,学习就是在相互指点和交流的情况下学习的,鄙人小白一个,要是有错请大佬指点!!!不胜感激!!!
No pains No results
上一篇: Hibernate 一级缓存的陷阱