本文章来自www.zyxmcu.com(张彦欣单片机),更多内容,敬请登录。
在上一节,我们讲了如何用单片机的IO口控制外部的发光二极管发光,设置组成漂亮的流水灯。这一节,我们学习如何使用单片机读取外部IO口的状态。这其中的用处是极其广泛的,比如读取传感器的状态等等,都需要这个功能。
虽然说起来用处大,但是这确实极其简单的一个过程。首先,我们先来看一个例子:
void main()
{
if(P0 == 0x00) //读取P0口的状态,检查P0口是不是全部是低电平。
{
P1=0xFF; //如果P0口全部是低电平,则让P1口全部输出高电平。
}
else
{
P1=0x00;
}
}
看上面的这个程序,是不是非常的简单?就是判断P0口是不是0x00。有人可能要问了,如果我要判断P0.0端口的状态呢?我应该如何编写?下面几种方式都可以(可以,但不限于这几种方法):
【1】首先定义位变量:
sbit PORT = P0^0; //首先将P1^0定义成一个“位变量”PORT(其他名字也可以)。
if(PORT == 1){……} //然后判断这个位变量的状态。
【2】通过逻辑运算:
if(P0&0x01 == 0){……} //通过“按位与”运算符将P0口的状态“与上0x01”。(不懂不要紧)
通过这个电路,我们可以很明显的看出来,当按键没有按下时候,端口“RST”处的电平是低电平;当按键按下去的时候,“RST”处的电平是高电平。那么,如果我们将这个按键电路的输出接到了P0.0端口上,我们就可以非常简单的检测出按键是否按了下去:
sbit KEY == P0^0;
if(KEY == 1) //按键按了下去
{……}
else if(KEY == 0) //按键没有按下去
{……}
你应该已经看到了吧,按键的电路就是这么简单。当然,以上的按键只是一种形式,你可以设计任何形式的电路,只要是按键在按下去前后有部分“变量”发生了改变,而单片机可以检测到这种变量。什么意思呢,就是说,你只要抓住某个“变量”发生了变化就可以。比如,上面的电路是按下去前后输出电平发生了变化,而单片机可以直接检测这个信号,那么这就是一个成功的按键电路;有些按键按下去以后,是电容值发生了变化,经过一系列的转换电路,也可以将这个变化转变成一个数字信号,这就是电容式按键;还有的按键电路,是按下去后电阻值发生了变化,通过一定的信号处理单元,单片机也可以计算出按键的状态,这也是很多触摸屏的工作原理。
总之,发挥你的想象,创造出更多的按键电路吧~~
既然已经谈到了按键电路,那有些需要注意的东西就不得不讨论一下了:
1.干扰的滤波问题。
如果有一个代码是这样写的:
sbit KEY == P0^0;
if(KEY == 1) //按键按了下去
{……}
else if(KEY == 0) //按键没有按下去
{……}
请问这个代码是否是可行的呢?有人可能奇怪了,这是我们刚才学习时候用的代码啊?怎么可能有问题呢?对,这就是问题。学习、理论和实际是有些许区别的。这行代码“不健康”(形容代码不能稳定有效的运行)的原因有:
A.单片机运行中可能有干扰,单片机的某个引脚可能遇到外部信号的影响(比如打雷、电动机的起停等),出现信号杂波干扰。这个时候可能出现脉冲尖峰干扰(出现一个时间极短的错误信号)。以上这几行代码显然不能抗干扰,会对这样的脉冲出现误动作。
B.人们在用手按一个按键的时候,其实微观上不是立即闭合的。其实我们在按一个按键的时候是断开--时断时续--闭合的过程。正如下图所示,这是一个振荡的过程。如果在振荡过程中,没有滤波,那么单片机就会认为是按下按键很多次,那么就可能发生很多次响应,导致错误(很有些场合,可能发生致命错误甚至人身伤亡)。
综上所述,按键的“去抖”问题,是必须要引起重视的。那么按键去抖都有那些方法呢,下面我们就开始讨论这个基本但是严肃的问题:
A。使用一个电容滤波是个不错的选择。我们都知道,电容两端的电压不能突变,这就意味着电容两端的电压变化是比较“平滑”的,这刚好对于这种“脉冲式”的杂波有着非常好的滤波效果。
B。有的最普遍,也是最有效的滤波方式是软件滤波。我们仔细分析一下以上的两个干扰的“共同点”,就是都是一个“非常短暂”的过程。都属于“脉冲式”的干扰。对付这样的干扰有什么好的办法吗?当然有--“延时”。先看看例子:
void mian()
{
sbit KEY = P0^0;
if(KEY==1) //检测到有按键按下的时候,不要立即执行相关程序。
{
Delay_20ms(); //延迟20ms以后再次检测按键状态。这个函数需要用户自己编写。
if(KEY==1) //如果按键还是按下的,执行相关的程序。
{......}
}
}
以上这个方法是非常常用的方法,也是比较经典的方法。当然,按键电路的方式还有很多,而每个方法肯定都有自己的优缺点。比如这个方法虽然简单,但是在延时20ms的时候CPU不响应任何的请求,造成系统实时性比较的差。
我自己经常用的是我自己发明的“事件驱动法”,这个用法在我的EDN博客中有说明(但是是早期的,不是很完善)。其主要的思想就是当按键按下后,就开始计数,计数到达一定的数值后就算按键被按下;当检测到按键松开后,立即清零计数值(当然这其中有很多的标志位和数据溢出等问题需要注意)。
用户1709358 2010-9-8 10:54