赞
踩
几乎每个开发板都会板载有独立按键,因为按键用处很多。常态下,独立按键是断开的,
按下的时候才闭合。每个独立按键会单独占用一个 IO 口,通过 IO 口的高低电平判断按键的状
态。但是按键在闭合和断开的时候,都存在抖动现象,即按键在闭合时不会马上就稳定的连接,
断开时也不会马上断开。这是机械触点,无法避免。独立按键抖动波形图如下:
图中的按下抖动和释放抖动的时间一般为 5~10ms,如果在抖动阶段采样,其不稳定状态可能出现一次按键动作被认为是多次按下的情况。为了避免抖动可能带来的误操作,我们要做的措施就是给按键消抖(即采样稳定闭合阶段)。消抖方法分为硬件消抖和软件消抖,我们常用软件的方法消抖。
软件消抖:方法很多,我们例程中使用最简单的延时消抖。检测到按键按下后,一般进行10ms 延时,用于跳过抖动的时间段,如果消抖效果不好可以调整这个 10ms 延时,因为不同类型的按键抖动时间可能有偏差。待延时过后再检测按键状态,如果没有按下,那我们就判断这是抖动或者干扰造成的;如果还是按下,那么我们就认为这是按键真的按下了。对按键释放的判断同理。
硬件消抖:利用 RC 电路的电容充放电特性来对抖动产生的电压毛刺进行平滑出来,从而实现消抖,但是成本会更高一点,本着能省则省的原则,我们推荐使用软件消抖即可。
本实验我们将会用到 GPIO 端口输入数据寄存器,下面来介绍一下。该寄存器用于存储 GPIOx 的输入状态,它连接到施密特触发器上,IO 口外部的电平信号经过触发器后,模拟信号就被转化成 0 和 1 这样的数字信号,并存储到该寄存器中。寄存器描述如图所示
该寄存器低 16 位有效,分别对应每一组 GPIO 的 16 个引脚。当 CPU 访问该寄存器,如果对应的某位为 0(IDRy=0),则说明该 IO 口输入的是低电平,如果是 1(IDRy=1),则表示输入的是高电平,y=0~15。
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 引脚的
高低电平,从而实现按键检测了。
- int main(void)
- {
- uint8_t key;
-
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
- delay_init(72); /* 延时初始化 */
- led_init(); /* 初始化LED */
- key_init(); /* 初始化按键 */
- beep_init(); /* 初始化蜂鸣器 */
- LED0(0); /* 先点亮LED0 */
-
- while(1)
- {
- key = key_scan(0); /* 得到键值 */
-
- if (key)
- {
- switch (key)
- {
- case WKUP_PRES: /* 控制蜂鸣器 */
- BEEP_TOGGLE(); /* BEEP状态取反 */
- break;
-
- case KEY2_PRES: /* 控制LED0(RED)翻转 */
- LED0_TOGGLE(); /* LED0状态取反 */
- break;
-
- case KEY1_PRES: /* 控制LED1(GREEN)翻转 */
- LED1_TOGGLE(); /* LED1状态取反 */
- break;
-
- case KEY0_PRES: /* 同时控制LED0, LED1翻转 */
- LED0_TOGGLE(); /* LED0状态取反 */
- LED1_TOGGLE(); /* LED1状态取反 */
- break;
- }
- }
- else
- {
- delay_ms(10);
- }
- }
- }
-
- /**
- * @brief 按键初始化函数
- * @param 无
- * @retval 无
- */
- void key_init(void)
- {
- GPIO_InitTypeDef gpio_init_struct;
- KEY0_GPIO_CLK_ENABLE(); /* KEY0时钟使能 */
- KEY1_GPIO_CLK_ENABLE(); /* KEY1时钟使能 */
- KEY2_GPIO_CLK_ENABLE(); /* KEY2时钟使能 */
- WKUP_GPIO_CLK_ENABLE(); /* WKUP时钟使能 */
-
- gpio_init_struct.Pin = KEY0_GPIO_PIN; /* KEY0引脚 */
- gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
- HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_init_struct); /* KEY0引脚模式设置,上拉输入 */
-
- gpio_init_struct.Pin = KEY1_GPIO_PIN; /* KEY1引脚 */
- gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
- HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_init_struct); /* KEY1引脚模式设置,上拉输入 */
-
- gpio_init_struct.Pin = KEY2_GPIO_PIN; /* KEY2引脚 */
- gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
- HAL_GPIO_Init(KEY2_GPIO_PORT, &gpio_init_struct); /* KEY2引脚模式设置,上拉输入 */
-
- gpio_init_struct.Pin = WKUP_GPIO_PIN; /* WKUP引脚 */
- gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
- gpio_init_struct.Pull = GPIO_PULLDOWN; /* 下拉 */
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
- HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_init_struct); /* WKUP引脚模式设置,下拉输入 */
-
- }
-
- /**
- * @brief 按键扫描函数
- * @note 该函数有响应优先级(同时按下多个按键): WK_UP > KEY2 > KEY1 > KEY0!!
- * @param mode:0 / 1, 具体含义如下:
- * @arg 0, 不支持连续按(当按键按下不放时, 只有第一次调用会返回键值,
- * 必须松开以后, 再次按下才会返回其他键值)
- * @arg 1, 支持连续按(当按键按下不放时, 每次调用该函数都会返回键值)
- * @retval 键值, 定义如下:
- * KEY0_PRES, 1, KEY0按下
- * KEY1_PRES, 2, KEY1按下
- * KEY2_PRES, 3, KEY2按下
- * WKUP_PRES, 4, WKUP按下
- */
- uint8_t key_scan(uint8_t mode)
- {
- static uint8_t key_up = 1; /* 按键按松开标志 */
- uint8_t keyval = 0;
-
- if (mode) key_up = 1; /* 支持连按 */
-
- if (key_up && (KEY0 == 0 || KEY1 == 0 || KEY2 == 0 || WK_UP == 1)) /* 按键松开标志为1, 且有任意一个按键按下了 */
- {
- delay_ms(10); /* 去抖动 */
- key_up = 0;
-
- if (KEY0 == 0) keyval = KEY0_PRES;
-
- if (KEY1 == 0) keyval = KEY1_PRES;
-
- if (KEY2 == 0) keyval = KEY2_PRES;
-
- if (WK_UP == 1) keyval = WKUP_PRES;
- }
- else if (KEY0 == 1 && KEY1 == 1 && KEY2 == 1 && WK_UP == 0) /* 没有任何按键按下, 标记按键松开 */
- {
- key_up = 1;
- }
-
- return keyval; /* 返回键值 */
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。