当前位置: 首页 > article >正文

STM32——KEY按键

一、基础工程

1. 查看引脚

B1~B4 对应引脚 为 PB0,PB1,PB2,PA0。按键按下后,接入低电平;抬起后为高电平。

2. CubeMX配置

4个对应引脚配置成 GPIO_Input。

3. 所用HAL库函数

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
  GPIO_PinState bitstatus;

  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));

  if ((GPIOx->IDR & GPIO_Pin) != 0x00U)
  {
    bitstatus = GPIO_PIN_SET;
  }
  else
  {
    bitstatus = GPIO_PIN_RESET;
  }
  return bitstatus;
}

功能:读取引脚电平状态

参数说明:    

GPIOx:端口号 GPIOA,GPIOB,GPIOC    

GPIO_Pin:引脚号 GPIO_PIN_0,GPIO_PIN_1,GPIO_PIN_2 ...

返回值:    

GPIO_PinState PinState:引脚的状态 GPIO_PIN_SET , GPIO_PIN_RESET

4. 编写Key_Scan()函数

uint8_t Key_Scan(void)
{
 uint8_t key_val=0;
//PB0
 if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET)
 {
 key_val=1;
 }
//PB1
 if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==GPIO_PIN_RESET)
 {
 key_val=2;
 }
//PB2
 if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==GPIO_PIN_RESET)
 {
 key_val=3;
 }
//PA0
 if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
 {
 key_val=4;
 }
 return key_val;
}

5. 简单的例子

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		key_val=Key_Scan();
		if(key_val==1)
		{
			ucled ^= 0x01;
		}
		Led_Disp(ucled);
  }

二、按键代码模板

void Key_Proc(void)
{
 key_val = Key_Scan();
 key_down = key_val & (key_val ^ key_old);
 key_up = ~key_val & (key_val ^ key_old);
 key_old = key_val;
 
 if(key_down==1)//1~4
 {
 //按键1按下,执行相应操作
 }
}
  • key_val 读取按键值
  • key_down 按键下降沿检测,只在按键按下瞬间为按键值,其他时刻全为0
  • key_up 按键上升沿检测,只在按键抬起瞬间为按键值,其他时刻全为0
  • key_old 保存上一次检测按键值

案例1:key1控制LED1开和关

注意点,书写规范。

  • 声明都在 *.h 文件中
  • Led_Disp() 和 KeyScan() 都涉及到 GPIO,那么就在 gpio.c 进行定义。
//gpio.h
/* USER CODE BEGIN Prototypes */
void Led_Disp(uint8_t ucled);
uint8_t Key_Scan(void);
/* USER CODE END Prototypes */

//gpio.c
/* USER CODE BEGIN 2 */
void Led_Disp(uint8_t ucled)
{
 	 HAL_GPIO_WritePin(GPIOC,0xFF<<8,GPIO_PIN_SET);

 	 HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);	// PD2 
 	 HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
	 
 	 HAL_GPIO_WritePin(GPIOC,ucled<<8,GPIO_PIN_RESET);
 	 HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
 	 HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

uint8_t Key_Scan(void)
{
  uint8_t key_val=0;
  if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET)
  {
    key_val=1;
  }
  if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==GPIO_PIN_RESET)
  {
    key_val=2;
  }
  if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==GPIO_PIN_RESET)
  {
    key_val=3;
  }
  if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
  {
    key_val=4;
  }
  return key_val;
}
/* USER CODE END 2 */

//main.h
/* USER CODE BEGIN EFP */
void Led_Proc(void);
void Key_Proc(void);
/* USER CODE END EFP */

//main.c
/* USER CODE BEGIN PV */
uint8_t ucled=0x01;
uint8_t key_val,key_up,key_down,key_old;
/* USER CODE END PV */

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    Led_Proc();
    Key_Proc();
  }
  /* USER CODE END 3 */

/* USER CODE BEGIN 4 */
void Led_Proc(void){
  Led_Disp(ucled);
}
void Key_Proc(void){
  key_val = Key_Scan();
  key_down = key_val & (key_val ^ key_old);
  key_up = ~key_val & (key_val ^ key_old);
  key_old = key_val;

  if(key_down == 1){
    ucled ^= 0x01;
  }
}
/* USER CODE END 4 */

案例2:按键按下LED亮,松开LED灭

