蓝桥杯STM32G431RBT6学习——按键
前言
按键同样为每年的必考考点,国信长天开发板中的按键电路如下:
芯片的PA0、PB0、PB1、PB2作为按键输入引脚,并采用外部上拉连接,当对应引脚检测到低电平时,即按键被按下。
STM32CubeMX配置
时钟配置不变,将以上引脚配置为输入模式,并设置其上拉模式。
Keil代码编写
关于按键的常用API如下:
读取IO口电平
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
参数1:IO口所在组;
参数2:IO口引脚号
整体控制
关于按键的使用,主要使用的方式有单击、长按,众所周知硬件按键按下时都会产生一定的抖动,因此需要延时消抖处理。为了程序重复执行,可以在代码算法上将其分为两个状态进行判断,即按键按下与按键松开。
(1)单击
对于单击而言,只需要区分一次按键按下松开即可,在程序中设置一个标志位用于判断按键的状态(初始化为0),当按键按下时,判断读取电平是否为低电平,同时标志位需要为0,方才认为按键按下,并将标志位置1;当按键松开时,判断读取电平为高电平,同时标志位需要为1(曾经按下过),方才认为按键松开了,并将标志位置0。
代码如下:
/****************
函数功能:按键单击读取函数
函数参数:无
函数返回值:按下的按键键值,KeyB1~KeyB4->a~d
****************/
uchar key_Scan(void)
{
static uchar K1_flag,K2_flag,K3_flag,K4_flag;
if(KeyB1 == GPIO_PIN_RESET && K1_flag == 0)
{
HAL_Delay(5);
if(KeyB1 == GPIO_PIN_RESET && K1_flag == 0)
{
K1_flag = 1;
return 'a';
}
}
else if(KeyB1 == GPIO_PIN_SET && K1_flag == 1)
K1_flag = 0;
if(KeyB2 == GPIO_PIN_RESET && K2_flag == 0)
{
HAL_Delay(5);
if(KeyB2 == GPIO_PIN_RESET && K2_flag == 0)
{
K2_flag = 1;
return 'b';
}
}
else if(KeyB2 == GPIO_PIN_SET && K2_flag == 1)
K2_flag = 0;
if(KeyB3 == GPIO_PIN_RESET && K3_flag == 0)
{
HAL_Delay(5);
if(KeyB3 == GPIO_PIN_RESET && K3_flag == 0)
{
K3_flag = 1;
return 'c';
}
}
else if(KeyB3 == GPIO_PIN_SET && K3_flag == 1)
K3_flag = 0;
if(KeyB4 == GPIO_PIN_RESET && K4_flag == 0)
{
HAL_Delay(5);
if(KeyB4 == GPIO_PIN_RESET && K4_flag == 0)
{
K4_flag = 1;
return 'd';
}
}
else if(KeyB4 == GPIO_PIN_SET && K4_flag == 1)
K4_flag = 0;
return 0;
}
通过读取函数返回值即可判断按键是否按下。
(2)长按
对于长按而言,字面意思就是按下按键达到一段时间后才会触发按键的功能,因此毫无疑问最简单粗暴的方法就是当按键按下时用延时进行阻塞,一段时间后再检测按键是否还是按下即可分辨是否属于长按。
代码如下:
if(KeyB1 == GPIO_PIN_RESET && K1_flag == 0)
{
HAL_Delay(5);
if(KeyB1 == GPIO_PIN_RESET && K1_flag == 0)
{
HAL_Delay(500);
if(KeyB1 == GPIO_PIN_RESET && K1_flag == 0)
{
K1_flag = 1;
return 'a';
}
}
}
但是这种方法存在弊端:1、严重影响系统运行,一般长按的时间都较长(500ms以上),对于单片机而言如此长的时间不干活是严重的资源浪费;2、难以实现多种按键并存,当一个按键既需要长按又需要短按的时候,这种方法就会很尴尬。
解决方法:后续使用定时器进行辅助按键功能的实现。