硬汉嵌入式论坛

 找回密码
 立即注册
查看: 4351|回复: 12
收起左侧

[NUCLEO-H743ZI] 【STM32H743实验例程】实验6:STM32H743按键FIFO,支持按下,释放,长按和连按

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
发表于 2018-4-5 02:33:24 | 显示全部楼层 |阅读模式
实验介绍
开发平台:官方STM32H743 NUCLEO板子
开发环境:MDK5.25正式版
软件版本:
(1)CMSIS软件包 V5.3.0
(2)H7的HAL库版本 V1.2.0
例程下载:
实验6:STM32H743按键FIFO.7z (1.08 MB, 下载次数: 249)


  1. /*
  2. *********************************************************************************************************
  3. *
  4. *        模块名称 : 独立按键驱动模块
  5. *        文件名称 : bsp_key.c
  6. *        版    本 : V1.0
  7. *        说    明 : 扫描独立按键,具有软件滤波机制,具有按键FIFO。可以检测如下事件:
  8. *                                (1) 按键按下
  9. *                                (2) 按键弹起
  10. *                                (3) 长按键
  11. *                                (4) 长按时自动连发
  12. *
  13. *        修改记录 :
  14. *                版本号  日期        作者     说明
  15. *                V1.0    2013-02-01 armfly  正式发布
  16. *                V1.1    2013-06-29 armfly  增加1个读指针,用于bsp_Idle() 函数读取系统控制组合键(截屏)
  17. *                                                                   增加 K1 K2 组合键 和 K2 K3 组合键,用于系统控制
  18. *
  19. *        Copyright (C), 2013-2014, 安富莱电子 www.armfly.com
  20. *
  21. *********************************************************************************************************
  22. */

  23. #include "bsp.h"

  24. /*
  25.         该程序适用于ST官方NUCLEO开发板
  26.         如果用于其它硬件,请修改GPIO定义和 IsKeyDown1 - IsKeyDown8 函数

  27.         如果用户的按键个数小于8个,你可以将多余的按键全部定义为和第1个按键一样,并不影响程序功能
  28.         #define KEY_COUNT    8          这个在 bsp_key.h 文件中定义
  29. */

  30. /*
  31.          按键口线分配:
  32.                 K1 键      : PC13   (高电平表示按下)
  33. */

  34. /* 按键口对应的RCC时钟 */
  35. #define RCC_ALL_KEY()   do { __HAL_RCC_GPIOC_CLK_ENABLE();} while(0)

  36. #define GPIO_PORT_K1    GPIOC
  37. #define GPIO_PIN_K1            GPIO_PIN_13


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

  40. static void bsp_InitKeyVar(void);
  41. static void bsp_InitKeyHard(void);
  42. static void bsp_DetectKey(uint8_t i);

  43. /*
  44. *********************************************************************************************************
  45. *        函 数 名: IsKeyDownX
  46. *        功能说明: 判断按键是否按下
  47. *        形    参: 无
  48. *        返 回 值: 返回值1 表示按下,0表示未按下
  49. *********************************************************************************************************
  50. */
  51. static uint8_t IsKeyDown1(void) {if ((GPIO_PORT_K1->IDR & GPIO_PIN_K1) == 0) return 0;else return 1;}


  52. /*
  53. *********************************************************************************************************
  54. *        函 数 名: bsp_InitKey
  55. *        功能说明: 初始化按键. 该函数被 bsp_Init() 调用。
  56. *        形    参:  无
  57. *        返 回 值: 无
  58. *********************************************************************************************************
  59. */
  60. void bsp_InitKey(void)
  61. {
  62.         bsp_InitKeyVar();                /* 初始化按键变量 */
  63.         bsp_InitKeyHard();                /* 初始化按键硬件 */
  64. }

  65. /*
  66. *********************************************************************************************************
  67. *        函 数 名: bsp_PutKey
  68. *        功能说明: 将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
  69. *        形    参:  _KeyCode : 按键代码
  70. *        返 回 值: 无
  71. *********************************************************************************************************
  72. */
  73. void bsp_PutKey(uint8_t _KeyCode)
  74. {
  75.         s_tKey.Buf[s_tKey.Write] = _KeyCode;

  76.         if (++s_tKey.Write  >= KEY_FIFO_SIZE)
  77.         {
  78.                 s_tKey.Write = 0;
  79.         }
  80. }

  81. /*
  82. *********************************************************************************************************
  83. *        函 数 名: bsp_GetKey
  84. *        功能说明: 从按键FIFO缓冲区读取一个键值。
  85. *        形    参:  无
  86. *        返 回 值: 按键代码
  87. *********************************************************************************************************
  88. */
  89. uint8_t bsp_GetKey(void)
  90. {
  91.         uint8_t ret;

  92.         if (s_tKey.Read == s_tKey.Write)
  93.         {
  94.                 return KEY_NONE;
  95.         }
  96.         else
  97.         {
  98.                 ret = s_tKey.Buf[s_tKey.Read];

  99.                 if (++s_tKey.Read >= KEY_FIFO_SIZE)
  100.                 {
  101.                         s_tKey.Read = 0;
  102.                 }
  103.                 return ret;
  104.         }
  105. }

  106. /*
  107. *********************************************************************************************************
  108. *        函 数 名: bsp_GetKey2
  109. *        功能说明: 从按键FIFO缓冲区读取一个键值。独立的读指针。
  110. *        形    参:  无
  111. *        返 回 值: 按键代码
  112. *********************************************************************************************************
  113. */
  114. uint8_t bsp_GetKey2(void)
  115. {
  116.         uint8_t ret;

  117.         if (s_tKey.Read2 == s_tKey.Write)
  118.         {
  119.                 return KEY_NONE;
  120.         }
  121.         else
  122.         {
  123.                 ret = s_tKey.Buf[s_tKey.Read2];

  124.                 if (++s_tKey.Read2 >= KEY_FIFO_SIZE)
  125.                 {
  126.                         s_tKey.Read2 = 0;
  127.                 }
  128.                 return ret;
  129.         }
  130. }

  131. /*
  132. *********************************************************************************************************
  133. *        函 数 名: bsp_GetKeyState
  134. *        功能说明: 读取按键的状态
  135. *        形    参:  _ucKeyID : 按键ID,从0开始
  136. *        返 回 值: 1 表示按下, 0 表示未按下
  137. *********************************************************************************************************
  138. */
  139. uint8_t bsp_GetKeyState(KEY_ID_E _ucKeyID)
  140. {
  141.         return s_tBtn[_ucKeyID].State;
  142. }

  143. /*
  144. *********************************************************************************************************
  145. *        函 数 名: bsp_SetKeyParam
  146. *        功能说明: 设置按键参数
  147. *        形    参:_ucKeyID : 按键ID,从0开始
  148. *                        _LongTime : 长按事件时间
  149. *                         _RepeatSpeed : 连发速度
  150. *        返 回 值: 无
  151. *********************************************************************************************************
  152. */
  153. void bsp_SetKeyParam(uint8_t _ucKeyID, uint16_t _LongTime, uint8_t  _RepeatSpeed)
  154. {
  155.         s_tBtn[_ucKeyID].LongTime = _LongTime;                        /* 长按时间 0 表示不检测长按键事件 */
  156.         s_tBtn[_ucKeyID].RepeatSpeed = _RepeatSpeed;                        /* 按键连发的速度,0表示不支持连发 */
  157.         s_tBtn[_ucKeyID].RepeatCount = 0;                                                /* 连发计数器 */
  158. }


  159. /*
  160. *********************************************************************************************************
  161. *        函 数 名: bsp_ClearKey
  162. *        功能说明: 清空按键FIFO缓冲区
  163. *        形    参:无
  164. *        返 回 值: 按键代码
  165. *********************************************************************************************************
  166. */
  167. void bsp_ClearKey(void)
  168. {
  169.         s_tKey.Read = s_tKey.Write;
  170. }

  171. /*
  172. *********************************************************************************************************
  173. *        函 数 名: bsp_InitKeyHard
  174. *        功能说明: 配置按键对应的GPIO
  175. *        形    参:  无
  176. *        返 回 值: 无
  177. *********************************************************************************************************
  178. */
  179. static void bsp_InitKeyHard(void)
  180. {
  181.         GPIO_InitTypeDef  GPIO_InitStruct;

  182.         /* 第1步:打开GPIO时钟 */
  183.         RCC_ALL_KEY();

  184.         /* 第2步:配置所有的按键GPIO */
  185.         GPIO_InitStruct.Mode = GPIO_MODE_INPUT;                           /* 设置输入 */
  186.         GPIO_InitStruct.Pull = GPIO_NOPULL;                 /* 上下拉电阻不使能 */
  187.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;  /* GPIO速度等级 */

  188.         GPIO_InitStruct.Pin = GPIO_PIN_K1;
  189.         HAL_GPIO_Init(GPIO_PORT_K1, &GPIO_InitStruct);
  190. }

  191. /*
  192. *********************************************************************************************************
  193. *        函 数 名: bsp_InitKeyVar
  194. *        功能说明: 初始化按键变量
  195. *        形    参:  无
  196. *        返 回 值: 无
  197. *********************************************************************************************************
  198. */
  199. static void bsp_InitKeyVar(void)
  200. {
  201.         uint8_t i;

  202.         /* 对按键FIFO读写指针清零 */
  203.         s_tKey.Read = 0;
  204.         s_tKey.Write = 0;
  205.         s_tKey.Read2 = 0;

  206.         /* 给每个按键结构体成员变量赋一组缺省值 */
  207.         for (i = 0; i < KEY_COUNT; i++)
  208.         {
  209.                 s_tBtn[i].LongTime = KEY_LONG_TIME;                        /* 长按时间 0 表示不检测长按键事件 */
  210.                 s_tBtn[i].Count = KEY_FILTER_TIME / 2;                /* 计数器设置为滤波时间的一半 */
  211.                 s_tBtn[i].State = 0;                                                        /* 按键缺省状态,0为未按下 */
  212.                 //s_tBtn[i].KeyCodeDown = 3 * i + 1;                                /* 按键按下的键值代码 */
  213.                 //s_tBtn[i].KeyCodeUp   = 3 * i + 2;                                /* 按键弹起的键值代码 */
  214.                 //s_tBtn[i].KeyCodeLong = 3 * i + 3;                                /* 按键被持续按下的键值代码 */
  215.                 s_tBtn[i].RepeatSpeed = 0;                                                /* 按键连发的速度,0表示不支持连发 */
  216.                 s_tBtn[i].RepeatCount = 0;                                                /* 连发计数器 */
  217.         }

  218.         /* 如果需要单独更改某个按键的参数,可以在此单独重新赋值 */
  219.         /* 比如,我们希望按键1按下超过1秒后,自动重发相同键值 */
  220.         s_tBtn[KID_K1].LongTime = 100;
  221.         s_tBtn[KID_K1].RepeatSpeed = 5;        /* 每隔50ms自动发送键值 */

  222.         /* 判断按键按下的函数 */
  223.         s_tBtn[KID_K1].IsKeyDownFunc = IsKeyDown1;
  224. }

  225. /*
  226. *********************************************************************************************************
  227. *        函 数 名: bsp_DetectKey
  228. *        功能说明: 检测一个按键。非阻塞状态,必须被周期性的调用。
  229. *        形    参:  按键结构变量指针
  230. *        返 回 值: 无
  231. *********************************************************************************************************
  232. */
  233. static void bsp_DetectKey(uint8_t i)
  234. {
  235.         KEY_T *pBtn;

  236.         /*
  237.                 如果没有初始化按键函数,则报错
  238.                 if (s_tBtn[i].IsKeyDownFunc == 0)
  239.                 {
  240.                         printf("Fault : DetectButton(), s_tBtn[i].IsKeyDownFunc undefine");
  241.                 }
  242.         */

  243.         pBtn = &s_tBtn[i];
  244.         if (pBtn->IsKeyDownFunc())
  245.         {
  246.                 if (pBtn->Count < KEY_FILTER_TIME)
  247.                 {
  248.                         pBtn->Count = KEY_FILTER_TIME;
  249.                 }
  250.                 else if(pBtn->Count < 2 * KEY_FILTER_TIME)
  251.                 {
  252.                         pBtn->Count++;
  253.                 }
  254.                 else
  255.                 {
  256.                         if (pBtn->State == 0)
  257.                         {
  258.                                 pBtn->State = 1;

  259.                                 /* 发送按钮按下的消息 */
  260.                                 bsp_PutKey((uint8_t)(3 * i + 1));
  261.                         }

  262.                         if (pBtn->LongTime > 0)
  263.                         {
  264.                                 if (pBtn->LongCount < pBtn->LongTime)
  265.                                 {
  266.                                         /* 发送按钮持续按下的消息 */
  267.                                         if (++pBtn->LongCount == pBtn->LongTime)
  268.                                         {
  269.                                                 /* 键值放入按键FIFO */
  270.                                                 bsp_PutKey((uint8_t)(3 * i + 3));
  271.                                         }
  272.                                 }
  273.                                 else
  274.                                 {
  275.                                         if (pBtn->RepeatSpeed > 0)
  276.                                         {
  277.                                                 if (++pBtn->RepeatCount >= pBtn->RepeatSpeed)
  278.                                                 {
  279.                                                         pBtn->RepeatCount = 0;
  280.                                                         /* 常按键后,每隔10ms发送1个按键 */
  281.                                                         bsp_PutKey((uint8_t)(3 * i + 1));
  282.                                                 }
  283.                                         }
  284.                                 }
  285.                         }
  286.                 }
  287.         }
  288.         else
  289.         {
  290.                 if(pBtn->Count > KEY_FILTER_TIME)
  291.                 {
  292.                         pBtn->Count = KEY_FILTER_TIME;
  293.                 }
  294.                 else if(pBtn->Count != 0)
  295.                 {
  296.                         pBtn->Count--;
  297.                 }
  298.                 else
  299.                 {
  300.                         if (pBtn->State == 1)
  301.                         {
  302.                                 pBtn->State = 0;

  303.                                 /* 发送按钮弹起的消息 */
  304.                                 bsp_PutKey((uint8_t)(3 * i + 2));
  305.                         }
  306.                 }

  307.                 pBtn->LongCount = 0;
  308.                 pBtn->RepeatCount = 0;
  309.         }
  310. }


  311. /*
  312. *********************************************************************************************************
  313. *        函 数 名: bsp_KeyScan
  314. *        功能说明: 扫描所有按键。非阻塞,被systick中断周期性的调用
  315. *        形    参:  无
  316. *        返 回 值: 无
  317. *********************************************************************************************************
  318. */
  319. void bsp_KeyScan(void)
  320. {
  321.         uint8_t i;

  322.         for (i = 0; i < KEY_COUNT; i++)
  323.         {
  324.                 bsp_DetectKey(i);
  325.         }
  326. }

  327. /***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
复制代码

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
 楼主| 发表于 2018-4-5 02:35:09 | 显示全部楼层
按键的原理图如下:

QQ截图20180405023510.png
回复

使用道具 举报

4

主题

15

回帖

27

积分

新手上路

积分
27
QQ
发表于 2018-4-11 16:56:59 | 显示全部楼层
什么时候出M7的开发板啊?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
 楼主| 发表于 2018-4-12 00:03:12 | 显示全部楼层
zhudadragon 发表于 2018-4-11 16:56
什么时候出M7的开发板啊?

还不清楚
回复

使用道具 举报

0

主题

4

回帖

4

积分

新手上路

积分
4
发表于 2020-3-30 16:21:09 | 显示全部楼层
请问长按时自动连发是指什么呢?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
 楼主| 发表于 2020-3-30 16:23:54 | 显示全部楼层
shoubolusdkd 发表于 2020-3-30 16:21
请问长按时自动连发是指什么呢?

电脑键盘按住某个字母不松手就有效果了。
回复

使用道具 举报

0

主题

4

回帖

4

积分

新手上路

积分
4
发表于 2020-3-30 16:29:31 | 显示全部楼层
好的,谢谢!
回复

使用道具 举报

2

主题

85

回帖

91

积分

初级会员

积分
91
发表于 2020-3-31 09:48:47 | 显示全部楼层
我来说一下自己做的按键
按键扫描采用10ms状态机处理,该按键扫描分按下消抖,短按,连续长按,普通长按,释放消抖等,上电后首先是进入状态0处理,后面根据相应的状态处理。该按键扫描方式比较简单,把相应的按键值填入就可以,想要短按还是长按等按键,就填入相应的值就可以了

QQ图片20200331094646.png
QQ图片20200331094629.png
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
 楼主| 发表于 2020-3-31 10:34:40 | 显示全部楼层
tianyekpsex 发表于 2020-3-31 09:48
我来说一下自己做的按键
按键扫描采用10ms状态机处理,该按键扫描分按下消抖,短按,连续长按,普通长按, ...

ADC方式也非常好,方便贴下按键这部分的原理图不
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
 楼主| 发表于 2020-3-31 10:35:26 | 显示全部楼层
tianyekpsex 发表于 2020-3-31 09:48
我来说一下自己做的按键
按键扫描采用10ms状态机处理,该按键扫描分按下消抖,短按,连续长按,普通长按, ...

方便的话,可以单独开一个帖子,非常具有参考价值
回复

使用道具 举报

18

主题

321

回帖

375

积分

高级会员

积分
375
发表于 2020-4-2 09:07:12 | 显示全部楼层
tianyekpsex 发表于 2020-3-31 09:48
我来说一下自己做的按键
按键扫描采用10ms状态机处理,该按键扫描分按下消抖,短按,连续长按,普通长按, ...

期待大佬的分享
回复

使用道具 举报

5

主题

132

回帖

147

积分

初级会员

积分
147
发表于 2020-5-25 12:04:29 | 显示全部楼层
按键在中断中检测,变量什么的不需要定义为volatile吗?我记得之前看的说是中断中修改的全局变量最好用volatile修饰
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
 楼主| 发表于 2020-5-25 16:03:51 | 显示全部楼层
无关风月 发表于 2020-5-25 12:04
按键在中断中检测,变量什么的不需要定义为volatile吗?我记得之前看的说是中断中修改的全局变量最好用vola ...

中断里面调用的是bsp_PutKey,修改的是Write变量,而中断外调用的是bsp_GetKey,修改是的bsp_GetKey。

可以考虑给Write加上个,不过加不加也没影响,因为这种FIFO处理,及时当前读取不是中断修改的最新值,下次读取判断也可以。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-29 11:45 , Processed in 0.363452 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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