微信公众号:小樊Study
关注共同学习,问题或建议,请公众号留言!!!
跑马灯实验我们学习了STM32F4的IO口作为输出的使用,这次我们将向大家介绍如何使用 STM32F4的IO口作为输入用,今天我们将利用开发板的4个按键,来控制开发板的两个LED的亮灭和蜂鸣器的开关。通过本次学习,你将了解到STM32F4的IO口作为输入口的使用方法。
硬件连接
KEY0、KEY1 和 KEY2 是低电平有效的,而 KEY_UP 是高电平有效的,并且外部都没有上下拉电阻,所以,需要在STM32F4内部设置上下拉
软件设计
key.c
1#include "key.h"
2#include "delay.h"
3//////////////////////////////////////////////////////////////////////////////////
4
5
6//按键初始化函数
7void KEY_Init(void)
8{
9
10 GPIO_InitTypeDef GPIO_InitStructure;
11
12 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOA,GPIOE时钟
13
14 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; //KEY0 KEY1 KEY2对应引脚
15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
16 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
17 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
18 GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4
19
20
21 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//WK_UP对应引脚PA0
22 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;//下拉
23 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA0
24
25}
26//按键处理函数
27//返回按键值
28//mode:0,不支持连续按;1,支持连续按;
29//0,没有任何按键按下
30//1,KEY0按下
31//2,KEY1按下
32//3,KEY2按下
33//4,WKUP按下 WK_UP
34//注意此函数有响应优先级,KEY0>KEY1>KEY2>WK_UP!!
35u8 KEY_Scan(u8 mode)
36{
37 static u8 key_up=1;//按键按松开标志
38 if(mode)key_up=1; //支持连按
39 if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
40 {
41 delay_ms(10);//去抖动
42 key_up=0;
43 if(KEY0==0)return 1;
44 else if(KEY1==0)return 2;
45 else if(KEY2==0)return 3;
46 else if(WK_UP==1)return 4;
47 }else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;
48 return 0;// 无按键按下
49}
这段代码包含 2 个函数,void KEY_Init(void)和 u8 KEY_Scan(u8 mode),KEY_Init 是用来初始化按键输入的 IO 口的。实现 PA0、PE2~4 的输入设置
KEY_Scan 函数,则是用来扫描这 4 个 IO 口是否有按键按下。KEY_Scan 函数,支持两种扫描方式,通过 mode 参数来设置。
当 mode 为 0 的时候,KEY_Scan 函数将不支持连续按,扫描某个按键,该按键按下之后必须要松开,才能第二次触发,否则不会再响应这个按键,这样的好处就是可以防止按一次多次触发,而坏处就是在需要长按的时候比较不合适。
当 mode 为 1 的时候,KEY_Scan 函数将支持连续按,如果某个按键一直按下,则会一直返回这个按键的键值,这样可以方便的实现长按检测。
有了 mode 这个参数,大家就可以根据自己的需要,选择不同的方式。这里要提醒大家,因为该函数里面有 static 变量,所以该函数不是一个可重入函数,在有 OS 的情况下,这个大家要留意下。同时还有一点要注意的就是,该函数的按键扫描是有优先级的,最优先的是 KEY0,第二优先的是 KEY1,接着 KEY2,最后是 KEY3(KEY3 对应 KEY_UP 按键)。该函数有返回值,如果有按键按下,则返回非 0 值,如果没有或者按键不正确,则返回 0。
key.h
1#ifndef __KEY_H
2#define __KEY_H
3#include "sys.h"
4
5/*下面方式是通过位带操作方式读取IO*/
6
7#define KEY0 PEin(4) //PE4
8#define KEY1 PEin(3) //PE3
9#define KEY2 PEin(2) //P32
10#define WK_UP PAin(0) //PA0
11
12
13
14#define KEY0_PRES 1
15#define KEY1_PRES 2
16#define KEY2_PRES 3
17#define WKUP_PRES 4
18
19void KEY_Init(void); //IO初始化
20u8 KEY_Scan(u8); //按键扫描函数
21
22#endif
main.c
1#include "sys.h"
2#include "delay.h"
3#include "usart.h"
4#include "led.h"
5#include "beep.h"
6#include "key.h"
7
8
9
10
11int main(void)
12{
13
14 u8 key; //保存键值
15 delay_init(168); //初始化延时函数
16 LED_Init(); //初始化LED端口
17 BEEP_Init(); //初始化蜂鸣器端口
18 KEY_Init(); //初始化与按键连接的硬件接口
19 LED0=0; //先点亮红灯
20 while(1)
21 {
22 key=KEY_Scan(0); //得到键值
23 if(key)
24 {
25 switch(key)
26 {
27 case WKUP_PRES: //控制蜂鸣器
28 BEEP=!BEEP;
29 break;
30 case KEY0_PRES: //控制LED0翻转
31 LED0=!LED0;
32 break;
33 case KEY1_PRES: //控制LED1翻转
34 LED1=!LED1;
35 break;
36 case KEY2_PRES: //同时控制LED0,LED1翻转
37 LED0=!LED0;
38 LED1=!LED1;
39 break;
40 }
41 }else delay_ms(10);
42 }
43
44}
主函数代码比较简单,先进行一系列的初始化操作,然后在死循环中调用按键扫描函数KEY_Scan()扫描按键值,最后根据按键值控制 LED 和蜂鸣器的翻转。
下载验证
在下载完之后,我们可以按 KEY0、KEY1、KEY2和 KEY_UP 来看看 DS0 和 DS1 以及蜂鸣器的变化,是否和我们预期的结果一致?
下面的是我的公众号二维码图片,欢迎关注。
图注:小樊Study