查看: 1026|回复: 20
打印 上一主题 下一主题
收起左侧

[程序源码] 精妙的按键扫描函数,不采用延时消抖,实现长短按,创...

[复制链接]   已结帖(0)
     
2主题12帖子36积分
实习生 专家等级:结帖率:0%
跳转到指定楼层
楼主
 楼主| 发表于 2017-9-10 22:27 | 只看该作者 |返回版面|回帖奖励 |倒序浏览 |乐虎国际娱乐手机版模式
本按键实现移植机制云的stm32按键扫描,不过也有些不同。
不同点:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录
x
     
2主题12帖子36积分
实习生 专家等级:结帖率:0%
沙发
 楼主| 发表于 2017-9-10 22:28 | 只看该作者 |返回版面
在定时器中断中扫描,不用10ms延时,动态响应极好。实现长按短按。
创建对象极度方便。
用户只需要根据自己需要修改keyInit( )函数和下图中的变量即可。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录
x
     
2主题12帖子36积分
实习生 专家等级:结帖率:0%
板凳
 楼主| 发表于 2017-9-10 22:29 | 只看该作者 |返回版面
接下来是51的介绍.................................................


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录
x
     
2主题12帖子36积分
实习生 专家等级:结帖率:0%
地板
 楼主| 发表于 2017-9-10 22:30 | 只看该作者 |返回版面
上传.c文件。51附例程,32只有只有.c文件。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录
x
     
1468主题1万帖子4万积分
版主 专家等级:结帖率:96%打赏:500.91受赏:1151.53
5
发表于 2017-9-11 07:36 | 只看该作者 |返回版面
观摩下这个按键算法。
qq群: 嵌入式系统arm初学者 224636155←← +→→点击-->小 i 精品课全集,21ic公开课~~←←→→点击-->小 i 精品课全集,给你全方位的技能策划~~←←
20主题178帖子648积分
高级技术员 专家等级:结帖率:100%
6
发表于 2017-9-11 11:24 | 只看该作者 |返回版面
状态机法,都是这么处理的
     
45主题1144帖子3569积分
中级工程师 专家等级:结帖率:96%
7
发表于 2017-9-11 11:58 | 只看该作者 |返回版面
几年前做过C++的按键类,可创建多实例,线程计时,不用阻塞delay,长短按、消抖参数可独立设置,按下、弹起、click等多种事件支持
本人精通模拟电路、数字电路、射频电路、电源电路的焊接;
精通cadence allegro、altium designer、power pcb、visual studio等软件的安装与卸载;
精通windows、Linux、Mac、Android、IOS等系统的开关机。
     
0主题43帖子135积分
中级技术员 专家等级:结帖率:0%
8
发表于 2017-9-11 12:06 | 只看该作者 |返回版面
楼主  大家都是这么干的
     
2主题12帖子36积分
实习生 专家等级:结帖率:0%
9
 楼主| 发表于 2017-9-11 14:10 | 只看该作者 |返回版面
xouou_53320 发表于 2017-9-11 12:06
楼主  大家都是这么干的

高手是怎么干的。新手进阶高手可以看看。
     
11主题42帖子515积分
高级技术员 专家等级:结帖率:0%
10
发表于 2017-9-11 18:02 | 只看该作者 |返回版面
     
2主题12帖子36积分
实习生 专家等级:结帖率:0%
11
 楼主| 发表于 2017-9-11 18:41 | 只看该作者 |返回版面
batsong 发表于 2017-9-11 11:58
几年前做过C++的按键类,可创建多实例,线程计时,不用阻塞delay,长短按、消抖参数可独立设置,按下、弹起 ...

厉害了,我没学过C++
     
1主题140帖子433积分
资深技术员 专家等级:结帖率:100%
12
发表于 2017-9-11 20:33 | 只看该作者 |返回版面
按键扫描还用delay死等,是没真正做过项目的,,,
     
3主题62帖子188积分
中级技术员 专家等级:结帖率:66%
13
发表于 2017-9-12 10:18 | 只看该作者 |返回版面
看不懂,额额
     
