单片机按键FIFO

[复制链接]
 楼主| 余三水 发表于 2020-5-31 16:18 | 显示全部楼层 |阅读模式
一般的单片机系统,按键作为人机交互工具是必不可少的,但是普通的按键需要消抖处理,极大的增加了程序开销,降低系统实时性。

安富莱的FIFO按键,无需延时处理消抖,可以记录按键按下、弹起、长按、组合按,并且移植起来也十分方便。之前在做一个项目时,用到一个矩阵键盘,移植了这个按键FIFO程序,用起来效果很不错。
967465ed3685866b03.png
主要流程就是开启一个10ms的定时器中断,在中断中扫描按键状态,并对按键状态进行分析消抖处理,如果按键动作,将按键动作压入FIFO中,在主循环中读取FIFO,获取按键状态。


 楼主| 余三水 发表于 2020-5-31 16:19 | 显示全部楼层
使用时首先要调用初始化函数,此函数有两个子函数,分别完成变量初始化和板子硬件初始化。
  1. /*
  2. *********************************************************************************************************
  3. *        函 数 名: bsp_InitKey
  4. *        功能说明: 初始化按键. 该函数被 bsp_Init() 调用。
  5. *        形    参:  无
  6. *        返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_InitKey(void)
  10. {
  11.         bsp_InitKeyVar();                /* 初始化按键变量 */
  12.         bsp_InitKeyHard();                /* 初始化按键硬件 */
  13. }
复制代码


 楼主| 余三水 发表于 2020-5-31 16:20 | 显示全部楼层
移植时需要注意对应IO硬件初始化修改成自己的,这里使用的STC8A单片机,3*4矩阵键盘,使用的IO通过宏定义封装起来。
857785ed368d37d26a.png
 楼主| 余三水 发表于 2020-5-31 16:22 | 显示全部楼层
  1. /* 矩阵键盘 */
  2. #define C1_PIN             1
  3. #define C1_GPIO_PORT       2

  4. #define C2_PIN             2
  5. #define C2_GPIO_PORT       2

  6. #define C3_PIN             3
  7. #define C3_GPIO_PORT       2

  8. #define C4_PIN             4
  9. #define C4_GPIO_PORT       2


  10. // Row1, Row2, Row3, Row4
  11. #define R1_PIN             1
  12. #define R1_GPIO_PORT       4

  13. #define R2_PIN             0
  14. #define R2_GPIO_PORT       2

  15. #define R3_PIN             2
  16. #define R3_GPIO_PORT       4


  17. /*
  18. *********************************************************************************************************
  19. *        函 数 名: bsp_InitKeyHard
  20. *        功能说明: 配置按键对应的GPIO
  21. *        形    参:  无
  22. *        返 回 值: 无
  23. *********************************************************************************************************
  24. */
  25. static void bsp_InitKeyHard(void)
  26. {
  27.         //KEY 初始化
  28.     PIN_InitPushPull(C1_GPIO_PORT, C1_PIN);
  29.         PIN_InitPushPull(C2_GPIO_PORT, C2_PIN);
  30.         PIN_InitPushPull(C3_GPIO_PORT, C3_PIN);
  31.         PIN_InitPushPull(C4_GPIO_PORT, C4_PIN);
  32.         PIN_InitOpenDrain(R1_GPIO_PORT, R1_PIN);
  33.         PIN_InitOpenDrain(R2_GPIO_PORT, R2_PIN);
  34.         PIN_InitOpenDrain(R3_GPIO_PORT, R3_PIN);
  35.        
  36. }
复制代码
 楼主| 余三水 发表于 2020-5-31 16:23 | 显示全部楼层
