广告() 还是先看下面的一个电路图,还是仔细看P2接口,这里我们接了一个发光二极管D1,又接了一个按键S2,我们想实现的功能是:按下按键S2,发光二极管D1改变发光状态。实际上就是模拟家庭的电灯开关。
当然了,要实现这样一个功能大可不必如此兴师动众,又是单片机又是最小系统的,实际用一个简单的闭合开关、一个限流电阻、一节电池、一个灯泡就足矣啦。但是在这可不单单是为了点亮一个灯而已,通过这个小案例,我们会引出单片机开发板系统里面两个非常重要的概念,“按键去抖”和“中断”!下面的内容涉及到好多编程理念,请认真阅读。
说到按键作者不禁要吐一下槽。作者曾经问(其实也被问过)这样一个问题:假设说单片机的P2.0管脚接按键,P2.4接发光二极管,怎样用按键控制灯的亮灭?
有人脱口而出:按键中断!(这是后文书,现在说出来太早了,掌嘴!)
还有人说:在单片机内部从P2.0直接接一条电线到P2.4……
我说:……
好吧,作者承认第一天学单片机的时候我也是这么认为的!
为什么要说这个呢,因为正如第一节我说的,很多人初学单片机的时候会错误地认为单片机是靠纯电路实现的控制,但是事实上它是依靠单片机识别和控制管脚电平来实现各种功能的。单片机就是一个非常听你话的大脑,你让它做啥,它就做啥了。比如想要实现如图按键控制二极管的功能,就让单片机一直监测P2.0的电平状态,S2在没有按下的时候,P2.0通过R4直接连接到VCC,电平状态肯定是高电平,若S2按下,P2.0此时会接地,电平变成低电平,所以当单片机发现P2.0管脚的电平状态变成低电平的时候就知道此时有按键按下了,然后单片机再通知P2.4管脚,让D1转变发光状态,整个过程就是这样的,然后我们将它转换成一个比较专业的程序流程图,就如下图所示。
然后再根据上面的流程图编写程序,代码如下所示:
#include<reg52.h>
sbit S2=P2^0;
sbit D1=P2^4;
/********************************************************
**函数名:main(void)
**返回:无
**函数功能描述:按键控制灯的亮灭
**********************************************************/
voidmain(void) //程序开始运行
{
D1=1; //程序初始化,令二极管不发光
while(1) //循环检测
{
if(S2==0) //如果检测到P2.0管脚为低电平,即按键按下
{
D1=~D1; //二极管转换发光状态,返回继续循环检测
}
}
}
应该可以看出,根据流程图来编程会让思路更加清晰,以后等大家编程编的多了的时候就更能体会程序流程图的重要性。
好了,一个按键控制电灯的程序就编好了。
那么,真的编好了吗?
试着把程序下载到单片机里,运行一下,看看是不是您想要的效果呢?
好吧,告诉你,这样还不行。你可以试着按下按键,会发现电灯并不是像您想的那样那么听话,有时候确实改变了发光状态,有时候就不变,有时候还会变好几次,这是要闹哪样?
我们来看一下按键按下去后P2.0管脚电平的变化情况,下图是一个理想情况的示意图。
T0时刻:按下按键,P2.0电平由高电平转换为低电平。
T1时刻:抬起按键,P2.0电平由低电平转换为高电平。
当单片机P2.0管脚检测到低电平的时候,D1发生转变。你要知道,这个过程在单片机里发生的极快,大概是微秒级的数量级,而按键按下去再抬起来,这个时间段对应的是毫秒级的数量级,所以在T0到T1这个时间段里,其实D1已经发生了若干次的转换,这个不是我们想要的效果,我们想着按键按一次,D1就转换一次,那这该如何实现呢!
思路是这样的,当按键按下去的时候,单片机开始等待,一直等到按键抬起来的时候让D1再转变状态。代码改成下面的样子。
#include<reg52.h>
sbit S2=P2^0;
sbit D1=P2^4;
/********************************************************
**函数名:main(void)
**返回:无
**函数功能描述:按键控制灯的亮灭
**********************************************************/
voidmain(void) //程序开始运行
{
D1=1; //程序初始化,令二极管不发光
while(1) //循环检测
{
if(S2==0) //如果检测到P2.0管脚为低电平,即按键按下
{
while(S2==0); //当P2.0为低电平的时候,单片机在此等待
D1=~D1; //二极管转换发光状态,返回继续循环检测
}
}
}
上面加了一句“while(S2==0);”这句代码等效于“while(!S2);”,意思是当括号内的语句为真时(P2.0为低电平),单片机程序在此等待,直到括号内语句为假时(P2.0变回高电平),程序往下继续运行。
好了,这下运行一下程序,看看是不是能达到您想要的效果来了。
。。。
那么,效果真的好了吗?
。。。
好吧,好像还是不行,上面的程序如果加载到类似于Proteus的仿真软件里(请参阅第五章Proteus仿真软件教程),程序运行起来一点问题也没有。但是下载到真正的单片机里运行起来虽然比不加“while(S2==0);”这句代码的时候要强一些,但时不时的还是不太听话。原因何在?
原因就在于一句非常有名的名言啊“现实往往比理想差好远!”,按键按下的电平变化会由于电路的稳定性和手的抖动产生一个非常不规则的波形,如下图所示,在按下和抬起的一刹那都会产生一个抖动区,不要小看这个抖动区,它足以让单片机产生误会,导致D1发生偏转。
所以在编写按键程序的时候往往都要加一个“去抖”过程,也就是当单片机P2.0口检测到低电平时,单片机不做任何处理,空等一段时间(10ms左右),再次检测P2.0端口,如果此时P2.0端口仍然是低电平,那就认为此次果然按下了按键,D1开始转换状态。重新编写程序,如下所示:
#include<reg52.h>
#define uintunsigned int
sbit S2=P2^0;
sbit D1=P2^4;
/********************************************************
**函数名: delay(uint x)
**返回:无
**函数功能描述:延时函数,延时大概x毫秒
**********************************************************/
voiddelay(uint x) //延时函数,让单片机空跑一段时间。
{
uint i,j;
for(i=0;i<=x;i++)
for(j=0;j<=100;j++);
}
/********************************************************
**函数名:main(void)
**返回:无
**函数功能描述:按键控制灯的亮灭
**********************************************************/
voidmain(void) //程序开始运行
{
D1=1; //程序初始化,令二极管不发光
while(1) //循环检测
{
if(S2==0) //如果检测到P2.0管脚为低电平,即按键按下
{
delay(10); //延时一下
if(S2==0)
{
while(S2==0);
D1=~D1; //二极管转换发光状态,返回继续循环检测
}
}
}
}
这下再试试,看看效果如何?
。。。
好吧
。。。
效果应该是不错了,假如还有问题的话就改改delay函数里面的参数值,多试几次肯定能调整出最好的效果。(这里如果告诉你,其实程序还是有问题的话,你会不会疯掉呢?-_-||)
再补充一句,有些时候我们闲编写去抖程序比较麻烦,可以在按键那里加一个滤波电容,如下图所示。按键按下后,若有抖动,电容C会起到一定的滤波作用,效果就会强很多,大家可以做实验试试看。
还有一个思路呢!上文咱们用到的按键都是自动弹起的,还有一种按下去就不弹起的开关呢,那种开关就简单多了,按下去就一直导通,再按一下才抬起,我用这么文艺的方式给您解释相信您一定能想的出那种开关长得什么样子吧。
广告(进入立创商城,点阅读原文)
关于立创商城
立创商城(WWW.SZLCSC.COM)是中国在线订单成交量最大的一站式电子元器件采购自营商城,自建6000多平方米现代化元器件仓库,现货库存超40000种。作为深圳嘉立创集团(电子全产业链自营服务涵盖:在线EDA(EasyEDA)+行业领先的PCB打样/中小批量+元器件商城+钢网制造+SMT贴片+电子设计教育及方案)旗下一家品种齐全、自营库存、质量有保障的电子元器件垂直商城,立创商城所有元器件均由原厂或代理商正规渠道采购,保证原装正品,为您提供专业的一站式电子元器件采购服务。