553主题5767帖子1万积分
版主 专家等级:结帖率:72%打赏:3.00受赏:107.00
14
发表于 2017-9-13 13:06 | 只看该作者 |返回版面
乐鑫的也不错:
中断方式,回调函数。
  1. /*
  2. * ESPRESSIF MIT License
  3. *
  4. * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
  5. *
  6. * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
  7. * it is free of charge, to any person obtaining a copy of this software and associated
  8. * documentation files (the "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
  11. * to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all copies or
  14. * substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. *
  23. */

  24. #include "ets_sys.h"
  25. #include "os_type.h"
  26. #include "osapi.h"
  27. #include "mem.h"
  28. #include "gpio.h"
  29. #include "user_interface.h"

  30. #include "driver/key.h"

  31. LOCAL void key_intr_handler(void *arg);

  32. /******************************************************************************
  33. * FunctionName : key_init_single
  34. * Description  : init single key's gpio and register function
  35. * Parameters   : uint8 gpio_id - which gpio to use
  36. *                uint32 gpio_name - gpio mux name
  37. *                uint32 gpio_func - gpio function
  38. *                key_function long_press - long press function, needed to install
  39. *                key_function short_press - short press function, needed to install
  40. * Returns      : single_key_param - single key parameter, needed by key init
  41. *******************************************************************************/
  42. struct single_key_param *ICACHE_FLASH_ATTR
  43. key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press)
  44. {
  45.     struct single_key_param *single_key = (struct single_key_param *)os_zalloc(sizeof(struct single_key_param));
  46.        
  47.         //os_printf("+++ %s         single_key: 0x%x       gpio_id:%d   gpio_name:%d    gpio_func:%d     lone_press:0x%x      short_press : 0x%x \n",__FUNCTION__,single_key,gpio_id,gpio_name,gpio_func,long_press,short_press);

  48.     single_key->gpio_id = gpio_id;
  49.     single_key->gpio_name = gpio_name;
  50.     single_key->gpio_func = gpio_func;
  51.     single_key->long_press = long_press;
  52.     single_key->short_press = short_press;

  53.     return single_key;
  54. }

  55. /******************************************************************************
  56. * FunctionName : key_init
  57. * Description  : init keys
  58. * Parameters   : key_param *keys - keys parameter, which inited by key_init_single
  59. * Returns      : none
  60. *******************************************************************************/
  61. void ICACHE_FLASH_ATTR
  62. key_init(struct keys_param *keys)
  63. {
  64.     uint8 i;

  65.     ETS_GPIO_INTR_ATTACH(key_intr_handler, keys);

  66.     ETS_GPIO_INTR_DISABLE();

  67.         os_printf("+++ %s    key_num: %d \n",__FUNCTION__,keys->key_num);
  68.        
  69.     for (i = 0; i < keys->key_num; i++) {
  70.         keys->single_key[i]->key_level = 1;

  71.         PIN_FUNC_SELECT(keys->single_key[i]->gpio_name, keys->single_key[i]->gpio_func);

  72.         gpio_output_set(0, 0, 0, GPIO_ID_PIN(keys->single_key[i]->gpio_id));

  73.         gpio_register_set(GPIO_PIN_ADDR(keys->single_key[i]->gpio_id), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)
  74.                           | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE)
  75.                           | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));

  76.         //clear gpio14 status
  77.         GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(keys->single_key[i]->gpio_id));

  78.         //enable interrupt
  79.         gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE);
  80.     }

  81.     ETS_GPIO_INTR_ENABLE();
  82. }

  83. /******************************************************************************
  84. * FunctionName : key_5s_cb
  85. * Description  : long press 5s timer callback
  86. * Parameters   : single_key_param *single_key - single key parameter
  87. * Returns      : none
  88. *******************************************************************************/
  89. LOCAL void ICACHE_FLASH_ATTR
  90. key_5s_cb(struct single_key_param *single_key)
  91. {
  92.         os_printf("\n\n+++++++++++++++++      %s\n\n\n",__FUNCTION__);
  93.     os_timer_disarm(&single_key->key_5s);

  94.        

  95.     // low, then restart
  96.     if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
  97.         if (single_key->long_press) {
  98.             single_key->long_press();

  99.                         os_printf("\n\n+++++++++++++++++     0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))  %s\n\n\n",__FUNCTION__);
  100.         }
  101.     }
  102. }

  103. /******************************************************************************
  104. * FunctionName : key_50ms_cb
  105. * Description  : 50ms timer callback to check it's a real key push
  106. * Parameters   : single_key_param *single_key - single key parameter
  107. * Returns      : none
  108. *******************************************************************************/
  109. LOCAL void ICACHE_FLASH_ATTR
  110. key_50ms_cb(struct single_key_param *single_key)
  111. {
  112.         os_printf("\n\n+++++++++++++++++      %s\n\n\n",__FUNCTION__);
  113.     os_timer_disarm(&single_key->key_50ms);
  114.        
  115.     // high, then key is up
  116.     if (1 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
  117.         os_timer_disarm(&single_key->key_5s);
  118.         single_key->key_level = 1;
  119.         gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_NEGEDGE);

  120.         if (single_key->short_press) {
  121.             single_key->short_press();
  122.         }
  123.     } else {
  124.         gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_POSEDGE);
  125.     }
  126. }

  127. /******************************************************************************
  128. * FunctionName : key_intr_handler
  129. * Description  : key interrupt handler
  130. * Parameters   : key_param *keys - keys parameter, which inited by key_init_single
  131. * Returns      : none
  132. *******************************************************************************/
  133. LOCAL void
  134. key_intr_handler(void *arg)
  135. {
  136.     uint8 i;
  137.     uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
  138.     struct keys_param *keys = (struct keys_param *)arg;

  139.         //os_printf("+++++++++++++++++      %s      gpio_status:%d     key_num: %d\n",__FUNCTION__,gpio_status,keys->key_num);

  140.     for (i = 0; i < keys->key_num; i++) {
  141.                 //os_printf("+++++++++++++++++    gpio_status:%d      keys->single_key[%d]->gpio_id:%d     BIT(keys->single_key[ %d ]->gpio_id) : %d      \n",gpio_status,i,keys->single_key[i]->gpio_id,i,BIT(keys->single_key[i]->gpio_id));
  142.         if (gpio_status & BIT(keys->single_key[i]->gpio_id)) {
  143.                         //os_printf("+++++++++++++++++      i: %d    \n",i);


  144.             //disable interrupt
  145.             gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_DISABLE);

  146.             //clear interrupt status
  147.             GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(keys->single_key[i]->gpio_id));

  148.             if (keys->single_key[i]->key_level == 1) {
  149.                 // 5s, restart & enter softap mode
  150.                 os_timer_disarm(&keys->single_key[i]->key_5s);
  151.                 os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]);
  152.                 os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0);
  153.                 keys->single_key[i]->key_level = 0;
  154.                 gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE);
  155.             } else {
  156.                 // 50ms, check if this is a real key up
  157.                 os_timer_disarm(&keys->single_key[i]->key_50ms);
  158.                 os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]);
  159.                 os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0);
  160.             }


  161.         }

  162.     }

  163. }

