书接上回讲了LED的引脚,现在来分享按键模块
下面是按键模块及其原理图
按键其实就是一个会回弹的振片,通过内部设计使得按键按下时,电路被接通(不再是断路的状态),电路中的电流从无到有,电平发生变化,观察原理图发现按键一端接GND一端接P3口,GND其实就是接地,也就是低电平,P3口默认接的是高电平,而按键如果按下,对于一个导通的线(例如图中的绿色线)来说,P3_1的电平就会跟GND一样,也就是低电平,而这种变化被单片机捕捉到,从而检测到按键按下的操作。这就是检测按键按下的基本原理。
了解了基本原理,来看代码如何实现检测按键按下(补充:~是逻辑电路中的非门,其实就是电平状态取反,比如P2_1=1; ~P2_1后 P2_1=0;)
#include <REGX52.H>
void main()
{
while(1)
{
if(P3_1==0)//P3_1是第一个按键的引脚,用于检测第一个按键的按下与否,
//P3口引脚开始是默认为高电平,按下按键使电路导通后,
//P3口就接地(GND)也就是变成低电平。1表示高电平,0表示低电平
{
P2_0=0;//如果按下第一个按键就让第一个LED点亮
}
else
{
P2_0=1;//按键重新变为断开状态则第一个LED熄灭
}
}
}
在单片机上运行代码发现不足之处是我要一直按着按键才能使LED一直亮,但是一松手,LED就熄灭了。想着能不能实现按下一次后LED就一直亮,再按下一次LED就熄灭。这就运用到while循环的一个巧妙思想。
#include <REGX52.H>
void main()
{
while(1)
{
if(P3_1==0)//如果按键1按下
{
while(P3_1==0); //这要手指还在按着按键,就再循环里一直不出来,手指松开,则跳出循环
//执行LED的命令
P2_0=~P2_0; //手指松开,使LED1口的电平反转,达到按下一次,小灯亮灭情况变化一次
}
//思考可知按键此时是松手那一刻跳出while循环才点亮LED1。即松手点亮。由于已经松手,P3_1==1,不满足if判断条件,也就不能进入if的执行语句,LED1刚刚被翻转的电平一直不变,也就能实现不用一直按着按键也能让灯一直亮着了。
}
} //如果再按下一次按键,就再进入if语句里,把电平再翻转一次。由亮,变为不亮。
编译烧录后发现现象还是有点小故障,其实是因为弹片在按下和弹起的时候都会有微小的振动,振动时间很段,就几毫秒的时间,但是对于单片机这样高速运行的CUP来说振动的时间并不是极短的,抖动造成的电平变化是不可以被忽略的。
振动时也会引起电平变化,我们为了振动的电平变化不被检测到,我们就用一个延时函数delay,让CPU去执行delay函数而忽略弹片的振动,我们把这样的行为叫消抖
#include <REGX52.H>
void Delay(unsigned int xms)//延时函数
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main()
{
while(1)
{
if(P3_1==0) //如果K1按键按下
{
Delay(20); //传入参数,知道到底要延时多少毫秒,由于按键抖动一般在10ms左右,延
//时20毫秒就够了。目的是为了消按键按下的抖动。
while(P3_1==0); //松手检测
Delay(20); //目的是为了消按键弹起的抖动
P2_0=~P2_0; //翻转LED的亮灭情况。
}
}
}
总结前面学到的东西:1:按下按键,导通电路,P3口变为低电平。 2:松手点亮 while循环 。 3:按键消抖 delay函数延时。
接下来尝试用学到的知识完成单片机上与按键有关的小题目
题目1:按下按键1实现让LED的8个灯,从左往右的流水。按下按键2实现LED全部熄灭的效果,按键3实现让LED流水灯延时时间增加。按键4实现让LED流水灯从右往左的流水。
#include <REGX52.H>
sbit key1 = P3^1; //仔细查看原理图的引脚定义,发现按键1是P3_1引脚,发现按键2是P3_0引脚,并没有
//按0123的顺序来。
sbit key2 = P3^0;
sbit key3 = P3^2;
sbit key4 = P3^3;
unsigned int time = 100;
void delay(unsigned int t) {
unsigned int i, j;
for(i = t; i > 0; i--)
for(j = 110; j > 0; j--);
}
void main() {
int i=0;
unsigned char code Led_mod[]={0XFE,0XFD,0XFB,0XF7,0XEF,0XDF,0XBF,0X7F,0XFF};//从1111
1110开始
while(1)
{
if(key1 == 0) //如果按键1按下
{
for(i=0;i<8;i++) //循环数组得到流水灯
{
P2=Led_mod[i];
delay(200);
}
}
if(key2 == 0) //如果按键2按下
{
P2 = 0xFF; //由于是低电平使能,故全灭就是1111 1111
}
if(key3 == 0) //如果按键3按下
{
time += 50; //延时时间增加
if (time > 500) //延时时间最大不能超过500
{time = 500;}
for(i=0;i<8;i++) //循环遍历数组得到流水灯
{
P2=Led_mod[i];
delay(time); //延时函数使传入time变量而不是直接传入一个值
}
}
if(key4 == 0) //如果按键4按下
{
for(i=8;i>=0;i--) //从右往左的流水灯
{
P2=Led_mod[i];
delay(200);
}
}
}
}
等后续学习到中断函数就可以优化此题目。