按键判断单击、双击、长按【STM32】
本次实验使用的是蓝桥杯嵌入式大赛的指定开发板,STM32G431R8T6。
下面为CubeMX和代码部分
CubeMX配置
将按键引脚设置为双边沿中断触发模式,并设置上拉电阻。
定时器本次选择TIM3,选择内部时钟源,设置PSC为80-1,COUNTER Period为1000-1,实现1ms定时(频率为80MHz)
并打开定时器中断。
Key.c
#include "key.h"
/* 3个按键的结构体定义 */
key_data keys[3]={0};
/* 按键中断回调函数 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY1_Pin) //此时按键1被按下
{
static unsigned int old_time = 0;
unsigned int new_time = HAL_GetTick();
/* 消抖 */
if(new_time - old_time < DEBOUNCE)
return ;
old_time = new_time;
/* 按键被按下 */
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
{
if(keys[0].key_state == FREE) /* 如果现在按键未被按下 */
{
keys[0].key_state = PRESSED; /* 现在已经第一次按下,等待松手 */
keys[0].waitetime = new_time; /* 保存当前情况的时间节点 */
}
else if(keys[0].key_state == WAIT_DOUBLE){ /* 按键现在状态处于等待第二次按下时候 */
keys[0].key_result = TWICE; /* 按键第二次按下,按键最终状态为双击 */
keys[0].key_state = FREE;
}
}
else{ /* 按键因上升沿产生的中断,按键松开 */
if(keys[0].key_state == PRESSED)
{
keys[0].key_state = WAIT_DOUBLE; /* 将当前状态值设置为等待第二次按下 */
keys[0].waitetime = new_time;
}
}
}
else if(GPIO_Pin == KEY2_Pin) //此时按键2被按下
{
}
else if(GPIO_Pin == KEY3_Pin) //此时按键3被按下
{
}
}
/* 按键状态判断函数,每1ms调用一次 */
void key_process(void)
{
unsigned char i;
unsigned int time;
time = HAL_GetTick();
for(i=0 ; i<3 ; i++)
{
switch(keys[i].key_state){
case PRESSED: /* 当按键当前处于按下的时候进行对应操作 */
if(time - keys[i].waitetime > LONGWAITETIME) /* 当按键保持按下状态1s时 */
{
keys[i].key_result = LONG; /* 按键最终的结果为长按 */
keys[i].key_state = FREE;
}
break;
case WAIT_DOUBLE: /* 当按键处于等待第二次按下的时候进行操作 */
if(time - keys[i].waitetime > DOUBLEWAITETIME)
{
keys[i].key_result = ONCE; /* 按键最终的结果为单击 */
keys[i].key_state = FREE;
}
break;
default:
break;
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3)
{
key_process(); /* 每1ms进入一次 */
}
}
key.h
#ifndef __KEY_H_
#define __KEY_H_
#include "main.h"
#define DEBOUNCE 20
#define LONGWAITETIME 1000
#define DOUBLEWAITETIME 400
/* 按键最后的状态:未按下,单击,双击,空闲 */
typedef enum{
IDLE = 0,
ONCE,
TWICE,
LONG
}keyresult_t;
/* 当前按键的三个状态,未被按下,按下,等待第二次按下 */
typedef enum{
FREE = 0,
PRESSED,
WAIT_DOUBLE
}keystate_t;
/* 按键的信息:按键最后的结果,按键当前的值,等待时间存储 */
typedef struct{
keyresult_t key_result;
keystate_t key_state;
unsigned int waitetime; /* 用于判断长按的时间,和第二次按下的间隔 */
}key_data;
extern key_data keys[3];
/* 函数声明 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
void key_process(void);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
#endif
main函数验证
while (1)
{
switch(keys[0].key_result){
case IDLE:
LCD_DisplayStringLine(Line1, (unsigned char *)" KEY1 IDLE ");
break;
case ONCE:
LCD_DisplayStringLine(Line1, (unsigned char *)" KEY1 ONCE ");
break;
case TWICE:
LCD_DisplayStringLine(Line1, (unsigned char *)" KEY1 TWIC ");
break;
case LONG:
LCD_DisplayStringLine(Line1, (unsigned char *)" KEY1 LONG ");
break;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
主要在main中还需要打开定时器的中断模式,
/*使能定时器1中断*/
HAL_TIM_Base_Start_IT(&htim2);
演示视频
相关文章
【蓝桥杯-嵌入式 STM32】ADC、DAC
本次实验使用的是蓝桥杯嵌入式大赛的指定开发板,STM32G431R8T6。 下面为 CubeMX 和代码部分 CubeMX ADC部分 设置引脚选择ADC模式,对应通道选择“Single-ended”(单端输出)。其他默认即可 DAC部分 DAC选择“仅与外部引脚相连”。 生成代码 ad.c ``` #include "ad.h" /* ADC读取函数 * 参数 A...
【蓝桥杯-嵌入式 STM32】PWM输入捕获,获取频率占空比
本次实验使用的是蓝桥杯嵌入式大赛的指定开发板,STM32G431R8T6。 下面为 CubeMX 和代码部分 CubeMX 选择对应引脚,配置为定时器模式,设置通道一路为“Input Captu direct mode”(输入捕获直接模式用于读取周期)、一路为“Input Captu inindirect mode”(输入捕获间接模式用于计算占空比)。 预分频(PSC)设置为(时钟频率-...
PWM输出——频率占空比可调【STM32】
本次实验使用的是蓝桥杯嵌入式大赛的指定开发板,STM32G431R8T6。 下面为 CubeMX 和代码部分 CubeMX定时器配置部分 选择对应引脚的通道设置为PWM输出模式(不要选择CH\*N)。 以获取一个100Hz,占空比为50的脉冲信号,现在设置时钟频率为80MHz,参数设置中PSC,ARR需要我们自己配置(当然我们后期实现代码修改频率、占空比的时候会修改这些数据)。 公...