配置
- 电路原理图
- cubeMX
由上图可知,PB0,PB1,PB2,PA0 对应按键 B1,B2,B3,B4。在配置时,将他们设为GPIO_Input(Pull_up上拉输入模式)。
配置定时器(定时器100Hz,即10ms扫描一次按键)
开启中断
程序编写
创建 interrupt.c 和 interrupt.h 文件,主要是用定时器去扫描按键,实现单击、双击、长按
- 使用#define简化程序
在 interrupt.h 文件中编写
#define KB1 HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin)
#define KB2 HAL_GPIO_ReadPin(B2_GPIO_Port, B2_Pin)
#define KB3 HAL_GPIO_ReadPin(B3_GPIO_Port, B3_Pin)
#define KB4 HAL_GPIO_ReadPin(B4_GPIO_Port, B4_Pin)
- 定义结构体
导入 <stdbool.h> 库:在支持C99标准中,新增了关键字_Bool,其值只能为0或1,这样只要导入 stdbool.h ,就能非常方便的使用我们常用的bool false true来操作布尔类型。
在 interrupt.h 中定义结构体
#include "stdbool.h"
struct keys
{
unsigned char judge_sta; //判断key处于什么阶段(消抖、确定、松手)
bool key_sta; //表示读到的值
bool single_flag; //表示单击最终的值
bool long_flag; //表示长按最终的值
unsigned int key_time; //停留时间
};
在 interrupt.c 中重新定义定时器中断回调函数
struct keys key[4]={0,0,0,0};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM4)
{
//依次读取4个按键的状态
key[0].key_sta = KB1;
key[1].key_sta = KB2;
key[2].key_sta = KB3;
key[3].key_sta = KB4;
for (int i=0; i<4; i++)
{
switch (key[i].judge_sta)
{
//消抖
case 0:
if (key[i].key_sta == 0)
key[i].judge_sta == 1;
key[i].key_time = 0;
break;
case 1:
if (key[i].key_sta == 0) //确定为稳定状态
{
key[i].judge_sta == 2;
}else //按键未被按下
{
key[i].judge_sta == 0;
}
break;
//松手
case 2:
if (key[i].key_sta == 1)
{
key[i].judge_sta == 0;
if (key[i].key_time <= 70) //单击
{
key[i].single_flag == 1;//松开再确认
}
}else
{
key[i].key_time++;
if (key[i].key_time > 70) //长按
{
key[i].long_flag == 1;
}
}
break;
}
}
}
}
- 初始化
在main函数里,/* USER CODE BEGIN 2 * /和/ * USER CODE END 2 */之间初始化
HAL_TIM_Base_Start_IT(&htim4);
在main.c 文件中编写一个按键处理对应操作的函数(要声明)
void key_proc(void)
{
if(keys[0].single_flag == 1) //B1单击屏幕切换
{
view++;
if (view == 3)
view=0;
keys[0].single_flag = 0; //清除标志位
LCD_Clear(Black); //清屏
}
if(keys[0].long_flag == 1) //B1长按
{
keys[0].long_flag = 0;
}
if(keys[1].single_flag == 1) //B2单击
{
keys[1].single_flag = 0;
}
if(keys[2].single_flag == 1) //B3单击
{
keys[2].single_flag = 0;
}
if(keys[3].single_flag == 1) //B4单击
{
keys[3].single_flag = 0;
}
}