极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 223770|回复: 65

arduino学习笔记6 - 按键实验

  [复制链接]
发表于 2011-7-5 22:26:17 | 显示全部楼层 |阅读模式

按键是一种常用的控制电器元件,常用来接通或断开电路,从而达到控制电机或者其他设备运行的开关。按键的外观多种多样,本次实验使用的是这种微型按键,6mm的,如下图。




此种按键有4个脚,从背面看是这样子的。





在按键没有按下去的时候1,2号脚相连,3,4号脚相连。按键按下去的时候,1,2,3,4号脚就全部接通。

本次实验使用按键来控制led的亮或者灭。
一般情况是直接把按键开关串联在led的电路中来开关,这种应用情况比较单一。
这次实验通过间接的方法来控制,按键接通后判断按键电路中的输出电压,如果电压大于4.88V,就使给LED电路输出高电平,反之就输出低电平。使用逻辑判断的方法来控制LED亮或者灭,此种控制方法应用范围较广。

本次连接方法如下图。按键开关两段一端连接5V接口,一端连接模拟5号口。LED长针脚串联220Ω电阻连接数字7号口,短针脚连接GND。






把下面的代码上传到arduino控制板上,看看效果。
  1. int key=7;//设置LED的数字IO脚
  2. void setup()
  3. {
  4.   pinMode(key,OUTPUT);//设置数字IO引脚为输出模式
  5. }
  6. void loop()
  7. {
  8.   int i;//定义变量
  9.   while(1)
  10.   {
  11.     i=analogRead(5);//读取模拟5口电压值
  12.     if(i>1000)//如果电压值大于1000(即4.88V)
  13.       digitalWrite(key,HIGH);//设置第七引脚为高电平,点亮led灯
  14.     else
  15.       digitalWrite(key,LOW);//设置第七引脚为低电平,熄灭led灯
  16.   }
  17. }
复制代码
本次实验的效果如下


本次实验使用到analogRead()这个新命令。
analogRead()作用是读取模拟口的数值。默认是把0-5V的输入电压分成1024份,每一份大约为0.0049V,其数值在0-1023之间。
在本次程序代码中的读取数值如果大于1000则给LED输出高电平, 所对应的电压也就为大于4.88V。
analogRead()命令输入的范围与分辨率可以使用analogReference()命令进行改动。


刚开始本实验选用的判断标准是512,也就是2.5V。但是有网友按照教程的方法进行试验发现有问题,有时不需要按按钮灯就会自己亮。根据多次试验与分析后,确定其为各种干扰所致。比如感应电流等等不少都是大于2.5V的,所以为了提高准确度,只能提高判断的电压,本次实验就是提高到1000(4.88V)。人体自身也带电,早中晚还个不一样。下面的实验就是把模拟5号口判断标准定位512,用手去触摸模拟5号口导线就可以点亮LED。



前面的按键实验,有人会反映手接近开关就会亮灯。这个是因为没有下拉电阻,使得外界干扰影响了判断。

先来看一下下拉电阻的接法。在接按键的接口与GND之间接一个1K-10K Ω的电阻。其作用是当外界有干扰源的时候,在断开状态下,干扰源在通向GND的过程中,会被电阻消耗掉。




看一下硬件连接图,本次实验直接使用arduino duemilanove 13号口自带的led作为指示灯。