复制代码
qq群:49734243
Email:zukeqiang@gmail.com
     
553主题5767帖子1万积分
版主 专家等级:结帖率:72%打赏:3.00受赏:107.00
15
发表于 2017-9-13 13:07 | 只看该作者 |返回版面
回调函数和初始化:

  1. void key_down50ms_func(void)
  2. {
  3.         os_printf("\n\n+++++++++++++++++      %s\n\n\n",__FUNCTION__);
  4.         os_printf("key down 50ms!\n");
  5. }

  6. void key_down5s_func(void)
  7. {
  8.         os_printf("+++++++++++++++++      %s\n",__FUNCTION__);
  9.         os_printf("start smartconfig............!\n");
  10.        
  11.         smartconfig_set_type(SC_TYPE_ESPTOUCH); //SC_TYPE_ESPTOUCH,SC_TYPE_AIRKISS,SC_TYPE_ESPTOUCH_AIRKISS
  12.         wifi_set_opmode(STATION_MODE);
  13.         smartconfig_start(smartconfig_done);
  14.        
  15. }

  16. struct keys_param key;
  17. struct single_key_param* single_key[1];


  18. void my_key_init(void)
  19. {
  20.         struct single_key_param *psingle_key;// = //&single_key[0];
  21.         psingle_key =
  22.                         key_init_single(GPIO_ID_PIN(2),PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2,key_down5s_func,key_down50ms_func);
  23.         key.key_num = 1;
  24.         //key.single_key = key_init_single(2,2,(key_function)NULL,(key_function)NULL,(key_function)NULL);
  25.         single_key[0] = psingle_key;
  26.         key.single_key = single_key;//&psingle_key;

  27.         key_init(&key);
  28. }
复制代码
qq群:49734243
Email:zukeqiang@gmail.com
     
