在我们的电子时钟设计里,通常会用到2-3个地理按键来完成对时间等其他信息的设置,在《Arduino入门教程》中我们已经详细讲解了独立按键模块的使用。在教程中我们是通过分析独立按键的电路,再到按键产出的信号,最终我们自己通过程序方式来获取到按键的信号,从而判断独立按键是否按下,最终实现了按键模块的使用。其实在Arduino强大的开源库中已经有一个库文件,可以很方便的实现独立按键的一次按下(单击),两次快速按下(双击)以及长按(长时间按下)等的按键检测了。使用这个库我们可以快速的完成按键的检测,快速的实现我们的任务功能,这个库文件就是“OneButton”库。可以直接在Arduino IDE的库管理中直接搜索,搜索结果只有一个,直接下载既可以。也可通过下方连接直接下载。
    OneButton.zip
    在OneButton库中有多个示例文件,大家可以自行查看,因为我们的电子使用需要使用3个独立按键,在示例程序中有个“TwoButton”的示例,其中有两个按键检测的程序,我就以此为例作简要说明。因为例程中所有注释都为英文,为方便大家查看,在此做了简单的中文化注释。

    1. /*
    2. This is a sample sketch to show how to use the OneButtonLibrary
    3. to detect click events on 2 buttons in parallel.
    4. The library internals are explained at
    5. http://www.mathertel.de/Arduino/OneButtonLibrary.aspx
    6. Setup a test circuit:
    7. * Connect a pushbutton to pin A1 (ButtonPin) and ground.
    8. * Connect a pushbutton to pin A2 (ButtonPin) and ground.
    9. * The Serial interface is used for output the detected button events.
    10. The Sketch shows how to setup the library and bind 2 buttons to their functions.
    11. In the loop function the button1.tick and button2.tick functions have to be called as often as you like.
    12. */
    13. // 01.03.2014 created by Matthias Hertel
    14. // ... and working.
    15. /* 一个输出示例:
    16. Starting TwoButtons... //按键按下后的输出明细
    17. Button 1 click. //按键 1 单击
    18. Button 2 click. //按键 2 单击
    19. Button 1 doubleclick. //按键 1 双击
    20. Button 2 doubleclick. //按键 2 双击
    21. Button 1 longPress start //按键 1 长按开始
    22. Button 1 longPress... //按键 1 长按。。。
    23. Button 1 longPress...
    24. Button 1 longPress...
    25. Button 1 longPress stop //按键 1 长按结束
    26. Button 2 longPress start //按键 2 长按开始
    27. Button 2 longPress... //按键 1 长按。。。
    28. Button 2 longPress...
    29. Button 2 longPress stop //按键 1 长按结束
    30. */
    31. #include "OneButton.h"
    32. // 设置按键引脚
    33. OneButton button1(11, true); //key1
    34. OneButton button2(10, true); //key2
    35. // setup 函数
    36. void setup() {
    37. Serial.begin(9600); //设置串口波特率
    38. while (!Serial) {
    39. ; // 等待串行端口连接。仅Leonardo需要,此处可以不用
    40. }
    41. Serial.println("Starting TwoButtons..."); //串口输出:Starting TwoButtons...
    42. // 注册按钮 1 的功能函数
    43. button1.attachClick(click1); //按键1单击
    44. button1.attachDoubleClick(doubleclick1); //按键1双击
    45. button1.attachLongPressStart(longPressStart1); //按键1长按开始
    46. button1.attachLongPressStop(longPressStop1); //按钮1长按停止
    47. button1.attachDuringLongPress(longPress1); //按钮1长按中。。。
    48. // 注册按钮 2 的功能函数
    49. button2.attachClick(click2);
    50. button2.attachDoubleClick(doubleclick2);
    51. button2.attachLongPressStart(longPressStart2);
    52. button2.attachLongPressStop(longPressStop2);
    53. button2.attachDuringLongPress(longPress2);
    54. } // setup
    55. // loop循环函数
    56. void loop() {
    57. // 按键执行函数,这个必须在loop中不断的检测
    58. button1.tick();
    59. button2.tick();
    60. // 你可以在此处实现其他代码,也可以稍等片刻
    61. delay(10);
    62. }
    63. // ----- 按键 1 的回调函数
    64. // 按下button1 1次(然后不按2.按钮)将调用此函数。
    65. void click1() {
    66. Serial.println("按键 1 单击");
    67. } // click1
    68. // 如果在短时间内两次按下button1,则将调用此函数。
    69. void doubleclick1() {
    70. Serial.println("按钮1双击。");
    71. } // doubleclick1
    72. // 长时间按下button1时,将调用一次此函数,长按开始
    73. void longPressStart1() {
    74. Serial.println("Button 1 longPress start");
    75. } // longPressStart1
    76. //长时间按下按钮1时,会周期性的调用此函数。
    77. void longPress1() {
    78. Serial.println("Button 1 longPress...");
    79. } // longPress1
    80. //长时间按下按钮1后松开时,此函数将被调用一次。长按停止
    81. void longPressStop1() {
    82. Serial.println("Button 1 longPress stop");
    83. } // longPressStop1
    84. // ----- 按键 2 的回调函数
    85. //按键2所有函数和按键1功能相同
    86. void click2() {
    87. Serial.println("Button 2 click.");
    88. } // click2
    89. void doubleclick2() {
    90. Serial.println("Button 2 doubleclick.");
    91. } // doubleclick2
    92. void longPressStart2() {
    93. Serial.println("Button 2 longPress start");
    94. } // longPressStart2
    95. void longPress2() {
    96. Serial.println("Button 2 longPress...");
    97. } // longPress2
    98. void longPressStop2() {
    99. Serial.println("Button 2 longPress stop");
    100. } // longPressStop2
    101. // End

    以上是对示例程序TwoButtons程序的简要中文注释,下面对部分程序做必要解释。

    1. #include "OneButton.h"
    2. // 设置按键引脚
    3. OneButton button1(11, true); //key1
    4. OneButton button2(10, true); //key2

    第一行是引用了OneButton的库文件,第二第三行是对独立按键的硬件连接做设置,参数1是按键连接的实际用引脚,在以上例程中使用得是数字引脚11和10号;第二个参数(true or false),默认是true,表示按键按下是低电平有效,若按键按下是高电平,需要设置为false;此函数其实还有第三个参数(true or false),表示按键引脚的工作模式是“输入上拉”还是“输入”模式。默认为输入上拉模式(true),通常情况下这个参数可以不用修改。

    1. // 注册按钮 1 的功能函数
    2. button1.attachClick(click1); //按键1单击
    3. button1.attachDoubleClick(doubleclick1); //按键1双击
    4. button1.attachLongPressStart(longPressStart1); //按键1长按开始
    5. button1.attachLongPressStop(longPressStop1); //按钮1长按停止
    6. button1.attachDuringLongPress(longPress1); //按钮1长按中。。。

    在setup中注册的按键函数名称一定要和后续的按键回调函数的函数名一致。

    1. // ----- 按键 1 的回调函数
    2. // 按下button1 1次(然后不按2.按钮)将调用此函数。
    3. void click1() {
    4. Serial.println("按键 1 单击");
    5. } // click1
    6. // 如果在短时间内两次按下button1,则将调用此函数。
    7. void doubleclick1() {
    8. Serial.println("按钮1双击。");
    9. } // doubleclick1
    10. // 长时间按下button1时,将调用一次此函数,长按开始
    11. void longPressStart1() {
    12. Serial.println("Button 1 longPress start");
    13. } // longPressStart1
    14. //长时间按下按钮1时,会周期性的调用此函数。
    15. void longPress1() {
    16. Serial.println("Button 1 longPress...");
    17. } // longPress1
    18. //长时间按下按钮1后松开时,此函数将被调用一次。长按停止
    19. void longPressStop1() {
    20. Serial.println("Button 1 longPress stop");
    21. } // longPressStop1

    函数名需要和按键函数注册中的一致,不然无法调用到。这里的按键按下后,我们只是通过发送一条信息到串口监视器,在实际的按键使用中,通常在按键按下后都是需要有处理其他任务的,我们可以在按键按下的回调函数中对某个变量进行操作,再在loop中去判断变量的值,从而识别是哪个按键按下,做出相应的处理。下面就来完成一个简单的实例。
    实例要求:创建一个变量,采用两个按键对变量进行加一和减一的操作。

    1. #include "OneButton.h"
    2. // 设置按键引脚
    3. OneButton button1(11, true); //key1
    4. OneButton button2(10, true); //key2
    5. byte count_key=10;
    6. // setup 函数
    7. void setup() {
    8. Serial.begin(9600); //设置串口波特率
    9. // 注册按钮 1 的功能函数
    10. button1.attachClick(click1); //按键1单击
    11. button1.attachDoubleClick(doubleclick1); //按键1双击
    12. button1.attachLongPressStart(longPressStart1); //按键1长按开始
    13. button1.attachLongPressStop(longPressStop1); //按钮1长按停止
    14. button1.attachDuringLongPress(longPress1); //按钮1长按中。。。
    15. // 注册按钮 2 的功能函数
    16. button2.attachClick(click2);
    17. button2.attachDoubleClick(doubleclick2);
    18. button2.attachLongPressStart(longPressStart2);
    19. button2.attachLongPressStop(longPressStop2);
    20. button2.attachDuringLongPress(longPress2);
    21. } // setup
    22. // loop循环函数
    23. void loop() {
    24. // 按键执行函数,这个必须在loop中不断的检测
    25. button1.tick();
    26. button2.tick();
    27. // 你可以在此处实现其他代码,也可以稍等片刻
    28. delay(10);
    29. }
    30. // ----- 按键 1 的回调函数
    31. // 按下button1 1次(然后不按2.按钮)将调用此函数。
    32. void click1() {
    33. Serial.println("按键 1 单击");
    34. count_key++; //对变量加一
    35. Serial.println(count_key); //变量发送串口监视器
    36. } // click1
    37. // 如果在短时间内两次按下button1,则将调用此函数。
    38. void doubleclick1() {
    39. Serial.println("按钮1双击。");
    40. }
    41. // 长时间按下button1时,将调用一次此函数,长按开始
    42. void longPressStart1() {
    43. Serial.println("Button 1 longPress start");
    44. } // longPressStart1
    45. //长时间按下按钮1时,会周期性的调用此函数。
    46. void longPress1() {
    47. Serial.println("Button 1 longPress...");
    48. } // longPress1
    49. //长时间按下按钮1后松开时,此函数将被调用一次。长按停止
    50. void longPressStop1() {
    51. Serial.println("Button 1 longPress stop");
    52. } // longPressStop1
    53. // ----- 按键 2 的回调函数
    54. //按键2所有函数和按键1功能相同
    55. void click2() {
    56. Serial.println("Button 2 click.");
    57. count_key--; //对变量减一
    58. Serial.println(count_key);//变量发送串口监视器
    59. }
    60. void doubleclick2() {
    61. Serial.println("Button 2 doubleclick.");
    62. }
    63. void longPressStart2() {
    64. Serial.println("Button 2 longPress start");
    65. }
    66. void longPress2() {
    67. Serial.println("Button 2 longPress...");
    68. }
    69. void longPressStop2() {
    70. Serial.println("Button 2 longPress stop");
    71. }
    72. // End

    因为以上实例任务简单,可以直接在按键回调函数中直接处理,如果按键任务比较复杂,需要占用时间长,那么可以在创建一个变量,在按键回调函数中只对这个变量进行赋值,比如加一按键赋值变量为1,减一按键变量赋值为2,这样赋值以后,在loop循环中在去判断是等于1还是等于2,如果等于1则去处理加一按键的任务。通过这样的处理,可以让按键回调函数变得简洁,并且不会占用按键的调用时间,提高按键的时效性。在复杂的任务中通常会采用这样的方式去处理按键,大家可以在自己的程序中进行尝试。