当前位置:   article > 正文

STM32教程——按键输入_stm32按键输入

stm32按键输入

按键与输入数据寄存器简介

独立按键简介


几乎每个开发板都会板载有独立按键,因为按键用处很多。常态下,独立按键是断开的,
按下的时候才闭合。每个独立按键会单独占用一个 IO 口,通过 IO 口的高低电平判断按键的状
态。但是按键在闭合和断开的时候,都存在抖动现象,即按键在闭合时不会马上就稳定的连接,
断开时也不会马上断开。这是机械触点,无法避免。独立按键抖动波形图如下:

        图中的按下抖动和释放抖动的时间一般为 5~10ms,如果在抖动阶段采样,其不稳定状态可能出现一次按键动作被认为是多次按下的情况。为了避免抖动可能带来的误操作,我们要做的措施就是给按键消抖(即采样稳定闭合阶段)。消抖方法分为硬件消抖和软件消抖,我们常用软件的方法消抖。
软件消抖:方法很多,我们例程中使用最简单的延时消抖。检测到按键按下后,一般进行10ms 延时,用于跳过抖动的时间段,如果消抖效果不好可以调整这个 10ms 延时,因为不同类型的按键抖动时间可能有偏差。待延时过后再检测按键状态,如果没有按下,那我们就判断这是抖动或者干扰造成的;如果还是按下,那么我们就认为这是按键真的按下了。对按键释放的判断同理。
硬件消抖:利用 RC 电路的电容充放电特性来对抖动产生的电压毛刺进行平滑出来,从而实现消抖,但是成本会更高一点,本着能省则省的原则,我们推荐使用软件消抖即可。


GPIO  端口输入数据寄存器(IDR )


本实验我们将会用到 GPIO 端口输入数据寄存器,下面来介绍一下。该寄存器用于存储 GPIOx 的输入状态,它连接到施密特触发器上,IO 口外部的电平信号经过触发器后,模拟信号就被转化成 0 和 1 这样的数字信号,并存储到该寄存器中。寄存器描述如图所示

该寄存器低 16 位有效,分别对应每一组 GPIO 的 16 个引脚。当 CPU 访问该寄存器,如果对应的某位为 0(IDRy=0),则说明该 IO 口输入的是低电平,如果是 1(IDRy=1),则表示输入的是高电平,y=0~15。

GPIO  输入 配置步骤