按键参数初始化需要注意设置连发速度来确定对应按键是否支持连按。还要自行修改判断按键按下函数和按键个数
  1. /*
  2.         按键滤波时间50ms, 单位10ms。
  3.         只有连续检测到50ms状态不变才认为有效,包括弹起和按下两种事件
  4.         即使按键电路不做硬件滤波,该滤波机制也可以保证可靠地检测到按键事件
  5. */
  6. #define KEY_FILTER_TIME   5
  7. #define KEY_LONG_TIME     100                             /* 单位10ms, 持续1秒,认为长按事件 */
  8. #define KEY_COUNT    13                                                   /* 按键个数, 12个独立建 + 1 个组合键 */
  9. static KEY_T xdata s_tBtn[KEY_COUNT];
  10. static KEY_FIFO_T xdata s_tKey;                /* 按键FIFO变量,结构体 */

  11. /* 检测按键按下函数 */
  12. static uint8_t IsKeyDown0(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 0; if (P(R2_GPIO_PORT, R2_PIN) == 0) return 1;else return 0;}
  13. static uint8_t IsKeyDown1(void)  {P(C1_GPIO_PORT, C1_PIN) = 0;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; NOP(50); if (P(R1_GPIO_PORT, R1_PIN) == 0) return 1;else return 0;}
  14. static uint8_t IsKeyDown2(void)  {P(C1_GPIO_PORT, C1_PIN) = 0;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R2_GPIO_PORT, R2_PIN) == 0) return 1;else return 0;}
  15. static uint8_t IsKeyDown3(void)  {P(C1_GPIO_PORT, C1_PIN) = 0;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R3_GPIO_PORT, R3_PIN) == 0) return 1;else return 0;}
  16. static uint8_t IsKeyDown4(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 0;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R1_GPIO_PORT, R1_PIN) == 0) return 1;else return 0;}
  17. static uint8_t IsKeyDown5(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 0;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R2_GPIO_PORT, R2_PIN) == 0) return 1;else return 0;}
  18. static uint8_t IsKeyDown6(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 0;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R3_GPIO_PORT, R3_PIN) == 0) return 1;else return 0;}
  19. static uint8_t IsKeyDown7(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 0; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R1_GPIO_PORT, R1_PIN) == 0) return 1;else return 0;}
  20. static uint8_t IsKeyDown8(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 0; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R2_GPIO_PORT, R2_PIN) == 0) return 1;else return 0;}
  21. static uint8_t IsKeyDown9(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 0; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R3_GPIO_PORT, R3_PIN) == 0) return 1;else return 0;}
  22. static uint8_t IsKeyDown10(void) {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 0; NOP(50); if (P(R1_GPIO_PORT, R1_PIN) == 0) return 1;else return 0;}
  23. static uint8_t IsKeyDown11(void) {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 0; if (P(R3_GPIO_PORT, R3_PIN) == 0) return 1;else return 0;}

  24. /* 组合按键 key1 && key2 */
  25. static uint8_t IsKeyDown12(void)  { return IsKeyDown1() && IsKeyDown2();}
  26. /*
  27. *********************************************************************************************************
  28. *        函 数 名: bsp_InitKeyVar
  29. *        功能说明: 初始化按键变量
  30. *        形    参:  无
  31. *        返 回 值: 无
  32. *********************************************************************************************************
  33. */
  34. static void bsp_InitKeyVar(void)
  35. {
  36.         uint8_t xdata i;

  37.         /* 对按键FIFO读写指针清零 */
  38.         fifo_init(&s_tKey);
  39.        
  40.         /* 给每个按键结构体成员变量赋一组缺省值 */
  41.         for (i = 0; i < KEY_COUNT; i++)
  42.         {
  43.                 s_tBtn[i].LongTime = KEY_LONG_TIME;                        /* 长按时间 0 表示不检测长按键事件 */
  44.                 s_tBtn[i].Count = KEY_FILTER_TIME / 2;                /* 计数器设置为滤波时间的一半 */
  45.                 s_tBtn[i].State = 0;                                                        /* 按键缺省状态,0为未按下 */
  46.                 //s_tBtn[i].KeyCodeDown = 3 * i + 1;                                /* 按键按下的键值代码 */
  47.                 //s_tBtn[i].KeyCodeUp   = 3 * i + 2;                                /* 按键弹起的键值代码 */
  48.                 //s_tBtn[i].KeyCodeLong = 3 * i + 3;                                /* 按键被持续按下的键值代码 */
  49.                 s_tBtn[i].RepeatSpeed = 0;                                                /* 按键连发的速度,0表示不支持连发 */
  50.                 s_tBtn[i].RepeatCount = 0;                                                /* 连发计数器 */
  51.         }


  52.         /* 判断按键按下的函数 */
  53.         s_tBtn[0].IsKeyDownFunc = IsKeyDown0;
  54.         s_tBtn[1].IsKeyDownFunc = IsKeyDown1;
  55.         s_tBtn[2].IsKeyDownFunc = IsKeyDown2;
  56.         s_tBtn[3].IsKeyDownFunc = IsKeyDown3;
  57.         s_tBtn[4].IsKeyDownFunc = IsKeyDown4;
  58.         s_tBtn[5].IsKeyDownFunc = IsKeyDown5;
  59.         s_tBtn[6].IsKeyDownFunc = IsKeyDown6;
  60.         s_tBtn[7].IsKeyDownFunc = IsKeyDown7;
  61.         s_tBtn[8].IsKeyDownFunc = IsKeyDown8;
  62.         s_tBtn[9].IsKeyDownFunc = IsKeyDown9;
  63.         s_tBtn[10].IsKeyDownFunc = IsKeyDown10;
  64.         s_tBtn[11].IsKeyDownFunc = IsKeyDown11;
  65.        
  66.         /* 组合按键 */
  67.         s_tBtn[12].IsKeyDownFunc = IsKeyDown12;
  68. }
复制代码
 楼主| 余三水 发表于 2020-5-31 16:24 | 显示全部楼层
