在我们学习STM32的过程中,按键是一个非常重要且必须要掌握的一个板块。下面小编就带大家进入按键模块吧!
一、原理说明
看到上面的原理图,想必大家已经知道该块STM32开发板的按键按下后的返回值应该是0。由于该开发板的按键数量比较少,因此我们直接使用switch即可判断某一个按键是否按下 。
二、部分库函数解析
1、GPIO_ReadInputDataBit函数
2、GPIO_ReadInputData函数
三、代码解析
1、枚举变量与全局变量
c
//定义变量 存储上次按键按下的值
unsigned char key_old;
//枚举按键但是KEY0是无效的 为了匹配现实中开发板按键的位置而设立
enum KEY_NUM{KEY0,KEY1,KEY2,KEY3,KEY4,KEY5};
2、GPIO初始化
在GPIO初始换中,我们只需要打开GPIOE时钟,选择GPIO引脚、GPIO的频率、GPIO的模式即可。
c
/*
* @brief The initialization of the button GPIO(按键GPIO的初始化)
* @param none
* @retval none
*/
void key_GPIO_init(void)
{
//声明一个结构体,用于初始化GPIO
GPIO_InitTypeDef GPIO_InitStructure;
//开启GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
//选择GPIO的引脚为Pin0,Pin2,Pin3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
//设置GPIO的速度为50MHz
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//将GPIO引脚设置成上拉输入模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
//GPIOE引脚的初始化
GPIO_Init(GPIOE,&GPIO_InitStructure);
}
3、按键扫描函数1
小编个人认为按键扫描函数1相对于按键扫描函数2来说,更容易理解,建议大家看懂扫描函数1后再去看扫描函数2。
c
/*
* @brief Determine whether the button is pressed(判断某一个按键是否按下)
* @param KEY_NUM:one of a button(其中一个按键)
* @retval key_num:Back to judgment status 0-pressed 1-not pressed(返回判断的状态 0-未按下 1-按下)
*/
int get_key(int KEY_NUM)
{
//待判断按键的返回状态 0-表示按下 1-表示松开
int key_num = 3;
switch(KEY_NUM){
//判断key1
case KEY1: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_0);break;
//判断key2
case KEY2: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_1);break;
//判断key3
case KEY3: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2);break;
//判断key4
case KEY4: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3);break;
//判断key5
case KEY5: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6);break;
//屏蔽可能出现的干扰
default: break;
}
return key_num;
}
4、按键服务函数1
这里的按键服务函数小编以点亮开发板上的LED灯为例。(想看小编的点亮LED函数可通过链接前往------STM32-八位流水灯)
c
/*
* @brief scan the button and perform the corresponding function which is Press and light up or loosen and go out
* (扫描按键并且执行相应的功能)
* @param none
* @retval none
*/
void scan_key(void)
{
if(get_key(KEY1) == 0){//按下key1点亮LED1
LED_ctrl(LED1,LED_ON);
}else{//松开key1熄灭LED1
LED_ctrl(LED1,LED_OFF);
}
if(get_key(KEY2) == 0){//按下key2点亮LED2
LED_ctrl(LED2,LED_ON);
}else{//松开key2熄灭LED2
LED_ctrl(LED2,LED_OFF);
}
if(get_key(KEY3) == 0){//按下key3点亮LED3
LED_ctrl(LED3,LED_ON);
}else{//松开key3熄灭LED3
LED_ctrl(LED3,LED_OFF);
}
if(get_key(KEY4) == 0){//按下key4点亮LED4
LED_ctrl(LED4,LED_ON);
}else{//松开key4熄灭LED4
LED_ctrl(LED4,LED_OFF);
}
if(get_key(KEY5) == 0){//按下key5点亮LED5
LED_ctrl(LED5,LED_ON);
}else{//松开key5熄灭LED5
LED_ctrl(LED5,LED_OFF);
}
//熄灭无关的LED6、LED7、LED8
LED_ctrl(LED6,LED_OFF);
LED_ctrl(LED7,LED_OFF);
LED_ctrl(LED8,LED_OFF);
}
5、按键扫描函数2
小编个人认为,尽管扫描函数2比扫描函数1跟不容易理解,但是小编更加青睐它。
c
/*
* @brief scan the button and back to the value
* @param none
* @retval key_val:Back to key number which was pressed(返回被按下按键的值)
*/
unsigned char scan_kbd(void)
{
//定义一个返回值
unsigned char key_val = 0;
//扫描按键的引脚
unsigned int key_press = GPIO_ReadInputData(GPIOE);
//排除其他引脚的影响
key_press = key_press|0xffb0;
//判断按键是否按下
switch(key_press)
{
//KEY1按下
case 0xfffe: key_val = 1;break;
//KEY2按下
case 0xfffd: key_val = 2;break;
//KEY3按下
case 0xfffb: key_val = 3;break;
//KEY4按下
case 0xfff7: key_val = 4;break;
//KEY5按下
case 0xffbf: key_val = 5;break;
//所有按键都没按下或者其他可能出现的干扰
default: key_val = 0;break;
}
return key_val;
}
6、按键服务函数2
这里小编是以数码管显示数值为实例的。相对于服务函数1而言,小编在服务函数2中加上了按键消抖、按键松开、按键按下这三个功能。其实这里的按键扫描函数使用函数1应该也是能够达到该效果的,不过小编没有尝试。(小编这里有数码管刷新的具体函数,可前往链接------STM32-刷新数码管)
c
/*
* @brief perform the corresponding function which is Press(执行按键按下后的执行相应的函数)
* @param none
* @retval none
*/
void key_por(void)
{
static unsigned int number = 0;
//定义变量 存储案件是否松开、按下的值
unsigned char key_up,key_down;
//按键扫描
unsigned int key_num = scan_kbd();
//获取按键是否按下
key_down = key_num & (key_old ^ key_num);
//获取按键是否松开
key_up = ~key_num & (key_old ^ key_num);
//保存本次按键的值
key_old = key_num;
if(key_down){//按键消抖 每次只有按键按下后number的值才会加1
number++;
}
segbuff[0] = key_num;
segbuff[1] = key_down;
segbuff[2] = key_up;
segbuff[3] = key_old;
segbuff[5] = number;
}
四、总结
STM32F103ZET6开发板的按键数量相对较少,实现按键扫描函数相对简单。 在我们写按键扫描函数时,第一步需要查阅原理图,观察按键的排列方式;第二步,判断扫描按键使用的方法,即是否需要使用行列扫描法扫描函数,若不需要(也就是按键数量较少、排列简单的前提下)我们可以直接使用switch判断按键是否按下;第三步,若有需要,可以完善按键的功能。