下面的代码和上面的不同,其中加入了软件消抖。因为本次例子是按键按一次灯亮,再按一次灯灭,如果不加消抖,就会产生按下去状态无法改变的情况。
软件消抖指的是检测出键闭合后执行一个延时程序,产生5ms~10ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。当检测到按键释放后,也要给5ms~10ms的延时,待后沿抖动消失后才能转入该键的处理程序。
硬件消抖是在开关两段接一个0.1uf的电容,但是其无法替代软件消抖。 其作用不同,搭配使用效果最好。
感谢ansifa提供的加入了软件消抖的实验代码。
  1. /*
  2. 开关连接实验
  3. 接线方法:
  4. 材料:一个轻触开关、一个10kΩ电阻,一个0.1uF电容(可选)
  5. 连接方法:
  6. 开关接在Arduino D3和+5V之间;
  7. 10kΩ电阻接在Arduino D3和GND之间;
  8. 0.1uF电容接在Arduino D3和+5V之间(可以不用电容);
  9. */

  10. int Button=3; //连接开关到D3。
  11. int LED=13; //连接LED到13(实际上UNO等版本已经有了)。
  12. boolean onoff=LOW; //设定一个变量用于记录开关状态。
  13. void setup()
  14. {
  15.   pinMode(Button,INPUT); //按钮端子作为输入
  16.   pinMode(LED,OUTPUT); //LED端子作为输出
  17. }
  18. void loop(){
  19.   if(digitalRead(Button)==LOW)  //由于本例检测上升沿触发,所以先检测输入是否低电平,
  20.   {
  21.     delay(10); //然后延时一段时间,
  22.     if(digitalRead(Button)==HIGH) //然后检测是不是电平变为高了。是的话,就是刚好按钮按下了。
  23.     {
  24.       digitalWrite(LED,onoff);  //写入当前LED状态onoff,
  25.       onoff=(!onoff); //然后LED状态反转,以便下一次使用。
  26.       delay(10);  //延时一段时间,防止按钮突然断开再按下。
  27.       while(digitalRead(Button)==HIGH) //判断按钮状态,如果仍然按下的话,等待松开。防止一直按住导致LED输出端连续反转
  28.       {
  29.         delay(1);
  30.       }
  31.     }
  32.   }
  33. }
复制代码
下面是这段代码的效果:


当没有下拉电阻的时候,可以明显看到下面的示波器波形,按键断开时低电平漂浮不定,这样子容易出现误判。看按键按下与松开的波形,也能明显感觉到低电平不稳。









当接上电阻后,低电平的稳定了,按键按下时,波形没问题,但是按键松开时,波形抖动很厉害。







最完美的是把下拉电阻和电容都接上,这样就综合了所有优点,按键松开时,波形很稳定。







本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2012-5-26 01:05:13 | 显示全部楼层
本帖最后由 zxuan 于 2012-5-26 01:17 编辑

我测试了一下,数字端口那个实验代码,需要在void loop() 里面第一句加上

  digitalWrite(LED,onoff);

否则上电或者复位后的第一次按键,执行结果仅仅是造成写LOW给数字端口,onoff变量状态虽然翻转,可是灯不会亮,要按第二次才会亮灯。加上这一句之后,状态反转完毕的下一周期就亮灯了,感觉几乎是按键同步的。

又思考了一下,在
      {
        delay(1);
      }
      digitalWrite(LED,onoff);

后面加上也是可以的。等于在按键操作结束,按钮抬起,电平状态稳定回到低电平,状态翻转后写端口,感觉上更为合理一些。测试的时候是每次在按键抬起之后,灯的状态翻转。
回复 支持 2 反对 0

使用道具 举报

发表于 2011-10-16 20:54:46 | 显示全部楼层
没有上/下拉电阻,当然容易干扰...
回复 支持 1 反对 0

使用道具 举报

发表于 2011-7-10 17:50:03 | 显示全部楼层
问:对于这种外界干扰,会影响程序执行状态,对于模拟口抗干扰弱,官方有什么具体解决方案吗
回复 支持 0 反对 1

使用道具 举报

发表于 2011-7-6 18:26:00 | 显示全部楼层
int key=7;//设置控制按键的数字IO脚   ?  错了,设置LED的数字IO脚
可否解释下while(1)函数的应用
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-7-6 18:43:44 | 显示全部楼层
偶是谁 发表于 2011-7-6 18:26
int key=7;//设置控制按键的数字IO脚   ?  错了,设置LED的数字IO脚
可否解释下while(1)函数的应用

哈哈~~~谢谢指出错误~~~马上改正。while()函数我晚上在教程里补充讲解下~
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-7-6 19:57:36 | 显示全部楼层
偶是谁 发表于 2011-7-6 18:26
int key=7;//设置控制按键的数字IO脚   ?  错了,设置LED的数字IO脚
可否解释下while(1)函数的应用

while()函数讲解我在蜂鸣器实验中进行补充了
http://www.geek-workshop.com/for ... 1&extra=#pid109
回复 支持 反对

使用道具 举报