1 )使能应 对应 GPIO  时钟
本实验用到 PA0 和 PE2/3/4 等四个 IO 口,因此需要先使能 GPIOA 和 GPIOE 的时钟,代码
如下:
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
2) )应 设置对应 GPIO  工作模式(上拉/ 下拉 输入) )
本实验 GPIO 使用输入模式(带上拉/下拉),从而可以读取 IO 口的状态,实现按键检测,
GPIO 模式通过函数 HAL_GPIO_Init 设置实现。
3) )取 读取 GPIO  引脚 高低电平
在配置好 GPIO 工作模式后,我们就可以通过 HAL_GPIO_ReadPin 函数读取 GPIO 引脚的
高低电平,从而实现按键检测了。

  1. int main(void)
  2. {
  3. uint8_t key;
  4. HAL_Init(); /* 初始化HAL库 */
  5. sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  6. delay_init(72); /* 延时初始化 */
  7. led_init(); /* 初始化LED */
  8. key_init(); /* 初始化按键 */
  9. beep_init(); /* 初始化蜂鸣器 */
  10. LED0(0); /* 先点亮LED0 */
  11. while(1)
  12. {
  13. key = key_scan(0); /* 得到键值 */
  14. if (key)
  15. {
  16. switch (key)
  17. {
  18. case WKUP_PRES: /* 控制蜂鸣器 */
  19. BEEP_TOGGLE(); /* BEEP状态取反 */
  20. break;
  21. case KEY2_PRES: /* 控制LED0(RED)翻转 */
  22. LED0_TOGGLE(); /* LED0状态取反 */
  23. break;
  24. case KEY1_PRES: /* 控制LED1(GREEN)翻转 */
  25. LED1_TOGGLE(); /* LED1状态取反 */
  26. break;
  27. case KEY0_PRES: /* 同时控制LED0, LED1翻转 */
  28. LED0_TOGGLE(); /* LED0状态取反 */
  29. LED1_TOGGLE(); /* LED1状态取反 */
  30. break;
  31. }
  32. }
  33. else
  34. {
  35. delay_ms(10);
  36. }
  37. }
  38. }
  39. /**
  40. * @brief 按键初始化函数
  41. * @param 无
  42. * @retval 无
  43. */
  44. void key_init(void)
  45. {
  46. GPIO_InitTypeDef gpio_init_struct;
  47. KEY0_GPIO_CLK_ENABLE(); /* KEY0时钟使能 */
  48. KEY1_GPIO_CLK_ENABLE(); /* KEY1时钟使能 */
  49. KEY2_GPIO_CLK_ENABLE(); /* KEY2时钟使能 */
  50. WKUP_GPIO_CLK_ENABLE(); /* WKUP时钟使能 */
  51. gpio_init_struct.Pin = KEY0_GPIO_PIN; /* KEY0引脚 */
  52. gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
  53. gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
  54. gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
  55. HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_init_struct); /* KEY0引脚模式设置,上拉输入 */
  56. gpio_init_struct.Pin = KEY1_GPIO_PIN; /* KEY1引脚 */
  57. gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
  58. gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
  59. gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
  60. HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_init_struct); /* KEY1引脚模式设置,上拉输入 */
  61. gpio_init_struct.Pin = KEY2_GPIO_PIN; /* KEY2引脚 */
  62. gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
  63. gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
  64. gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
  65. HAL_GPIO_Init(KEY2_GPIO_PORT, &gpio_init_struct); /* KEY2引脚模式设置,上拉输入 */
  66. gpio_init_struct.Pin = WKUP_GPIO_PIN; /* WKUP引脚 */
  67. gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
  68. gpio_init_struct.Pull = GPIO_PULLDOWN; /* 下拉 */
  69. gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
  70. HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_init_struct); /* WKUP引脚模式设置,下拉输入 */
  71. }
  72. /**
  73. * @brief 按键扫描函数
  74. * @note 该函数有响应优先级(同时按下多个按键): WK_UP > KEY2 > KEY1 > KEY0!!
  75. * @param mode:0 / 1, 具体含义如下:
  76. * @arg 0, 不支持连续按(当按键按下不放时, 只有第一次调用会返回键值,
  77. * 必须松开以后, 再次按下才会返回其他键值)
  78. * @arg 1, 支持连续按(当按键按下不放时, 每次调用该函数都会返回键值)
  79. * @retval 键值, 定义如下:
  80. * KEY0_PRES, 1, KEY0按下
  81. * KEY1_PRES, 2, KEY1按下
  82. * KEY2_PRES, 3, KEY2按下
  83. * WKUP_PRES, 4, WKUP按下
  84. */
  85. uint8_t key_scan(uint8_t mode)
  86. {
  87. static uint8_t key_up = 1; /* 按键按松开标志 */
  88. uint8_t keyval = 0;
  89. if (mode) key_up = 1; /* 支持连按 */
  90. if (key_up && (KEY0 == 0 || KEY1 == 0 || KEY2 == 0 || WK_UP == 1)) /* 按键松开标志为1, 且有任意一个按键按下了 */
  91. {
  92. delay_ms(10); /* 去抖动 */
  93. key_up = 0;
  94. if (KEY0 == 0) keyval = KEY0_PRES;
  95. if (KEY1 == 0) keyval = KEY1_PRES;
  96. if (KEY2 == 0) keyval = KEY2_PRES;
  97. if (WK_UP == 1) keyval = WKUP_PRES;
  98. }
  99. else if (KEY0 == 1 && KEY1 == 1 && KEY2 == 1 && WK_UP == 0) /* 没有任何按键按下, 标记按键松开 */
  100. {
  101. key_up = 1;
  102. }
  103. return keyval; /* 返回键值 */
  104. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/527060
推荐阅读
相关标签
  

闽ICP备14008679号