按键扫描函数,需要开启一个10ms的定时器中断,在中断中对按键状态进行扫描。
  1. /*
  2. *********************************************************************************************************
  3. *        函 数 名: bsp_DetectKey
  4. *        功能说明: 检测一个按键。非阻塞状态,必须被周期性的调用。
  5. *        形    参:  按键结构变量指针
  6. *        返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void bsp_DetectKey(uint8_t i)
  10. {
  11.         KEY_T xdata *pBtn;

  12.         /*
  13.                 如果没有初始化按键函数,则报错
  14.                 if (s_tBtn[i].IsKeyDownFunc == 0)
  15.                 {
  16.                         printf("Fault : DetectButton(), s_tBtn[i].IsKeyDownFunc undefine");
  17.                 }
  18.         */

  19.         pBtn = &s_tBtn[i];
  20.         if (pBtn->IsKeyDownFunc())
  21.         {
  22.                 if (pBtn->Count < KEY_FILTER_TIME)
  23.                 {
  24.                         pBtn->Count = KEY_FILTER_TIME;
  25.                 }
  26.                 else if(pBtn->Count < 2 * KEY_FILTER_TIME)
  27.                 {
  28.                         pBtn->Count++;
  29.                 }
  30.                 else
  31.                 {
  32.                         if (pBtn->State == 0)
  33.                         {
  34.                                 pBtn->State = 1;

  35.                                 /* 发送按钮按下的消息 */
  36.                                 bsp_PutKey((uint8_t)(3 * i + 1));
  37.                         }

  38.                         if (pBtn->LongTime > 0)
  39.                         {
  40.                                 if (pBtn->LongCount < pBtn->LongTime)
  41.                                 {
  42.                                         /* 发送按钮持续按下的消息 */
  43.                                         if (++pBtn->LongCount == pBtn->LongTime)
  44.                                         {
  45.                                                 /* 键值放入按键FIFO */
  46.                                                 bsp_PutKey((uint8_t)(3 * i + 3));
  47.                                         }
  48.                                 }
  49.                                 else
  50.                                 {
  51.                                         if (pBtn->RepeatSpeed > 0)
  52.                                         {
  53.                                                 if (++pBtn->RepeatCount >= pBtn->RepeatSpeed)
  54.                                                 {
  55.                                                         pBtn->RepeatCount = 0;
  56.                                                         /* 常按键后,每隔10ms发送1个按键 */
  57.                                                         bsp_PutKey((uint8_t)(3 * i + 1));
  58.                                                 }
  59.                                         }
  60.                                 }
  61.                         }
  62.                 }
  63.         }
  64.         else
  65.         {
  66.                 if(pBtn->Count > KEY_FILTER_TIME)
  67.                 {
  68.                         pBtn->Count = KEY_FILTER_TIME;
  69.                 }
  70.                 else if(pBtn->Count != 0)
  71.                 {
  72.                         pBtn->Count--;
  73.                 }
  74.                 else
  75.                 {
  76.                         if (pBtn->State == 1)
  77.                         {
  78.                                 pBtn->State = 0;

  79.                                 /* 发送按钮弹起的消息 */
  80.                                 bsp_PutKey((uint8_t)(3 * i + 2));
  81.                         }
  82.                 }

  83.                 pBtn->LongCount = 0;
  84.                 pBtn->RepeatCount = 0;
  85.         }
  86. }
  87. /*
  88. *********************************************************************************************************
  89. *        函 数 名: bsp_KeyScan
  90. *        功能说明: 扫描所有按键。非阻塞,被systick中断周期性的调用
  91. *        形    参:  无
  92. *        返 回 值: 无
  93. *********************************************************************************************************
  94. */
  95. void bsp_KeyScan(void)
  96. {
  97.         uint8_t xdata i;

  98.         for (i = 0; i < KEY_COUNT; i++)
  99.         {
  100.                 bsp_DetectKey(i);
  101.         }
  102. }
复制代码
 楼主| 余三水 发表于 2020-5-31 16:24 | 显示全部楼层
在主函数中,非堵塞方式获取按键键值
  1. /*
  2. *********************************************************************************************************
  3. *        函 数 名: bsp_GetKey
  4. *        功能说明: 从按键FIFO缓冲区读取一个键值。
  5. *        形    参:  无
  6. *        返 回 值: 按键代码
  7. *********************************************************************************************************
  8. */
  9. uint8_t bsp_GetKey(void)
  10. {
  11.         uint8_t xdata ret;

  12.         if (fifo_pop(&s_tKey, &ret) == 1)
  13.         {
  14.                 return KEY_NONE;
  15.         }
  16.         else
  17.         {
  18.                 return ret;
  19.         }
  20. }
复制代码
 楼主| 余三水 发表于 2020-5-31 16:25 | 显示全部楼层