void Key_Proc(void){
 key_val=Key_Scan();
 key_down = key_val & (key_val^key_old);
 key_up = ~key_val & (key_val^key_old);
 key_old=key_val;

 if(key_down==3)
 {
    ucled=0x01;//下降沿,按下LED亮
 }
 if(key_up==3)
 {
    ucled=0x00;//上升沿,松开LED灭
 }
}

三、长按 短按

按键按下后开始计时,如果没有在规定时间内抬起,就是长按,否则就是短按。

  • 短按,LED1亮,LED2不亮
  • 长按,LED1灭,LED2亮
void Key_Proc(void){
 key_val=Key_Scan();
 key_down = key_val & (key_val^key_old);
 key_up = ~key_val & (key_val^key_old);
 key_old=key_val;

 if (key_down){
  uskey = 0; //按下就从0开始计时
 }
 if (uskey < 1000){
    if(key_up == 1){ //1s 内抬起,短按
        ucled = 0x01;
    }
    if(key_up == 2){
      // 按键2短按操作,自行填写
    }
 }else{
    if(key_val == 1){ //1s 后未抬起,长按
      ucled = 0x02;
    }
    if(key_up == 2){
      //按键2长按操作
    }
 }
}

这里的 uskey,出门右转 STM32点亮LED的系统定时器。

四、单击 双击

当按键抬起时,开始计时。

双击:当在规定时间内再次按下该按键;

单击:超时没有按键按下。

案例

双击B1,LED2亮,LED1灭

单击B1,LED1亮,LED2灭

void Key_Proc(void){
 key_val=Key_Scan();
 key_down = key_val & (key_val^key_old);
 key_up = ~key_val & (key_val^key_old);
 key_old=key_val;

 //抬手
 //第一次单击并抬手,要执行下面操作的 flag=0操作
 //第二次单击并抬手,要执行下面操作的 flag=1操作
 if(key_up){
  key_temp = key_up;  //记录此时的动作
  //flag初始值为0
  if(key_flag==0){  //开始计时
    uskey = 0;
    key_flag = 1;
  }else{  //双击结束
    key_flag = 0;
  }
 }
 if(key_flag==1){
  if(uskey<300){  //没超时
    if(key_down==1 && key_temp==1){ //双击B1,点亮灯2
      ucled = 0x02;
    }
    if(key_down==2 && key_temp==2){
      //双击B2
    }
  }
  else{
  if(key_temp==1){  //超时
    ucled = 0x01; //单击B1,亮灯1
  }
  if(key_temp==2){
    //单击B2
  }
  key_flag=0;
 }
 }
}

当按键抬起后,key_up会从按键值变0,需要有个临时变量 key_temp 保存按键值。那么双击可以定义为 key_temp=1 && key_down==n。

单击 双击,需要考虑下面3个问题:

  1. 上电后第一次按下
  2. 双击结束后的下一次
  3. 单击结束,超时后的第一次


http://www.kler.cn/a/516845.html

相关文章:

  • Java导出通过Word模板导出docx文件并通过QQ邮箱发送
  • ansible一键安装nginx二进制版本
  • 聊一聊 CSS 样式的导入方式
  • MySQL数据库批量插入包含uuid的数据
  • 后端的config包中的常用配置
  • 豆包MarsCode 蛇年编程大作战 | 高效开发“蛇年运势预测系统”
  • ETLCloud在iPaas中的是关键角色?
  • 若依 v-hasPermi 自定义指令失效场景
  • Java核心技术解析:泛型与类型安全全面指南
  • android wifi AsyncChannel(WifiManager和WifiP2pManager)
  • 【CS61A 2024秋】Python入门课,全过程记录P3(Week5 Sequences开始,更新于2025/1/23)
  • 韩国机场WebGIS可视化集合Google遥感影像分析
  • Java EE 进阶:Spring MVC(1)
  • HarmonyOS快速入门
  • 【YOLOv10改进[Backbone]】使用LSKNet替换Backbone | 用于遥感目标检测的大型选择性核网络
  • 在centos上编译安装opensips【初级-默认安装】
  • Nginx 性能优化技巧与实践(一)
  • PLC通信
  • 2025年最新汽车零部件企业销售项目管理解决方案
  • 解密堡垒机:安全与效率的守护者
  • 2K320Hz显示器哪个好?
  • Vue.js 嵌套路由和动态路由
  • 【问题】Qt c++ 界面 lineEdit、comboBox、tableWidget.... SIGSEGV错误
  • MsfVenom木马制作及使用
  • 在K8S中,如何使用EFK实现日志的统一管理?
  • FFmpeg 头文件完美翻译之 libavcodec 模块