当按下一个按键时,系统是如何检测到的呢?
我们通过LED灯的亮灭状态来间接完成按键检测。当按下按键时,LED灯亮,再次按下时,LED灯灭。
要完成这个实验,我们就会用到GPIO外设的基本输入功能。
查阅开发板的按键原理图,如图3-1。
图3-1
图中的K1、K2即为按键。以K1为例,当未按下按键时,其PA0引脚处于接地状态,即低电平,按下按键时,引脚接到电源,输入状态为高电平。所以只要我们检测按键对应引脚(这里是PA0)的输入电平状态,即可判断按键是否被按下。这便是按键的检测原理了。
有一点需要知道,由于机械按键的弹性作用,按下按键时并不会马上稳定接通或断开,即存在按键抖动。一般情况下我们需要通过软件或硬件的方式消抖才能得到理想的实验效果。软件消抖如通过定时器延时等方式,忽略前后的抖动;而硬件消抖,如可以利用电容的充放电延时等方式。本文默认已经进行过消抖处理了。
直接开始编程环节的分析。
首先得使能GPIO端口的时钟,然后初始化按键和LED灯的引脚,最后通过读取引脚不同电平状态控制LED灯的状态切换。这便是这个实验的大致步骤了。
使能GPIO端口时钟
所有的GPIO外设都挂载在APB2总线上,所以其使能寄存器为RCC_APB2ENR,查阅固件库手册可得其固件函数为RCC_APB2PeriphClockCmd(该固件函数功能即为对RCC_APB2ENR寄存器操作的封装)。我们需要使能的是GPIOA时钟,所以可调用如下API实现使能时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
初始化按键和LED灯
在使能GPIOA时钟后,便开始初始化按键和LED灯了。我们需要用到GPIO_Init固件函数(该函数实现对配置引脚模式的封装),将引脚配置为浮空输入模式。这一步我们可以写一个函数将其封装起来。如下代码:
/**
* @brief 初始化按键
* @param 无
* @retval 无
*/
void Key_GPIO_Config(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 选择按键引脚PA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 设置引脚模式为浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化按键
}
注:IO口为输入模式时,不用设置输出速率。
同样的,由于我们需要通过LED灯来间接完成按键检测(这里我们使用的是RGB灯,使用G色的引脚PB0),所以以上步骤也需要对LED灯的PB0引脚重复一遍,其流程与按键初始化流程类似,这里就不再赘述了,读者可参考按键流程完成。
检测按键状态
接下来就需要通过检测按键引脚的电平状态来判断按键是否按下了。那么我们怎么获取引脚的电平状态呢,查阅参考手册可知,我们可以通过读取IDR寄存器的值来获取。而这个操作同样被STM32固件库封装了,其函数名为GPIO_ReadInputDataBit。查看源码,其正是对IDR寄存器操作的封装,如下图3-2所示。
图3-2
其最终会返回引脚的电平状态,即返回1(高电平),返回0(低电平)。代码里“Bit_RESET”和“Bit_SET”已经通过枚举方式定义了,Bit_RESET=0(低电平),Bit_SET=1(高电平)。最后我们通过判断函数返回值完成按键检测。若按键按下,则引脚输出高电平。我们将该检测过程也封装为一个函数Key_DETECTOR,具体如下:
/**
* @brief 检测按键状态
* @param GPIOx:x可以是A, B, C, D, E
* GPIO_Pin:对应引脚序号
* @retval 1(高电平,即按下按键)、0(低电平,即没有按下按键)
*/
uint8_t Key_DETECTOR(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin){
uint16_t keyState = GPIO_ReadInputDataBit(GPIOx, GPIO_Pin);
/* 检测是否按下按键 */
if(keyState){
return 1;
}else{
return 0;
}
}
万事俱备,只欠东风,我们终于可以开始写main函数了。main函数里,需要逐步调用以上所述的API,完成实验功能。直接上代码:
// 定义控制LED的引脚
#define LED_TOGGLE LED_Control(GPIOB, GPIO_Pin_0)
// 使用带参宏输出LED灯的另一种状态
#define LED_Control(GPIOx, GPIO_Pin) {GPIOx->ODR ^= GPIO_Pin;}
int main(void){
uint8_t SaveStatus = 0;
uint8_t State;
LED_GPIO_Config();
Key_GPIO_Config();
while(1)
{
State = Key_DETECTOR(GPIOA, GPIO_Pin_0);
if(SaveStatus != State)
{
if(State == 1)
{
LED_TOGGLE;
}
SaveStatus = State;
}
}
}
至此,我们的按键检测实验也分析完成了。
转自知乎。
原文地址:https://www.cnblogs.com/fire909090/p/8874335.html