完整代码如下
bsp_key.h
  1. /*!
  2.   * [url=home.php?mod=space&uid=288409]@file[/url]     BSP_KEY.h
  3.   *
  4.   * [url=home.php?mod=space&uid=247401]@brief[/url]    按键驱动文件
  5.   *
  6.   * [url=home.php?mod=space&uid=102924]@company[/url]  
  7.   *
  8.   * [url=home.php?mod=space&uid=187600]@author[/url]   不咸不要钱
  9.   *
  10.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]     无
  11.   *
  12.   * [url=home.php?mod=space&uid=895143]@version[/url]  
  13.   *
  14.   * [url=home.php?mod=space&uid=212281]@date[/url]     2019/10/18 星期五
  15.   */
  16. #ifndef __LQ_KEY_H
  17. #define __LQ_KEY_H

  18. #include "LQ_GPIO.h"



  19. /* 矩阵键盘 */
  20. #define C1_PIN             1
  21. #define C1_GPIO_PORT       2

  22. #define C2_PIN             2
  23. #define C2_GPIO_PORT       2

  24. #define C3_PIN             3
  25. #define C3_GPIO_PORT       2

  26. #define C4_PIN             4
  27. #define C4_GPIO_PORT       2


  28. // Row1, Row2, Row3, Row4
  29. #define R1_PIN             1
  30. #define R1_GPIO_PORT       4

  31. #define R2_PIN             0
  32. #define R2_GPIO_PORT       2

  33. #define R3_PIN             2
  34. #define R3_GPIO_PORT       4




  35. #define KEY_COUNT    13                                                   /* 按键个数, 12个独立建 + 1 个组合键 */



  36. /* 按键ID, 主要用于bsp_KeyState()函数的入口参数 */
  37. typedef enum
  38. {
  39.         KID_K0,
  40.         KID_K1,
  41.         KID_K2,
  42.         KID_K3,
  43.         KID_K4,
  44.         KID_K5,
  45.         KID_K6,
  46.         KID_K7,
  47.         KID_K8,
  48.         KID_K9,
  49.         KID_K10,
  50.         KID_K11,
  51.         KID_K12,
  52.        
  53. }KEY_ID_E;

  54. /*
  55.         按键滤波时间50ms, 单位10ms。
  56.         只有连续检测到50ms状态不变才认为有效,包括弹起和按下两种事件
  57.         即使按键电路不做硬件滤波,该滤波机制也可以保证可靠地检测到按键事件
  58. */
  59. #define KEY_FILTER_TIME   5
  60. #define KEY_LONG_TIME     100                        /* 单位10ms, 持续1秒,认为长按事件 */

  61. /*
  62.         每个按键对应1个全局的结构体变量。
  63. */
  64. typedef struct
  65. {
  66.         /* 下面是一个函数指针,指向判断按键手否按下的函数 */
  67.         uint8_t (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */

  68.         uint8_t  Count;                        /* 滤波器计数器 */
  69.         uint16_t LongCount;                /* 长按计数器 */
  70.         uint16_t LongTime;                /* 按键按下持续时间, 0表示不检测长按 */
  71.         uint8_t  State;                        /* 按键当前状态(按下还是弹起) */
  72.         uint8_t  RepeatSpeed;        /* 连续按键周期 */
  73.         uint8_t  RepeatCount;        /* 连续按键计数器 */
  74. }KEY_T;

  75. /*
  76.         定义键值代码, 必须按如下次序定时每个键的按下、弹起和长按事件

  77.         推荐使用enum, 不用#define,原因:
  78.         (1) 便于新增键值,方便调整顺序,使代码看起来舒服点
  79.         (2) 编译器可帮我们避免键值重复。
  80. */
  81. typedef enum
  82. {
  83.         KEY_NONE = 0,                        /* 0 表示按键事件 */

  84.         KEY_0_DOWN,                            /* 0键按下 */
  85.         KEY_0_UP,                                /* 0键弹起 */
  86.         KEY_0_LONG,                            /* 0键长按 */
  87.        
  88.         KEY_1_DOWN,                                /* 1键按下 */
  89.         KEY_1_UP,                                /* 1键弹起 */
  90.         KEY_1_LONG,                                /* 1键长按 */

  91.         KEY_2_DOWN,                                /* 2键按下 */
  92.         KEY_2_UP,                                /* 2键弹起 */
  93.         KEY_2_LONG,                                /* 2键长按 */

  94.         KEY_3_DOWN,                                /* 3键按下 */
  95.         KEY_3_UP,                                /* 3键弹起 */
  96.         KEY_3_LONG,                                /* 3键长按 */

  97.         KEY_4_DOWN,                                /* 4键按下 */
  98.         KEY_4_UP,                                /* 4键弹起 */
  99.         KEY_4_LONG,                                /* 4键长按 */

  100.         KEY_5_DOWN,                                /* 5键按下 */
  101.         KEY_5_UP,                                /* 5键弹起 */
  102.         KEY_5_LONG,                                /* 5键长按 */

  103.         KEY_6_DOWN,                                /* 6键按下 */
  104.         KEY_6_UP,                                /* 6键弹起 */
  105.         KEY_6_LONG,                                /* 6键长按 */

  106.         KEY_7_DOWN,                                /* 7键按下 */
  107.         KEY_7_UP,                                /* 7键弹起 */
  108.         KEY_7_LONG,                                /* 7键长按 */

  109.         KEY_8_DOWN,                                /* 8键按下 */
  110.         KEY_8_UP,                                /* 8键弹起 */
  111.         KEY_8_LONG,                                /* 8键长按 */

  112.         KEY_9_DOWN,                                /* 9键按下 */
  113.         KEY_9_UP,                                /* 9键弹起 */
  114.         KEY_9_LONG,                                /* 9键长按 */

  115.         KEY_10_DOWN,                        /* 10键按下 */
  116.         KEY_10_UP,                                /* 10键弹起 */
  117.         KEY_10_LONG,                        /* 10键长按 */
  118.        
  119.         KEY_11_DOWN,                        /* 11键按下 */
  120.         KEY_11_UP,                                /* 11键弹起 */
  121.         KEY_11_LONG,                        /* 11键长按 */
  122.        
  123.         KEY_12_DOWN,                        /* 12键按下 */
  124.         KEY_12_UP,                                /* 12键弹起 */
  125.         KEY_12_LONG,                        /* 12键长按 */
  126. }KEY_ENUM;

  127. /* 按键FIFO用到变量 */
  128. #define FIFO_SIZE        15

  129. /*! fifo缓冲区类型 */
  130. #define FIFO_TYPE    uint8_t

  131. /*! fifo缓冲区满后 是否覆盖旧数据 0进行覆盖  1报错入栈失败*/
  132. #define FIFO_COVER   0
  133. typedef struct
  134. {
  135.     FIFO_TYPE  buff[FIFO_SIZE];       /* FIFO 缓冲区 */

  136.     uint32_t   fifoLen;               /* FIFO 缓冲区有效数据长度 */

  137.     uint32_t   fifoWrite;             /* 缓冲区写指针 */
  138.     uint32_t   fifoRead;              /* 缓冲区读指针 */

  139. }fifo_t;

  140. typedef fifo_t KEY_FIFO_T;

  141. /* 供外部调用的函数声明 */
  142. void bsp_InitKey(void);
  143. void bsp_KeyScan(void);
  144. void bsp_PutKey(uint8_t _KeyCode);
  145. uint8_t bsp_GetKey(void);
  146. uint8_t bsp_GetKey2(void);
  147. uint8_t bsp_GetKeyState(KEY_ID_E _ucKeyID);
  148. void bsp_SetKeyParam(uint8_t _ucKeyID, uint16_t _LongTime, uint8_t  _RepeatSpeed);
  149. void bsp_ClearKey(void);




  150. #endif
复制代码
 楼主| 余三水 发表于 2020-5-31 16:27 | 显示全部楼层
bsp_key.c
  1. /*!
  2.   * @file     BSP_KEY.c
  3.   *
  4.   * @brief    按键驱动文件
  5.   *
  6.   * @company  
  7.   *
  8.   * @author   不咸不要钱
  9.   *
  10.   * @note     无
  11.   *
  12.   * @version  
  13.   *
  14.   * @date     2019/10/18 星期五
  15.   */
  16. #include "bsp_key.h"
  17. #include "lq_gpio.h"
  18. #include "stdio.h"



  19. static KEY_T xdata s_tBtn[KEY_COUNT];
  20. static KEY_FIFO_T xdata s_tKey;                /* 按键FIFO变量,结构体 */

  21. static void bsp_InitKeyVar(void);
  22. static void bsp_InitKeyHard(void);
  23. static void bsp_DetectKey(uint8_t i);

  24. static uint8_t IsKeyDown0(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 0; if (P(R2_GPIO_PORT, R2_PIN) == 0) return 1;else return 0;}
  25. static uint8_t IsKeyDown1(void)  {P(C1_GPIO_PORT, C1_PIN) = 0;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; NOP(50); if (P(R1_GPIO_PORT, R1_PIN) == 0) return 1;else return 0;}
  26. static uint8_t IsKeyDown2(void)  {P(C1_GPIO_PORT, C1_PIN) = 0;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R2_GPIO_PORT, R2_PIN) == 0) return 1;else return 0;}
  27. static uint8_t IsKeyDown3(void)  {P(C1_GPIO_PORT, C1_PIN) = 0;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R3_GPIO_PORT, R3_PIN) == 0) return 1;else return 0;}
  28. static uint8_t IsKeyDown4(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 0;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R1_GPIO_PORT, R1_PIN) == 0) return 1;else return 0;}
  29. static uint8_t IsKeyDown5(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 0;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R2_GPIO_PORT, R2_PIN) == 0) return 1;else return 0;}
  30. static uint8_t IsKeyDown6(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 0;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R3_GPIO_PORT, R3_PIN) == 0) return 1;else return 0;}
  31. static uint8_t IsKeyDown7(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 0; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R1_GPIO_PORT, R1_PIN) == 0) return 1;else return 0;}
  32. static uint8_t IsKeyDown8(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 0; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R2_GPIO_PORT, R2_PIN) == 0) return 1;else return 0;}
  33. static uint8_t IsKeyDown9(void)  {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 0; P(C4_GPIO_PORT, C4_PIN) = 1; if (P(R3_GPIO_PORT, R3_PIN) == 0) return 1;else return 0;}
  34. static uint8_t IsKeyDown10(void) {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 0; NOP(50); if (P(R1_GPIO_PORT, R1_PIN) == 0) return 1;else return 0;}
  35. static uint8_t IsKeyDown11(void) {P(C1_GPIO_PORT, C1_PIN) = 1;  P(C2_GPIO_PORT, C2_PIN) = 1;  P(C3_GPIO_PORT, C3_PIN) = 1; P(C4_GPIO_PORT, C4_PIN) = 0; if (P(R3_GPIO_PORT, R3_PIN) == 0) return 1;else return 0;}

  36. /* 组合按键 key1 && key2 */
  37. static uint8_t IsKeyDown12(void)  { return IsKeyDown1() && IsKeyDown2();}

  38. /*!
  39. * @brief    fifo初始化
  40. *
  41. * @param    fifo_t    :  FIFO
  42. *
  43. * [url=home.php?mod=space&uid=266161]@return[/url]   无
  44. *
  45. * @note     无
  46. *
  47. * [url=home.php?mod=space&uid=8537]@see[/url]      fifo_t  tempFifo;
  48. *           fifo_init(tempFifo);  //fifo初始化
  49. *
  50. * @date     2020/5/21
  51. */
  52. void fifo_init(fifo_t *fifo)
  53. {
  54.     fifo->fifoLen   = 0;
  55.     fifo->fifoRead  = 0;
  56.     fifo->fifoWrite = 0;
  57. }


  58. /*!
  59. * @brief    fifo压入数据
  60. *
  61. * @param    fifo_t    :  FIFO
  62. * @param    data      :  入栈数据
  63. *
  64. * @return   0 :成功   1 :失败
  65. *
  66. * @note     FIFO_COVER 宏定义进行判断缓冲区满后的操作
  67. *
  68. * @see      fifo_t  tempFifo;
  69. *           fifo_push(tempFifo, 120);  //fifo中压入一个数据
  70. *
  71. * @date     2020/5/21
  72. */
  73. uint8_t fifo_push(fifo_t *fifo, FIFO_TYPE dat)
  74. {
  75.     fifo->fifoLen++;

  76.     /* 判断缓冲区是否已满 */
  77.     if(fifo->fifoLen > FIFO_SIZE)
  78.     {
  79.         fifo->fifoLen = FIFO_SIZE;

  80. #if FIFO_COVER
  81.         return 1;
  82. #else
  83.         if(++fifo->fifoRead >= FIFO_SIZE)
  84.         {
  85.             fifo->fifoRead = 0;
  86.         }
  87. #endif
  88.     }

  89.     fifo->buff[fifo->fifoWrite] = dat;

  90.     if(++fifo->fifoWrite >= FIFO_SIZE)
  91.     {
  92.         fifo->fifoWrite = 0;
  93.     }

  94.     return 0;

  95. }

  96. /*!
  97. * @brief    fifo弹出数据
  98. *
  99. * @param    fifo_t    :  FIFO
  100. * @param    data      :  出栈数据
  101. *
  102. * @return   0 :成功   1 :失败
  103. *
  104. * @note     无
  105. *
  106. * @see      fifo_t  tempFifo;
  107. *           FIFO_TYPE tempData;
  108. *           fifo_push(tempFifo, 120);       //fifo中压入一个数据
  109. *           fifo_pop(tempFifo, &tempData);  //fifo中弹出一个数据
  110. *
  111. * @date     2020/5/21
  112. */
  113. uint8_t fifo_pop(fifo_t *fifo, FIFO_TYPE *dat)
  114. {
  115.     /* 缓冲区为空 */
  116.     if(fifo->fifoLen == 0)
  117.     {
  118.         return 1;
  119.     }

  120.     fifo->fifoLen--;

  121.     *dat = fifo->buff[fifo->fifoRead];

  122.     if(++fifo->fifoRead >= FIFO_SIZE)
  123.     {
  124.         fifo->fifoRead = 0;
  125.     }

  126.     return 0;
  127. }

  128. /*
  129. *********************************************************************************************************
  130. *        函 数 名: bsp_InitKey
  131. *        功能说明: 初始化按键. 该函数被 bsp_Init() 调用。
  132. *        形    参:  无
  133. *        返 回 值: 无
  134. *********************************************************************************************************
  135. */
  136. void bsp_InitKey(void)
  137. {
  138.         bsp_InitKeyVar();                /* 初始化按键变量 */
  139.         bsp_InitKeyHard();                /* 初始化按键硬件 */
  140. }


  141. /*
  142. *********************************************************************************************************
  143. *        函 数 名: bsp_PutKey
  144. *        功能说明: 将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
  145. *        形    参:  _KeyCode : 按键代码
  146. *        返 回 值: 无
  147. *********************************************************************************************************
  148. */
  149. void bsp_PutKey(uint8_t _KeyCode)
  150. {
  151.         fifo_push(&s_tKey, _KeyCode);
  152. }


  153. /*
  154. *********************************************************************************************************
  155. *        函 数 名: bsp_GetKey
  156. *        功能说明: 从按键FIFO缓冲区读取一个键值。
  157. *        形    参:  无
  158. *        返 回 值: 按键代码
  159. *********************************************************************************************************
  160. */
  161. uint8_t bsp_GetKey(void)
  162. {
  163.         uint8_t xdata ret;

  164.         if (fifo_pop(&s_tKey, &ret) == 1)
  165.         {
  166.                 return KEY_NONE;
  167.         }
  168.         else
  169.         {
  170.                 return ret;
  171.         }
  172. }


  173. /*
  174. *********************************************************************************************************
  175. *        函 数 名: bsp_GetKeyState
  176. *        功能说明: 读取按键的状态
  177. *        形    参:  _ucKeyID : 按键ID,从0开始
  178. *        返 回 值: 1 表示按下, 0 表示未按下
  179. *********************************************************************************************************
  180. */
  181. uint8_t bsp_GetKeyState(KEY_ID_E _ucKeyID)
  182. {
  183.         return s_tBtn[_ucKeyID].State;
  184. }


  185. /*
  186. *********************************************************************************************************
  187. *        函 数 名: bsp_SetKeyParam
  188. *        功能说明: 设置按键参数
  189. *        形    参:_ucKeyID : 按键ID,从0开始
  190. *                        _LongTime : 长按事件时间
  191. *                         _RepeatSpeed : 连发速度
  192. *        返 回 值: 无
  193. *********************************************************************************************************
  194. */
  195. void bsp_SetKeyParam(uint8_t _ucKeyID, uint16_t _LongTime, uint8_t  _RepeatSpeed)
  196. {
  197.         s_tBtn[_ucKeyID].LongTime = _LongTime;                        /* 长按时间 0 表示不检测长按键事件 */
  198.         s_tBtn[_ucKeyID].RepeatSpeed = _RepeatSpeed;                        /* 按键连发的速度,0表示不支持连发 */
  199.         s_tBtn[_ucKeyID].RepeatCount = 0;                                                /* 连发计数器 */
  200. }

  201. /*
  202. *********************************************************************************************************
  203. *        函 数 名: bsp_ClearKey
  204. *        功能说明: 清空按键FIFO缓冲区
  205. *        形    参:无
  206. *        返 回 值: 按键代码
  207. *********************************************************************************************************
  208. */
  209. void bsp_ClearKey(void)
  210. {
  211.         s_tKey.fifoRead = s_tKey.fifoWrite;
  212. }


  213. /*
  214. *********************************************************************************************************
  215. *        函 数 名: bsp_InitKeyHard
  216. *        功能说明: 配置按键对应的GPIO
  217. *        形    参:  无
  218. *        返 回 值: 无
  219. *********************************************************************************************************
  220. */
  221. static void bsp_InitKeyHard(void)
  222. {
  223.         //KEY 初始化
  224.     PIN_InitPushPull(C1_GPIO_PORT, C1_PIN);
  225.         PIN_InitPushPull(C2_GPIO_PORT, C2_PIN);
  226.         PIN_InitPushPull(C3_GPIO_PORT, C3_PIN);
  227.         PIN_InitPushPull(C4_GPIO_PORT, C4_PIN);
  228.         PIN_InitOpenDrain(R1_GPIO_PORT, R1_PIN);
  229.         PIN_InitOpenDrain(R2_GPIO_PORT, R2_PIN);
  230.         PIN_InitOpenDrain(R3_GPIO_PORT, R3_PIN);
  231.        
  232. }


  233. /*
  234. *********************************************************************************************************
  235. *        函 数 名: bsp_InitKeyVar
  236. *        功能说明: 初始化按键变量
  237. *        形    参:  无
  238. *        返 回 值: 无
  239. *********************************************************************************************************
  240. */
  241. static void bsp_InitKeyVar(void)
  242. {
  243.         uint8_t xdata i;

  244.         /* 对按键FIFO读写指针清零 */
  245.         fifo_init(&s_tKey);
  246.        
  247.         /* 给每个按键结构体成员变量赋一组缺省值 */
  248.         for (i = 0; i < KEY_COUNT; i++)
  249.         {
  250.                 s_tBtn[i].LongTime = KEY_LONG_TIME;                        /* 长按时间 0 表示不检测长按键事件 */
  251.                 s_tBtn[i].Count = KEY_FILTER_TIME / 2;                /* 计数器设置为滤波时间的一半 */
  252.                 s_tBtn[i].State = 0;                                                        /* 按键缺省状态,0为未按下 */
  253.                 //s_tBtn[i].KeyCodeDown = 3 * i + 1;                                /* 按键按下的键值代码 */
  254.                 //s_tBtn[i].KeyCodeUp   = 3 * i + 2;                                /* 按键弹起的键值代码 */
  255.                 //s_tBtn[i].KeyCodeLong = 3 * i + 3;                                /* 按键被持续按下的键值代码 */
  256.                 s_tBtn[i].RepeatSpeed = 0;                                                /* 按键连发的速度,0表示不支持连发 */
  257.                 s_tBtn[i].RepeatCount = 0;                                                /* 连发计数器 */
  258.         }


  259.         /* 判断按键按下的函数 */
  260.         s_tBtn[0].IsKeyDownFunc = IsKeyDown0;
  261.         s_tBtn[1].IsKeyDownFunc = IsKeyDown1;
  262.         s_tBtn[2].IsKeyDownFunc = IsKeyDown2;
  263.         s_tBtn[3].IsKeyDownFunc = IsKeyDown3;
  264.         s_tBtn[4].IsKeyDownFunc = IsKeyDown4;
  265.         s_tBtn[5].IsKeyDownFunc = IsKeyDown5;
  266.         s_tBtn[6].IsKeyDownFunc = IsKeyDown6;
  267.         s_tBtn[7].IsKeyDownFunc = IsKeyDown7;
  268.         s_tBtn[8].IsKeyDownFunc = IsKeyDown8;
  269.         s_tBtn[9].IsKeyDownFunc = IsKeyDown9;
  270.         s_tBtn[10].IsKeyDownFunc = IsKeyDown10;
  271.         s_tBtn[11].IsKeyDownFunc = IsKeyDown11;
  272.        
  273.         /* 组合按键 */
  274.         s_tBtn[12].IsKeyDownFunc = IsKeyDown12;
  275. }

  276. /*
  277. *********************************************************************************************************
  278. *        函 数 名: bsp_DetectKey
  279. *        功能说明: 检测一个按键。非阻塞状态,必须被周期性的调用。
  280. *        形    参:  按键结构变量指针
  281. *        返 回 值: 无
  282. *********************************************************************************************************
  283. */
  284. static void bsp_DetectKey(uint8_t i)
  285. {
  286.         KEY_T xdata *pBtn;

  287.         /*
  288.                 如果没有初始化按键函数,则报错
  289.                 if (s_tBtn[i].IsKeyDownFunc == 0)
  290.                 {
  291.                         printf("Fault : DetectButton(), s_tBtn[i].IsKeyDownFunc undefine");
  292.                 }
  293.         */

  294.         pBtn = &s_tBtn[i];
  295.         if (pBtn->IsKeyDownFunc())
  296.         {
  297.                 if (pBtn->Count < KEY_FILTER_TIME)
  298.                 {
  299.                         pBtn->Count = KEY_FILTER_TIME;
  300.                 }
  301.                 else if(pBtn->Count < 2 * KEY_FILTER_TIME)
  302.                 {
  303.                         pBtn->Count++;
  304.                 }
  305.                 else
  306.                 {
  307.                         if (pBtn->State == 0)
  308.                         {
  309.                                 pBtn->State = 1;

  310.                                 /* 发送按钮按下的消息 */
  311.                                 bsp_PutKey((uint8_t)(3 * i + 1));
  312.                                 P27 = 1;                   //开启蜂鸣器
  313.                         }

  314.                         if (pBtn->LongTime > 0)
  315.                         {
  316.                                 if (pBtn->LongCount < pBtn->LongTime)
  317.                                 {
  318.                                         /* 发送按钮持续按下的消息 */
  319.                                         if (++pBtn->LongCount == pBtn->LongTime)
  320.                                         {
  321.                                                 /* 键值放入按键FIFO */
  322.                                                 bsp_PutKey((uint8_t)(3 * i + 3));
  323.                                         }
  324.                                 }
  325.                                 else
  326.                                 {
  327.                                         if (pBtn->RepeatSpeed > 0)
  328.                                         {
  329.                                                 if (++pBtn->RepeatCount >= pBtn->RepeatSpeed)
  330.                                                 {
  331.                                                         pBtn->RepeatCount = 0;
  332.                                                         /* 常按键后,每隔10ms发送1个按键 */
  333.                                                         bsp_PutKey((uint8_t)(3 * i + 1));
  334.                                                 }
  335.                                         }
  336.                                 }
  337.                         }
  338.                 }
  339.         }
  340.         else
  341.         {
  342.                 if(pBtn->Count > KEY_FILTER_TIME)
  343.                 {
  344.                         pBtn->Count = KEY_FILTER_TIME;
  345.                 }
  346.                 else if(pBtn->Count != 0)
  347.                 {
  348.                         pBtn->Count--;
  349.                 }
  350.                 else
  351.                 {
  352.                         if (pBtn->State == 1)
  353.                         {
  354.                                 pBtn->State = 0;

  355.                                 /* 发送按钮弹起的消息 */
  356.                                 bsp_PutKey((uint8_t)(3 * i + 2));
  357.                                 P27 = 0;                   //关闭蜂鸣器
  358.                         }
  359.                 }

  360.                 pBtn->LongCount = 0;
  361.                 pBtn->RepeatCount = 0;
  362.         }
  363. }

  364. /*
  365. *********************************************************************************************************
  366. *        函 数 名: bsp_KeyScan
  367. *        功能说明: 扫描所有按键。非阻塞,被systick中断周期性的调用
  368. *        形    参:  无
  369. *        返 回 值: 无
  370. *********************************************************************************************************
  371. */
  372. void bsp_KeyScan(void)
  373. {
  374.         uint8_t xdata i;

  375.         for (i = 0; i < KEY_COUNT; i++)
  376.         {
  377.                 bsp_DetectKey(i);
  378.         }
  379. }
复制代码
晓伍 发表于 2020-6-3 15:38 | 显示全部楼层
非常感谢楼主分享
八层楼 发表于 2020-6-3 15:38 | 显示全部楼层
可以嵌套吗
观海 发表于 2020-6-3 15:39 | 显示全部楼层
**很不错
heimaojingzhang 发表于 2020-6-3 15:39 | 显示全部楼层
楼主辛苦了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

356

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部