16主题743帖子2251积分
版主 专家等级:结帖率:100%打赏:11.11受赏:41.50
16
发表于 2017-9-13 17:09 | 只看该作者 |返回版面
发一个马老师的:
//machao key
/*=============
低层按键(I/0)扫描函数,即低层按键设备驱动,只返回无键、短按和长按。具体双击不在此处判断。参考本人教材的例9-1,稍微有变化。教材中为连_发。
===============*/


unsigned char key_driver(void)
{
        static unsigned char key_state = key_state_0, key_time = 0;
        unsigned char key_press, key_return = N_key;
        key_press = GPIO_ReadInputDataBit(KEY1_BANK,KEY1_PIN);       // 读按键I/O电平
       
        switch (key_state) {
                case key_state_0:                              // 按键初始态
                        if (!key_press)
                                key_state = key_state_1;             // 键被按下,状态转换到按键消抖和确认状态
                                break;

                case key_state_1:                      // 按键消抖与确认态
                        if (!key_press) {
                                key_time = 0;                   //
                                key_state = key_state_2;          // 按键仍然处于按下,消抖完成,状态转换到按下键时间的计时状态,但返回的还是无键事件
                        } else
                                key_state = key_state_0;          // 按键已抬起,转换到按键初始态。此处完成和实现软件消抖,其实按键的按下和释放都在此消抖的。
                        break;

                case key_state_2:
                        if(key_press) {
                                key_return = S_key;        // 此时按键释放,说明是产生一次短操作,回送S_key
                                key_state = key_state_0;   // 转换到按键初始态
                        } else if (++key_time >= 100) {     // 继续按下,计时加10ms(10ms为本函数循环执行间隔)
                                key_return = L_key;        // 按下时间>1000ms,此按键为长按操作,返回长键事件
                                key_state = key_state_3;   // 转换到等待按键释放状态
                        }
                        break;

                case key_state_3:                 // 等待按键释放状态,此状态只返回无按键事件
                        if (key_press)
                                key_state = key_state_0;        //按键已释放,转换到按键初始态
                        break;
        }        
        return key_return;
}

/*=============
中间层按键处理函数,调用低层函数一次,处理双击事件的判断,返回上层正确的无键、单键、双键、长键4个按键事件。
本函数由上层循环调用,间隔10ms
===============*/

unsigned char key_read(void)
{
    static unsigned char key_m = key_state_0, key_time_1 = 0;
    unsigned char key_return = N_key,key_temp;
   
    key_temp = key_driver();
   
    switch(key_m) {
                case key_state_0:
                        if (key_temp == S_key ) {
                                key_time_1 = 0;               // 第1次单击,不返回,到下个状态判断后面是否出现双击
                                key_m = key_state_1;
                        } else
                                key_return = key_temp;        // 对于无键、长键,返回原事件
                        break;

                case key_state_1:
                        if (key_temp == S_key) {            // 又一次单击(间隔肯定<500ms)
                                key_return = D_key;           // 返回双击键事件,回初始状态
                                key_m = key_state_0;
                        }
                        else {                                  // 这里500ms内肯定读到的都是无键事件,因为长键>1000ms,在1s前低层返回的都是无键
                                if(++key_time_1 >= 50) {
                                        key_return = S_key;      // 500ms内没有再次出现单键事件,返回上一次的单键事件
                                        key_m = key_state_0;     // 返回初始状态
                                }
                        }
                        break;
    }
    return key_return;
}   
     
2主题43帖子129积分
中级技术员 专家等级:结帖率:0%
17
发表于 2017-9-13 20:36 | 只看该作者 |返回版面
恕我愚钝,真没看出来哪里精妙了?
     
2主题12帖子36积分
实习生 专家等级:结帖率:0%
18
 楼主| 发表于 2017-9-16 12:25 | 只看该作者 |返回版面
座机呀 发表于 2017-9-13 20:36
恕我愚钝,真没看出来哪里精妙了?

高手肯定觉得不咋地,适合初学者。
     
14主题110帖子371积分
资深技术员 专家等级:结帖率:66%
19
发表于 2017-11-23 09:11 | 只看该作者 |返回版面
本帖最后由 ailingg 于 2017-11-23 11:08 编辑

