蓝桥杯嵌入式按键长短按移植
1、外设占用,基本定时器1个,配置为10ms中断
初始化后,打开中断。
HAL_TIM_Base_Start_IT(&htim4);//打开定时器中断
2、按键代码
key.c
:
#include "key.h"
#include "oled.h"
struct keys g_key[4] = {0,0,0,0};
/**
* @brief 按键扫描函数,需要10ms执行一次
*
*/
void key_scan(void)
{
//读取本次扫描电平状态
g_key[0].state_pin = HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin);
g_key[1].state_pin = HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
g_key[2].state_pin = HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin);
g_key[3].state_pin = HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin);
//轮询按键消抖
for(int i=0;i<4;i++)
{
switch(g_key[i].state_step)
{
case 0://首次按下
{
if(g_key[i].state_pin == 0)
{
g_key[i].state_step = 1; //跳转到消抖状态
g_key[i].time_press = 0; //清零计时
}
}
break;
case 1://10ms后按键仍按下,说明电平已稳定,完成消抖
{
if(g_key[i].state_pin == 0)
{
// g_key[i].flag_press = 1; //记录短按生效
g_key[i].state_step = 2; //跳转到松手检测
}
else
g_key[i].state_step = 0; //否则视为抖动,重新检测
}
break;
case 2://读取到松手,本次扫描结束
{
if(g_key[i].state_pin == 1)//松手
{
if(g_key[i].time_press < 100)//小于1s视为短按
{
g_key[i].flag_press = 1;//短按松手生效
}
else if(g_key[i].time_press >= 100)//大于1s视为长按
{
g_key[i].flag_press_long = 1;//长按松手生效
}
g_key[i].state_step = 0; //回到最初状态
}
else
{
g_key[i].time_press++;//未松手就计时
// if(g_key[i].time_press >= 100)
// g_key[i].flag_press_long = 1;//长按未松手生效,放在这里会由bug,按完不松手会与key_proc里的清零一直冲突,相当于长按一直生效
}
}
break;
}
}
}
/**
* @brief 按键动作处理函数,响应按键动作
*
*/
void key_proc(void)
{
static uint8_t a = 0;
static uint8_t b = 0;
if(g_key[0].flag_press == 1)//按键1动作处理
{
OLED_ShowNum(0,0,a++,3,16,1);
OLED_Refresh();
g_key[0].flag_press = 0;//记住用完后一定要清零,才能继续使用
}
if(g_key[0].flag_press_long == 1)//按键1动作处理
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
g_key[0].flag_press_long = 0;//记住用完后一定要清零,才能继续使用
}
if(g_key[1].flag_press == 1)//按键2动作处理
{
OLED_ShowNum(0,16,b++,3,16,1);
OLED_Refresh();
g_key[1].flag_press = 0;//记住用完后一定要清零,才能继续使用
}
if(g_key[1].flag_press_long == 1)//按键2动作处理
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
g_key[1].flag_press_long = 0;//记住用完后一定要清零,才能继续使用
}
}
key.h
:
#ifndef __KEY_H
#define __KEY_H
#include "main.h"
struct keys
{
uint8_t state_step; //判断进程
uint8_t state_pin; //按键电平状态
uint8_t flag_press; //按键按下标志位
uint16_t time_press; //记录按下时间*10ms
uint8_t flag_press_long; //长按标志位
};
extern struct keys g_key[];
void key_scan(void);
void key_proc(void);
#endif
定时器中断
:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4)//10ms按键扫描
{
key_scan();
}
}
main.c
:
while (1)
{
key_proc();
}