zoukankan      html  css  js  c++  java
  • 单片机---多功能按键处理

    最近自己在琢磨按键程序,之前弄了,按键单击程序,程序可以实现读取按键的几个状态,然后根据需求使用。单击按键的几个状态如下:

    • 单击后,马上返回按键值
    • 单击后,释放之后,返回按键值
    • 单击后,按住不放,多次返回按键值

    但是在其上面扩展双击和三击以及多击程序时,遇到了麻烦(其实就是不会啦),于是在网上看了某个老师的经典按键程序,里面讲了单击和双击,拿着源程序理解了半天,终于一知半解了(一知半解的状态就是能读懂思想,但是闭卷完全自己写,写不出)。但是个人觉得其中的消抖部分还有按键释放的部分还可以改善,还有根据其思路扩展了三击以及N击,于是写了这篇博客供自己以后遗忘时参考以及跟大家分享。


    正文:

    此按键程序的实现的功能是单个独立按键的[单击],[长按],[双击],[三击]以及[多击]。本文分为三个部分,

    • 第一个部分是说[单击],[长按]的程序;
    • 第二部分是讲[双击]
    • 第三部分是讲[三击],[多击]

    一、[单击]、[长按]程序

    1. 简单介绍本按键程序的单击和长按

    首先说一下单击,长按的响应情况,就是按多久算单击或者长按,按下按键马上返回有效键值,还是释放之后返回有效键值等等,下面说下它在什么情况下返回有效的【单击】和【长按】。

    首先看一张时序图:

    注:

    T1:是单击的按键消抖时长,这里预设的是30ms,也可以根据需求自行定义;
    T2:是单击时,按键释放的有效时间段,提前或者超过这个时间段释放的按键都不再是单击了。提前释放则是无效键值,超过后释放则是长按。
    T3:是长按时长,按键超过此时长,则为长按。这里的预设值是3s,同样可根据需求自行更改。

    【单击】:按键按下超过消抖时长T1(30ms),并且在T2时间段内释放按键,按键一释放,马上返回有效按键值—【单击】。
    注意:单击是释放后,才返回有效按键值,不释放时,是无效按键值。

    【长按】:按键按下的时间超过预设的长按时长T3(3s) ,马上返回有效按键值—【长按】;
    注意:长按是只要按下的时间超过预设的长按时长,马上返回有效键值。但是,如果按键一直按着不释放,则只返回一次有效按键值,不重复返回,直到释放之后,才开始重新读取键值。

    2. 按键程序的架构

    按键程序可以分为四个部分,第一部分:判断有无按键按下;第二部分:按键是否有效(按键消抖);第三部分:确定有效按键的种类(单击还是长按);第四部分:等待按键释放。

    3. 按键程序的源代码以及注释

    程序的注释写的很详细,应该是可以读懂的,如果有疑问可以留言讨论。
    以下是key.c 的源代码:

    1. #define KEY_INPUT P1.0 //按键IO
    2. #define KEY_STATE_0 0 //按键状态
    3. #define KEY_STATE_1 1
    4. #define KEY_STATE_2 2
    5. #define KEY_STATE_3 3
    6. #define LONG_KEY_TIME 300 //LONG_KEY_TIME*10MS = 3S
    7. #define SINGLE_KEY_TIME 3 //SINGLE_KEY_TIME*10MS = 30MS
    8. #define KEY_NONE 0 //no click
    9. #define KEY_SHORT 1 //single click
    10. #define KEY_LONG 10 //long press
    11. //10MS
    12. void key_driver(void)
    13. {
    14. static char key_state; //按键状态变量
    15. static int key_time; //按键计时变量
    16. char key_press, key_return;
    17. key_return = KEY_NONE; // 清除 返回按键值
    18. key_press = KEY_INPUT; // 读取当前键值
    19. switch (key_state)
    20. {
    21. case KEY_STATE_0: // 按键状态0:判断有无按键按下
    22. if (!key_press) // 有按键按下
    23. {
    24. key_time = 0; // 清零时间间隔计数
    25. key_state = KEY_STATE_1; // 然后进入 按键状态1
    26. }
    27. break;
    28. case KEY_STATE_1: // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
    29. if (!key_press)
    30. {
    31. key_time++; // 一次10ms
    32. if (key_time >= SINGLE_KEY_TIME) // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
    33. {
    34. key_state = KEY_STATE_2; // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
    35. }
    36. }
    37. else
    38. key_state = KEY_STATE_0; // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
    39. break;
    40. case KEY_STATE_2: // 按键状态2:判定按键有效的种类:是单击,还是长按
    41. if (key_press) // 如果按键在 设定的长按时间 内释放,则判定为单击
    42. {
    43. key_return = KEY_SHORT; // 返回 有效按键值:单击
    44. key_state = KEY_STATE_0; // 返回 按键状态0,继续等待按键
    45. }
    46. else
    47. {
    48. key_time++;
    49. if (key_time >= LONG_KEY_TIME) // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按
    50. {
    51. key_return = KEY_LONG; // 返回 有效键值值:长按
    52. key_state = KEY_STATE_3; // 去状态3,等待按键释放
    53. }
    54. }
    55. break;
    56. case KEY_STATE_3: // 等待按键释放
    57. if (key_press)
    58. {
    59. key_state = KEY_STATE_0; // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
    60. }
    61. break;
    62. default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
    63. key_state = KEY_STATE_0;
    64. break;
    65. }
    66. return key_return; // 返回 按键值
    67. }

    使用注意:
    1)硬件:按键的一端接地(GND),另一端接IO口。IO为输入,一定要有上拉电阻。
    2)定时器:这里为了精确的定时,所以使用了定时器,定时器的时间是10ms。
    3)扫描周期:调用此函数时,一定确保”扫描周期“要小于10ms。不然按键内所涉及的时间就会不准,会偏大。所涉及的时间包括消抖时长,按键长按时长等。

    4. 按键程序的使用实例

    这里以C51位硬件平台进行实例讲解
    1)实例程序的功能:
    单击:点亮LED1
    长按:熄灭LED1
    2)硬件:
    按键IO:P1.0
    LED1 :P2.0
    以下是 main.c 源代码:

    1. #include "reg51.h"
    2. #include "key.c"
    3. sbit LED1 = P2.0; //定义LEDIO口
    4. unsigned char g_u8_KeyValue; //按键值
    5. unsigned char g_flag_10ms_key; //10ms 计时标志
    6. //timer0,初始化函数 ,定时时间为 10ms
    7. void T0_Init_10ms(void)
    8. {
    9. TMOD |= 0x01;
    10. TH0 = (65535 - 10000)/256;
    11. TL0 = (65535 - 10000)%256;
    12. ET0 = 1;
    13. TR0 = 1;
    14. EA = 1;
    15. }
    16. //主函数
    17. void main(void)
    18. {
    19. P1.0 = 1; //P1.0 拉高
    20. T0_Init_10ms(); //定时器0,初始化,定时10ms
    21. while(1)
    22. {
    23. if(g_flag_10ms_key) //等待10ms,定时完成
    24. {
    25. g_flag_10ms_key = 0; //清零10ms定时标志
    26. g_u8_KeyValue = key_driver(); //读取按键值
    27. switch(g_u8_KeyValue)
    28. {
    29. case S_Key: LED1 = 1; break; //单击 点亮LED1
    30. case L_Key: LED1 = 1; break; //长按 熄灭LED1
    31. }
    32. }
    33. }
    34. }
    35. //timer0 中断服务程序
    36. void IRQ_T0(void) interrupt 1
    37. {
    38. g_flag_10ms_key = 1; //置位 10ms 定时标志
    39. }

    二、 [双击]程序

    1.双击介绍

    双击的判定
    在完成第一次【单击】之后,在一定的时间间隔内(本程序使用的是300ms),接着完成第二次【单击】,及判定为【双击】。
    双击的响应
    1)在预设的时间间隔内完成第二次【单击】,按键释放后,响应返回有效键值【双击】。
    2)如果第二次按下键并一直按住,当按住的时间超过设定的时间间隔(300ms)后,会响应第一个【单击】,并返回有效键值【单击】。
    注:【单击】是包括按下和释放按键的过程,判定方式沿用上文所说的,如果忘了,可以参考上文。
    双击响应时序图

    注:
    T1:是单击判定的时间,范围:30ms < T1 < 3000ms
    T2:是判定双击的时间间隔,是个定值 300ms。在完成第一次【单击】后(释放按键后开始计时),在这个时间间隔内,如果再一次完成【单击】(释放按键后结束计时),则判定为【双击】。
    T3:与T1相同。

    2.按键程结构

    按键程序可以分为四个部分,第一部分:判断有无单击按键;第二部分:判断双击即是在预设的时间间隔内,有无第二次【单击】;第三部分:等待按键释放。

    3.双击程序的源代码以及注释

    程序的注释写的很详细,应该是可以读懂的,如果有疑问可以留言讨论。
    上文的【单击】函数作为这次【双击】程序的子函数
    以下是key.c 的源代码:

    1. #define KEY_INPUT P1.0 // 按键IO
    2. #define KEY_STATE_0 0 // 按键状态
    3. #define KEY_STATE_1 1
    4. #define KEY_STATE_2 2
    5. #define KEY_STATE_3 3
    6. #define SINGLE_KEY_TIME 3 // SINGLE_KEY_TIME*10MS = 30MS 判定单击的时间长度,软件消抖
    7. #define KEY_INTERVAL 30 // KEY_INTERVAL*10MS = 300MS 判定双击的时间间隔
    8. #define LONG_KEY_TIME 300 // LONG_KEY_TIME*10MS = 3S 判定长按的时间长度
    9. #define KEY_NONE 0 // no click
    10. #define KEY_SHORT 1 // single click
    11. #define KEY_DOUBLE 2 // double click
    12. #define KEY_LONG 10 // long press
    13. // ----------------------------------- key_driver --------------------------
    14. unsigned char key_driver(void)
    15. {
    16. static unsigned char key_state = 0;
    17. static unsigned int key_time = 0;
    18. unsigned char key_press, key_return;
    19. key_return = KEY_NONE; // 清除 返回按键值
    20. key_press = KEY_INPUT; // 读取当前键值
    21. switch (key_state)
    22. {
    23. case KEY_STATE_0: // 按键状态0:判断有无按键按下
    24. if (!key_press) // 有按键按下
    25. {
    26. key_time = 0; // 清零时间间隔计数
    27. key_state = KEY_STATE_1; // 然后进入 按键状态1
    28. }
    29. break;
    30. case KEY_STATE_1: // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
    31. if (!key_press)
    32. {
    33. key_time++; // 一次10ms
    34. if (key_time >= SINGLE_KEY_TIME) // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
    35. {
    36. key_state = KEY_STATE_2; // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
    37. }
    38. }
    39. else
    40. key_state = KEY_STATE_0; // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
    41. break;
    42. case KEY_STATE_2: // 按键状态2:判定按键有效的种类:是单击,还是长按
    43. if (key_press) // 如果按键在 设定的长按时间 内释放,则判定为单击
    44. {
    45. key_return = KEY_SHORT; // 返回 有效按键值:单击
    46. key_state = KEY_STATE_0; // 返回 按键状态0,继续等待按键
    47. }
    48. else
    49. {
    50. key_time++;
    51. if (key_time >= LONG_KEY_TIME) // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=300*10ms=3000ms), 则判定为 长按
    52. {
    53. key_return = KEY_LONG; // 返回 有效键值值:长按
    54. key_state = KEY_STATE_3; // 去状态3,等待按键释放
    55. }
    56. }
    57. break;
    58. case KEY_STATE_3: // 等待按键释放
    59. if (key_press)
    60. {
    61. key_state = KEY_STATE_0; // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
    62. }
    63. break;
    64. default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
    65. key_state = KEY_STATE_0;
    66. break;
    67. }
    68. return key_return; // 返回 按键值
    69. }
    70. // ----------------------------------- key_read --------------------------------
    71. void key_read(void)
    72. {
    73. static unsigned char key_state1 = 0, key_time1 = 0;
    74. unsigned char key_return, key_temp;
    75. key_return = KEY_NONE; // 清零 返回按键值
    76. key_temp = key_driver(); // 读取键值
    77. switch (key_state1)
    78. {
    79. case KEY_STATE_0: // 按键状态0:等待有效按键(通过 key_driver 返回的有效按键值)
    80. if (key_temp == KEY_SHORT) // 如果是[单击],不马上返回单击按键值,先进入 按键状态1,判断是否有[双击]的可能
    81. {
    82. key_time1 = 0; // 清零计时
    83. key_state1 = KEY_STATE_1;
    84. }
    85. else // 如果不是[单击],直接返回按键值。这里的按键值可能是:[长按],[无效按键]
    86. {
    87. key_return = key_temp; // 返回 按键值
    88. }
    89. break;
    90. case KEY_STATE_1: // 按键状态1:判定是否有[双击]
    91. if (key_temp == KEY_SHORT) // 有[单击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms) 内,再次有[单击],则为[双击],但是不马上返回 有效按键值为[双击],先进入 按键状态2,判断是否有[三击]
    92. {
    93. key_return = KEY_DOUBLE; // 返回 有效按键:[双击]
    94. key_state1 = KEY_STATE_0; // 返回 按键状态0,等待新的有效按键
    95. }
    96. else // 有[单击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms)内,没有[单击]出现,则判定为 [单击]
    97. {
    98. key_time1++; // 计数 时间间隔
    99. if (key_time1 >= KEY_INTERVAL) // 超过 时间间隔
    100. {
    101. key_return = KEY_SHORT; // 返回 有效按键:[单击]
    102. key_state1 = KEY_STATE_0; // 返回 按键状态0,等待新的有效按键
    103. }
    104. }
    105. break;
    106. default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
    107. key_state1 = KEY_STATE_0;
    108. break;
    109. }
    110. return key_return; // 返回 按键值
    111. }

    使用注意:

    1)硬件:按键的一端接地(GND),另一端接IO口。IO为输入,一定要有上拉电阻。
    2)定时器:这里为了精确的定时,所以使用了定时器,定时器的时间是10ms。
    3)扫描周期:调用此函数时,一定确保”扫描周期“要小于10ms。不然按键内所涉及的时间就会不准,会偏大。所涉及的时间包括消抖时长,按键长按时长等。
    扫描周期定义:从 第一次进入按键扫描程序 开始,到第二次进入按键扫描程序时 结束,之间所用的时间。
    测量扫描周期的方法:可以在按键扫描程序的第一句,添加IO口取反函数,然后用示波器查看改IO口,其IO口周期的一般就是扫描周期了。
    4)特别注意以上程序的3个关于时间的宏,相当的重要。如果想更改按键的单击的灵敏度,双击的速度,或者长按的时间,只需要修改这些宏的值即可。
    比如:针对于老人的使用的按键,就需要将双击的速度调节的慢一点,就可以将KEY_INTERVAL的值增大。
    SINGLE_KEY_TIME:单击的灵敏度,值越小,越灵敏。
    KEY_INTERVAL :双击的点击速度,修改这个值,值越小,速度越快。同时这个值也决定了单击的响应时间,因为单击之后,还需要判断在这个时间间隔内没有第二次单击,如果没有才是真正的单击,所以单击响应的时间为:SINGLE_KEY_TIME+KEY_INTERVAL;
    LONG_KEY_TIME :长按的时间,修改这个即可,值越大,时间越长。

    4.按键程序的使用实例

    这里以C51位硬件平台进行实例讲解
    1)实例程序的功能
    单击:点亮LED1
    双击:熄灭LED1
    长按:熄灭LED1
    2)硬件:
    按键IO:P1.0
    LED1 :P2.0
    以下是 main.c 源代码:

    1. // =========================== key.c ======================
    2. #include "reg51.h"
    3. #include "key.c"
    4. sbit LED1 = P2.0; // 定义LEDIO口
    5. unsigned char g_u8_KeyValue; // 按键值
    6. unsigned char g_flag_10ms_key; // 10ms 计时标志
    7. void key_read(); // 声明读取按键函数
    8. void T0_Init_10ms(void) // timer0,初始化函数 ,定时时间为 10ms
    9. {
    10. TMOD |= 0x01;
    11. TH0 = (65535 - 10000)/256;
    12. TL0 = (65535 - 10000)%256;
    13. ET0 = 1;
    14. TR0 = 1;
    15. EA = 1;
    16. }
    17. // 主函数
    18. void main(void)
    19. {
    20. P1.0 = 1; // P1.0 拉高
    21. T0_Init_10ms(); // 定时器0,初始化,定时10ms
    22. while(1)
    23. {
    24. if(g_flag_10ms_key) // 等待10ms,定时完成
    25. {
    26. g_flag_10ms_key = 0; // 清零10ms定时标志
    27. g_u8_KeyValue = key_read(); // 读取按键值
    28. switch(g_u8_KeyValue)
    29. {
    30. case S_Key: LED1 = 1; break; // 单击 点亮LED1
    31. case D_Key: LED1 = 0; break; // 单击 熄灭LED1
    32. case L_Key: LED1 = 0; break; // 长按 熄灭LED1
    33. }
    34. }
    35. }
    36. }
    37. // timer0 中断服务程序
    38. void IRQ_T0(void) interrupt 1
    39. {
    40. g_flag_10ms_key = 1; // 置位 10ms 定时标志
    41. }

    三、 [三击]程序

    1.三击介绍

    三击判定:在完成第一次【单击】之后,在一定的时间间隔内(本程序使用的是300ms),接着完成第二次【单击】,时间间隔重新计时,然后又在这个时间间隔内,完成第三次【单击】,及判定为【三击】。
    注:【单击】是包括按下和释放按键的过程,判定方式沿用上文所说的,如果忘了,可以参考上文。
    三击响应时序图

    注:
    T1:是单击判定的时间,范围:30ms < T1 < 3000ms。
    T2:是判定双击的时间间隔,是个定值 300ms。这个时间间隔的计算,是从第一次【单击】释放后开始计时,直到第二次【单击】释放按键后结束。在完成第一次【单击】后(释放按键后开始计时),在这个时间间隔内,如果再一次完成【单击】
    T3:是判定三击的时间间隔,双击之后,在这个时间内,再一次有【单击】,击判定为【三击】。其实质与T2一样。

    2.按键程序结果

    按键程序结构可以分为三个部分:
    第一部分:判断有无单击按键;
    第二部分:判断双击,即是在预设的时间间隔内,有无第二次【单击】;
    第三部分:判断三击,即是在【双击】后,在预设的时间间隔内,有无再一次的【单击】。

    3.三击程序的源代码以及注释

    程序的注释写的很详细,应该是可以读懂的,如果有疑问可以留言讨论。
    以下是key.c 的源代码:

    1. #define KEY_INPUT P1.0 // 按键IO
    2. #define KEY_STATE_0 0 // 按键状态
    3. #define KEY_STATE_1 1
    4. #define KEY_STATE_2 2
    5. #define KEY_STATE_3 3
    6. #define SINGLE_KEY_TIME 3 // SINGLE_KEY_TIME*10MS = 30MS 判定单击的时间长度,软件消抖
    7. #define KEY_INTERVAL 30 // KEY_INTERVAL*10MS = 300MS 判定双击的时间间隔
    8. #define LONG_KEY_TIME 300 // LONG_KEY_TIME*10MS = 3S 判定长按的时间长度
    9. #define N_KEY 0 // no click
    10. #define S_KEY 1 // single click
    11. #define D_KEY 2 // double click
    12. #define T_KEY 3 // Triple click
    13. #define L_KEY 10 // long press
    14. // ----------------------------------- key_driver --------------------------
    15. unsigned char key_driver(void)
    16. {
    17. static unsigned char key_state = 0;
    18. static unsigned int key_time = 0;
    19. unsigned char key_press, key_return;
    20. key_return = N_KEY; // 清除 返回按键值
    21. key_press = KEY_INPUT; // 读取当前键值
    22. switch (key_state)
    23. {
    24. case KEY_STATE_0: // 按键状态0:判断有无按键按下
    25. if (!key_press) // 有按键按下
    26. {
    27. key_time = 0; // 清零时间间隔计数
    28. key_state = KEY_STATE_1; // 然后进入 按键状态1
    29. }
    30. break;
    31. case KEY_STATE_1: // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
    32. if (!key_press)
    33. {
    34. key_time++; // 一次10ms
    35. if (key_time >= SINGLE_KEY_TIME) // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
    36. {
    37. key_state = KEY_STATE_2; // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
    38. }
    39. }
    40. else
    41. key_state = KEY_STATE_0; // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
    42. break;
    43. case KEY_STATE_2: // 按键状态2:判定按键有效的种类:是单击,还是长按
    44. if (key_press) // 如果按键在 设定的长按时间 内释放,则判定为单击
    45. {
    46. key_return = S_KEY; // 返回 有效按键值:单击
    47. key_state = KEY_STATE_0; // 返回 按键状态0,继续等待按键
    48. }
    49. else
    50. {
    51. key_time++;
    52. if (key_time >= LONG_KEY_TIME) // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=300*10ms=3000ms), 则判定为 长按
    53. {
    54. key_return = L_KEY; // 返回 有效键值值:长按
    55. key_state = KEY_STATE_3; // 去状态3,等待按键释放
    56. }
    57. }
    58. break;
    59. case KEY_STATE_3: // 等待按键释放
    60. if (key_press)
    61. {
    62. key_state = KEY_STATE_0; // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
    63. }
    64. break;
    65. default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
    66. key_state = KEY_STATE_0;
    67. break;
    68. }
    69. return key_return; // 返回 按键值
    70. }
    71. void key_read(void)
    72. {
    73. static unsigned char key_state1 = 0, key_time1 = 0;
    74. unsigned char key_return, key_temp;
    75. key_return = N_KEY; // 清零 返回按键值
    76. key_temp = key_driver(); // 读取键值
    77. switch (key_state1)
    78. {
    79. case KEY_STATE_0: // 按键状态0:等待有效按键(通过 key_driver 返回的有效按键值)
    80. if (key_temp == S_KEY) // 如果是[单击],不马上返回单击按键值,先进入 按键状态1,判断是否有[双击]的可能
    81. {
    82. key_time1 = 0; // 清零计时
    83. key_state1 = KEY_STATE_1;
    84. }
    85. else // 如果不是[单击],直接返回按键值。这里的按键值可能是:[长按],[无效按键]
    86. {
    87. key_return = key_temp; // 返回 按键值
    88. }
    89. break;
    90. case KEY_STATE_1: // 按键状态1:判定是否有[双击]
    91. if (key_temp == S_KEY) // 有[单击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms) 内,再次有[单击],则为[双击],但是不马上返回 有效按键值为[双击],先进入 按键状态2,判断是否有[三击]
    92. {
    93. key_time1 = 0; // 清零 时间间隔
    94. key_state1 = KEY_STATE_2; // 改变 按键状态值
    95. }
    96. else // 有[单击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms)内,没有[单击]出现,则判定为 [单击]
    97. {
    98. key_time1++; // 计数 时间间隔
    99. if (key_time1 >= KEY_INTERVAL) // 超过 时间间隔
    100. {
    101. key_return = S_KEY; // 返回 有效按键:[单击]
    102. key_state1 = KEY_STATE_0; // 返回 按键状态0,等待新的有效按键
    103. }
    104. }
    105. break;
    106. case KEY_STATE_2: // 按键状态2:判定是否有[三击]
    107. if (key_temp == S_KEY) // 有[双击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms) 内,再次有[单击],则为[三击],由于这里只扩展到[三击],所以马上返回 有效按键值为[三击]
    108. {
    109. key_return = T_KEY; // 返回 有效按键:[三击]
    110. key_state1 = KEY_STATE_0; // 返回 按键状态0,等待新的有效按键
    111. }
    112. else // 有[双击]后,如果在 设定的时间间隔(KEY_INTERVAL*10ms=30*10ms=300ms)内,没有[单击],则判定为 [双击]
    113. {
    114. key_time1++; // 计数 时间间隔
    115. if (key_time1 >= KEY_INTERVAL) // 超过 时间间隔
    116. {
    117. key_return = D_KEY; // 返回 有效按键:[双击]
    118. key_state1 = KEY_STATE_0; // 返回 按键状态0,等待新的有效按键
    119. }
    120. }
    121. break;
    122. default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
    123. key_state1 = KEY_STATE_0;
    124. break;
    125. }
    126. return key_return; // 返回 按键值
    127. }

    使用注意:

    1)硬件:按键的一端接地(GND),另一端接IO口。IO为输入,一定要有上拉电阻。
    2)定时器:这里为了精确的定时,所以使用了定时器,定时器的时间是10ms。
    3)扫描周期:调用此函数时,一定确保”扫描周期“要小于10ms。不然按键内所涉及的时间就会不准,会偏大。所涉及的时间包括消抖时长,按键长按时长等。
    扫描周期定义:从 第一次进入按键扫描程序 开始,到第二次进入按键扫描程序时 结束,之间所用的时间。
    测量扫描周期的方法:可以在按键扫描程序的第一句,添加IO口取反函数,然后用示波器查看改IO口,其IO口周期的一般就是扫描周期了。
    4)特别注意以上程序的3个关于时间的宏,相当的重要。如果想更改按键的单击的灵敏度,双击(三击)的速度,或者长按的时间,只需要修改这些宏的值即可。
    比如:针对于老人的使用的按键,就需要将双击的速度调节的慢一点,就可以将KEY_INTERVAL的值增大。

    SINGLE_KEY_TIME:单击的灵敏度,值越小,越灵敏。
    KEY_INTERVAL :双击的点击速度,修改这个值,值越小,速度越快。同时这个值也决定了单击的响应时间,因为单击之后,还需要判断在这个时间间隔内没有第二次单击,如果没有才是真正的单击,所以单击响应的时间为:SINGLE_KEY_TIME+KEY_INTERVAL;
    LONG_KEY_TIME :长按的时间,修改这个即可,值越大,时间越长。





  • 相关阅读:
    (转)jQuery.extend 函数详解
    (转)跟我一起学JQuery插件开发教程
    (转)jQuery插件开发全解析
    (转)弹出窗口lhgDialog API文档
    (转)反射发送实战(-)InvokeMember
    (转)JQuery处理json与ajax返回JSON实例
    linux下添加用户并赋予root权限
    Linux 下配置,安装Hadoop
    Linux 下安装 jdk-7u79-linux-x64.gz,jdk1.7.0_79,jdk1.7步骤:
    linux下导入、导出mysql数据库命令
  • 原文地址:https://www.cnblogs.com/mcumagic/p/5892995.html
Copyright © 2011-2022 走看看