在我们的电子时钟设计里,通常会用到2-3个地理按键来完成对时间等其他信息的设置,在《Arduino入门教程》中我们已经详细讲解了独立按键模块的使用。在教程中我们是通过分析独立按键的电路,再到按键产出的信号,最终我们自己通过程序方式来获取到按键的信号,从而判断独立按键是否按下,最终实现了按键模块的使用。其实在Arduino强大的开源库中已经有一个库文件,可以很方便的实现独立按键的一次按下(单击),两次快速按下(双击)以及长按(长时间按下)等的按键检测了。使用这个库我们可以快速的完成按键的检测,快速的实现我们的任务功能,这个库文件就是“OneButton”库。可以直接在Arduino IDE的库管理中直接搜索,搜索结果只有一个,直接下载既可以。也可通过下方连接直接下载。
OneButton.zip
在OneButton库中有多个示例文件,大家可以自行查看,因为我们的电子使用需要使用3个独立按键,在示例程序中有个“TwoButton”的示例,其中有两个按键检测的程序,我就以此为例作简要说明。因为例程中所有注释都为英文,为方便大家查看,在此做了简单的中文化注释。
/*This is a sample sketch to show how to use the OneButtonLibraryto detect click events on 2 buttons in parallel.The library internals are explained athttp://www.mathertel.de/Arduino/OneButtonLibrary.aspxSetup a test circuit:* Connect a pushbutton to pin A1 (ButtonPin) and ground.* Connect a pushbutton to pin A2 (ButtonPin) and ground.* The Serial interface is used for output the detected button events.The Sketch shows how to setup the library and bind 2 buttons to their functions.In the loop function the button1.tick and button2.tick functions have to be called as often as you like.*/// 01.03.2014 created by Matthias Hertel// ... and working./* 一个输出示例:Starting TwoButtons... //按键按下后的输出明细Button 1 click. //按键 1 单击Button 2 click. //按键 2 单击Button 1 doubleclick. //按键 1 双击Button 2 doubleclick. //按键 2 双击Button 1 longPress start //按键 1 长按开始Button 1 longPress... //按键 1 长按。。。Button 1 longPress...Button 1 longPress...Button 1 longPress stop //按键 1 长按结束Button 2 longPress start //按键 2 长按开始Button 2 longPress... //按键 1 长按。。。Button 2 longPress...Button 2 longPress stop //按键 1 长按结束*/#include "OneButton.h"// 设置按键引脚OneButton button1(11, true); //key1OneButton button2(10, true); //key2// setup 函数void setup() {Serial.begin(9600); //设置串口波特率while (!Serial) {; // 等待串行端口连接。仅Leonardo需要,此处可以不用}Serial.println("Starting TwoButtons..."); //串口输出:Starting TwoButtons...// 注册按钮 1 的功能函数button1.attachClick(click1); //按键1单击button1.attachDoubleClick(doubleclick1); //按键1双击button1.attachLongPressStart(longPressStart1); //按键1长按开始button1.attachLongPressStop(longPressStop1); //按钮1长按停止button1.attachDuringLongPress(longPress1); //按钮1长按中。。。// 注册按钮 2 的功能函数button2.attachClick(click2);button2.attachDoubleClick(doubleclick2);button2.attachLongPressStart(longPressStart2);button2.attachLongPressStop(longPressStop2);button2.attachDuringLongPress(longPress2);} // setup// loop循环函数void loop() {// 按键执行函数,这个必须在loop中不断的检测button1.tick();button2.tick();// 你可以在此处实现其他代码,也可以稍等片刻delay(10);}// ----- 按键 1 的回调函数// 按下button1 1次(然后不按2.按钮)将调用此函数。void click1() {Serial.println("按键 1 单击");} // click1// 如果在短时间内两次按下button1,则将调用此函数。void doubleclick1() {Serial.println("按钮1双击。");} // doubleclick1// 长时间按下button1时,将调用一次此函数,长按开始void longPressStart1() {Serial.println("Button 1 longPress start");} // longPressStart1//长时间按下按钮1时,会周期性的调用此函数。void longPress1() {Serial.println("Button 1 longPress...");} // longPress1//长时间按下按钮1后松开时,此函数将被调用一次。长按停止void longPressStop1() {Serial.println("Button 1 longPress stop");} // longPressStop1// ----- 按键 2 的回调函数//按键2所有函数和按键1功能相同void click2() {Serial.println("Button 2 click.");} // click2void doubleclick2() {Serial.println("Button 2 doubleclick.");} // doubleclick2void longPressStart2() {Serial.println("Button 2 longPress start");} // longPressStart2void longPress2() {Serial.println("Button 2 longPress...");} // longPress2void longPressStop2() {Serial.println("Button 2 longPress stop");} // longPressStop2// End
以上是对示例程序TwoButtons程序的简要中文注释,下面对部分程序做必要解释。
#include "OneButton.h"// 设置按键引脚OneButton button1(11, true); //key1OneButton button2(10, true); //key2
第一行是引用了OneButton的库文件,第二第三行是对独立按键的硬件连接做设置,参数1是按键连接的实际用引脚,在以上例程中使用得是数字引脚11和10号;第二个参数(true or false),默认是true,表示按键按下是低电平有效,若按键按下是高电平,需要设置为false;此函数其实还有第三个参数(true or false),表示按键引脚的工作模式是“输入上拉”还是“输入”模式。默认为输入上拉模式(true),通常情况下这个参数可以不用修改。
// 注册按钮 1 的功能函数button1.attachClick(click1); //按键1单击button1.attachDoubleClick(doubleclick1); //按键1双击button1.attachLongPressStart(longPressStart1); //按键1长按开始button1.attachLongPressStop(longPressStop1); //按钮1长按停止button1.attachDuringLongPress(longPress1); //按钮1长按中。。。
在setup中注册的按键函数名称一定要和后续的按键回调函数的函数名一致。
// ----- 按键 1 的回调函数// 按下button1 1次(然后不按2.按钮)将调用此函数。void click1() {Serial.println("按键 1 单击");} // click1// 如果在短时间内两次按下button1,则将调用此函数。void doubleclick1() {Serial.println("按钮1双击。");} // doubleclick1// 长时间按下button1时,将调用一次此函数,长按开始void longPressStart1() {Serial.println("Button 1 longPress start");} // longPressStart1//长时间按下按钮1时,会周期性的调用此函数。void longPress1() {Serial.println("Button 1 longPress...");} // longPress1//长时间按下按钮1后松开时,此函数将被调用一次。长按停止void longPressStop1() {Serial.println("Button 1 longPress stop");} // longPressStop1
函数名需要和按键函数注册中的一致,不然无法调用到。这里的按键按下后,我们只是通过发送一条信息到串口监视器,在实际的按键使用中,通常在按键按下后都是需要有处理其他任务的,我们可以在按键按下的回调函数中对某个变量进行操作,再在loop中去判断变量的值,从而识别是哪个按键按下,做出相应的处理。下面就来完成一个简单的实例。
实例要求:创建一个变量,采用两个按键对变量进行加一和减一的操作。
#include "OneButton.h"// 设置按键引脚OneButton button1(11, true); //key1OneButton button2(10, true); //key2byte count_key=10;// setup 函数void setup() {Serial.begin(9600); //设置串口波特率// 注册按钮 1 的功能函数button1.attachClick(click1); //按键1单击button1.attachDoubleClick(doubleclick1); //按键1双击button1.attachLongPressStart(longPressStart1); //按键1长按开始button1.attachLongPressStop(longPressStop1); //按钮1长按停止button1.attachDuringLongPress(longPress1); //按钮1长按中。。。// 注册按钮 2 的功能函数button2.attachClick(click2);button2.attachDoubleClick(doubleclick2);button2.attachLongPressStart(longPressStart2);button2.attachLongPressStop(longPressStop2);button2.attachDuringLongPress(longPress2);} // setup// loop循环函数void loop() {// 按键执行函数,这个必须在loop中不断的检测button1.tick();button2.tick();// 你可以在此处实现其他代码,也可以稍等片刻delay(10);}// ----- 按键 1 的回调函数// 按下button1 1次(然后不按2.按钮)将调用此函数。void click1() {Serial.println("按键 1 单击");count_key++; //对变量加一Serial.println(count_key); //变量发送串口监视器} // click1// 如果在短时间内两次按下button1,则将调用此函数。void doubleclick1() {Serial.println("按钮1双击。");}// 长时间按下button1时,将调用一次此函数,长按开始void longPressStart1() {Serial.println("Button 1 longPress start");} // longPressStart1//长时间按下按钮1时,会周期性的调用此函数。void longPress1() {Serial.println("Button 1 longPress...");} // longPress1//长时间按下按钮1后松开时,此函数将被调用一次。长按停止void longPressStop1() {Serial.println("Button 1 longPress stop");} // longPressStop1// ----- 按键 2 的回调函数//按键2所有函数和按键1功能相同void click2() {Serial.println("Button 2 click.");count_key--; //对变量减一Serial.println(count_key);//变量发送串口监视器}void doubleclick2() {Serial.println("Button 2 doubleclick.");}void longPressStart2() {Serial.println("Button 2 longPress start");}void longPress2() {Serial.println("Button 2 longPress...");}void longPressStop2() {Serial.println("Button 2 longPress stop");}// End
因为以上实例任务简单,可以直接在按键回调函数中直接处理,如果按键任务比较复杂,需要占用时间长,那么可以在创建一个变量,在按键回调函数中只对这个变量进行赋值,比如加一按键赋值变量为1,减一按键变量赋值为2,这样赋值以后,在loop循环中在去判断是等于1还是等于2,如果等于1则去处理加一按键的任务。通过这样的处理,可以让按键回调函数变得简洁,并且不会占用按键的调用时间,提高按键的时效性。在复杂的任务中通常会采用这样的方式去处理按键,大家可以在自己的程序中进行尝试。