一个按键程序弄得的好繁琐,ram占用的也多。
我自己用的,弄个表格就好.
  1. /**
  2. *   按键程序
  3. *   PIC16单片机
  4. */




  5. #define KEY_QTY                  6


  6. #define KEY_DOWN                 1
  7. #define KEY_UP                   0
  8. #define TRUE                     1
  9. #define FALSE                    0


  10. // Key pins position,                         // PORTB : I I x x  x O O O
  11. #define KEY_READ_PINS_SET        0xc0         // Read pin : RB7 ~ RB6
  12. #define KEY_SCAN_PINS_SET        0x07         // Scan pin : RB2 ~ RB0 经过NPN反向后作为键盘的行扫描,所以判断是否有按键按下是将所有扫描引脚置高
  13. #define KEY_PORT                 PORTB


  14. /** 按键扫描变量 */
  15. typedef struct
  16. {
  17.     unsigned GetKey   :1;  
  18.     unsigned KeyState :1;
  19.    
  20.     UINT8    FiltCnt;
  21.     UINT8    LongCnt;
  22.     UINT8    PressTimes; //纪录按键进入的次数
  23.     UINT8    SetPoint;
  24.    
  25. }KeyVar_TypeDef;

  26. extern KeyVar_TypeDef KeyVar;




  27. typedef struct
  28. {
  29.     void (*IsKeyDownFunc)(void); // 按键事件函数
  30.     UINT8 KeyCode;               // 键值,由硬件决定
  31.     UINT8 LongTime;              // 长按键生效时间
  32.     UINT8 RenewTime;             // 长按键重新开始时间
  33.     UINT8 FiltTime;              // 去抖滤波时间   
  34.     UINT8 KeyID;
  35.    
  36. }KeyElem_TypeDef;

  37. extern KeyElem_TypeDef const KeyElem[KEY_QTY +1];


  38. // 按键元素表
  39. KeyElem_TypeDef const KeyElem[KEY_QTY + 1] = {
  40.     { EmptyFunc,       0   ,  0,    0,   4,  0 },
  41.     { StopKey,         0x81,  0,    0,   4,  1 },
  42.     { VacuumParamSet,  0x82,  0,    0,   4,  2 },
  43.     { SealingParamSet, 0x84,  0,    0,   4,  3 },
  44.     { DigitIncrease,   0x41,  100,  80,  4,  4 },
  45.     { DigitDecrease,   0x42,  100,  80,  4,  5 },
  46.     { HeatLevelSet,    0x44,  0,    0,   4,  6 }
  47. };


  48. KeyVar_TypeDef KeyVar;
  49. KeyMsg_TypeDef KeyMsg;





  50. /***********************************************************************************************************
  51. * [url=home.php?mod=space&uid=247401]@brief[/url]  空函数
  52. ************************************************************************************************************/
  53. void EmptyFunc(void)
  54. {
  55.     NOP();
  56. }
  57. /***********************************************************************************************************
  58. * [url=home.php?mod=space&uid=247401]@brief[/url]   获取按键参数元素
  59. * @retval  找到对应键则返回对应结构元素指针,否则返回空键结构元素指针
  60. ************************************************************************************************************/
  61. KeyElem_TypeDef const* get_KeyElem(UINT8 var)
  62. {
  63.     UINT8 i;
  64.     for( i = 0; i < ( KEY_QTY + 1 ); i++ )
  65.     {
  66.         if( var == KeyElem[i].KeyCode )
  67.         {
  68.             return( &KeyElem[i] );
  69.         }
  70.     }
  71.     return( &KeyElem[0] );
  72. }
  73. /***********************************************************************************************************
  74. * [url=home.php?mod=space&uid=247401]@brief[/url]  按键参数初始化
  75. ************************************************************************************************************/
  76. void Key_Init(void)
  77. {
  78.     KeyMode.bMode = 0; //0=直接加减方式,1=位选加减方式
  79.     KeyVar.GetKey = 0;
  80.     KeyVar.KeyState = KEY_UP;
  81.     KeyVar.FiltCnt = 0;
  82.     KeyVar.LongCnt = 0;
  83.     KeyVar.SetPoint = NO;
  84.     KeyVar.PressTimes = 0;
  85. }
  86. /**************************************************************************************************************
  87. * [url=home.php?mod=space&uid=247401]@brief[/url]  键盘扫描函数
  88. *         矩阵式扫描,RB7,RB6 为扫描读取口;RB2,RB1,RB0反向后作为键盘的行扫描。
  89. * [url=home.php?mod=space&uid=536309]@NOTE[/url]   RB2,RB1,RB0反向后也是数码管和 LED的位驱动口,因此键盘扫描前要先保存
  90. *         扫描端口的位值,扫描结束后还原。
  91. * @Param  *PORTx    键盘扫描所在端口
  92. * @retval KeyID
  93. **************************************************************************************************************/
  94. UINT8 KeyScan( PORT_TypeDef *PORTx )
  95. {
  96.     UINT8 retval, i;
  97.     UINT8 PortKeep;
  98.     UINT8 KeyPortVal;
  99.     UINT8 MultiKeyCnt = 0;
  100.     KeyElem_TypeDef const *pKeyElem;
  101.    
  102.     HC595_OEN_Pin = 1;                         // Disable 74HC595 out,RA2
  103.     PortKeep = *PORTx;                          // Save Port Value , PORTB
  104.     *PORTx |= KEY_SCAN_PINS_SET;               // 使能所有扫描引脚;RB2 ~ RB0通过UNL2003反向后作为键盘的行扫描,所以所有扫描引脚置高电平
  105.     pKeyElem = &KeyElem[0];
  106.     retval = KeyElem->KeyID;
  107.     if( ( *PORTx & KEY_READ_PINS_SET  ) == KEY_READ_PINS_SET ) //判断按键释放
  108.     {
  109.         if( KeyVar.FiltCnt == 0 )
  110.         {
  111.             KeyVar.FiltCnt = 0;
  112.             KeyVar.LongCnt = 0;
  113.             KeyVar.GetKey = FALSE;
  114.             KeyVar.KeyState = KEY_UP;
  115.         }
  116.         else
  117.             KeyVar.FiltCnt--;
  118.     }
  119.     else
  120.     {
  121.         for( i = 0; i < KEY_SCAN_PINS_COUNT; i++ )
  122.         {
  123.             *PORTx &= ~KEY_SCAN_PINS_SET; // 扫描端口全禁止
  124.             NOP( );
  125.             NOP( );
  126.             *PORTx |= 1 << i;
  127.             NOP( );
  128.             NOP( );
  129.             if( ( *PORTx & KEY_READ_PINS_SET  ) != KEY_READ_PINS_SET )
  130.             {
  131.                 KeyPortVal = *PORTx & ( KEY_READ_PINS_SET | KEY_SCAN_PINS_SET ); // *PORTx & 0xc7
  132.                 continue;
  133.             }
  134.         }
  135.         if( ++KeyVar.FiltCnt > pKeyElem->FiltTime )            
  136.         {
  137.             KeyVar.FiltCnt = pKeyElem->FiltTime;
  138.             KeyVar.KeyState = KEY_DOWN;
  139.             
  140.             pKeyElem = get_KeyElem( KeyPortVal );
  141.             
  142.             if( pKeyElem->LongTime > 0 )
  143.             {
  144.                 if( ++KeyVar.LongCnt == pKeyElem->LongTime )
  145.                 {
  146.                     KeyVar.LongCnt = pKeyElem->RenewTime;      // 长按键重新开始计时值,按键重新生效的的时间间隔等于长按生效时间减去重新开始时间
  147.                     retval = pKeyElem->KeyID;                  // 返回对应键值的按键 ID
  148.                 }                                 
  149.             }
  150.             if( KeyVar.GetKey == FALSE )
  151.             {
  152.                 KeyVar.GetKey = TRUE;
  153.                 retval =  pKeyElem->KeyID;
  154.             }            
  155.         }
  156.     }
  157.     *PORTx = PortKeep; // 还原端口值,因按键扫描引脚与数显引脚共用
  158.     HC595_OEN_Pin = 0; // 允许 74595 三态输出口输出
  159.     return retval;
  160. }

  161. /********************************************************************************************
  162. * [url=home.php?mod=space&uid=247401]@brief[/url]  按键事件函数回调
  163. *
  164. ********************************************************************************************/
  165. void KeyEventFunc( void )
  166. {
  167.     UINT8 FuncID;
  168.     KeyElem_TypeDef const *pFunc;
  169.    
  170.     FuncID = KeyScan( &KEY_PORT );
  171.     pFunc = &KeyElem[FuncID];
  172.     pFunc->IsKeyDownFunc();
  173. }
复制代码



  

     
     
23主题474帖子1433积分
版主 专家等级:结帖率:0%
20
发表于 2017-11-23 09:19 | 只看该作者 |返回版面
不错,机智云那个按键写的真的很棒,上次做项目研究了他们的代码,有好多地方需要学习。
*滑动验证:
您需要登录后才可以回帖 登录 | 注册 手机登录
本版积分规则
关闭

热门推荐上一条 /2 下一条

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