发表于 2011-7-7 12:57:11 | 显示全部楼层
这个实验,我的没有成功,下载程序后LED就亮了,模拟口5接地可以熄灭,
接3.3V灯亮度增加,不知何解,我单片机是328p-PU
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-7-8 09:40:03 | 显示全部楼层
偶是谁 发表于 2011-7-7 12:57
这个实验,我的没有成功,下载程序后LED就亮了,模拟口5接地可以熄灭,
接3.3V灯亮度增加,不知何解,我单 ...


经过反复做实验,我找到原因了~~~原因是设置到512太小了~也就是2.5V的检测电压

因为外界干扰太多,比如人体就带电,或者感应电之类的~~~~如果设置到512(2.5V)检测电压,我手去摸住5号检测口,灯都会亮。你也可以试一试,用手摸住模拟5号口导线~~~

所以基于这个外界干扰问题,只能提高检测电压,我把检测电压提高到1000(程序中修改),也就是接近5V,然后开关一只脚接5V口,一只脚接模拟5号口~~这样干扰问题基本就很少了~~~

谢谢你提的问题,刚开始我模拟时还没出现这个干扰问题。。。后来多做了几次就出现了~

我一会儿把教程修改一下,正好把您提出的这个问题也在教程中进行说明~再次感谢你找出来的问题
回复 支持 反对

使用道具 举报

发表于 2011-7-10 12:29:17 | 显示全部楼层
还有一个问题,就是我感觉LED好像有一个缓慢熄灭的过程,特别是人体感应的时候,虽然时间很短,关断不那么彻底
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-7-10 13:12:12 | 显示全部楼层
偶是谁 发表于 2011-7-10 12:29
还有一个问题,就是我感觉LED好像有一个缓慢熄灭的过程,特别是人体感应的时候,虽然时间很短,关断不那么彻 ...


这个现象很有可能是和arduino控制板中使用的电容有关,如果有电容,电容充满电以后,就算电源消失,电量不会瞬间没有,而是电容逐步放出来。
比如输入电压是5V,检测电压是2.5V。那么电容从5V放电到2.5V的过程可能有200毫秒,那么肉眼就可以察觉。
如果输入电压是5V,检测电压是4.88V,那么电容从5V放电到4.88V过程可能就是10毫秒,这个时间太短,肉眼就无法察觉了。

还有一个就是如果人体电压高于5V,同样4.88V的判断标准下,因为电容通过人体充电后电压高于5V,所以放到4.88V时间也会比标准5V放到4.88V时间久~~~
回复 支持 反对

使用道具 举报

发表于 2011-7-10 17:52:38 | 显示全部楼层
补上:好像数字IO口开关应用不存在这种问题
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-7-11 20:34:45 | 显示全部楼层
偶是谁 发表于 2011-7-10 17:50
问:对于这种外界干扰,会影响程序执行状态,对于模拟口抗干扰弱,官方有什么具体解决方案吗


这种暂时没有太好的解决方法,只能说提高判断电压尽量降低外界干扰造成的影响
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-8-28 20:46:43 | 显示全部楼层
转载风教授的一段代码,写的很好,也是按键控制LED的,按一次开,按一次关。
  1. int kaiguan=3;//连接开关到IO3
  2. int LED=13;//连接LED到13(实际上UNO等版本已经有了)
  3. int onoff=0;//设定一个变量用于记录开关被按下了偶数还是奇数次,按一次,为奇数次,=1;两下就是偶数次,=0
  4. void setup()
  5. {pinMode(3,INPUT);pinMode(13,OUTPUT);}
  6. void loop(){
  7.   if(digitalRead(3)==HIGH){
  8.     if (onoff==0){
  9.     onoff=1;}
  10.   else{onoff=0;}//记录开关被按下的次数部分
  11. }
  12. if(onoff==0)
  13. {digitalWrite(LED,HIGH); }

  14.   else{digitalWrite(LED,LOW);}//根据到底按了多少下确定到底是点亮LED还是熄灭
  15. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2011-10-16 18:42:07 | 显示全部楼层
loop已经是循环了,为虾米还要加while(1)?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-10-16 18:57:05 | 显示全部楼层
Dawn 发表于 2011-10-16 18:42
loop已经是循环了,为虾米还要加while(1)?

介个由其他代码改的。。。所以嘛,就没有进行优化直接粗略加工的用了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-19 20:41 , Processed in 0.049053 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表