蓝桥杯—STM32G431RBT6(三行代码算法及按键消抖短按长按短按,单击双击)原理精讲接上篇(二)

消抖完整代码见http://t.csdnimg.cn/cWWFq

目录

一、

1.三行代码是什么?

 2.三行代码算法的原理是什么?

1.符号

2.以按下按键二举例

3.为什么能消抖

二、

1.长按与短按(含详细解释)

2.单击与双击(含详细解释)

一、

1.三行代码是什么?

    Key_down=key_rval&(key_rval^key_old);
	Key_up=~key_rval&(key_rval^key_old);
	key_old=key_rval;

 2.三行代码算法的原理是什么?

1.符号

 `~` 表示按位取反(bitwise NOT)操作,将每一位上的 0 变为 1,1 变为 0。

`&` 表示按位与(bitwise AND)操作,只有当两个对应位上都为 1 时,结果才为 1,否则为 0。

^ 运算符表示按位异或(bitwise exclusive OR)操作。:当两个对应位上只有一个为 1 时,结果为 1,否则为 0。

2.以按下按键二举例

初始状态:

  • key_rval 为其他按键值(非按键二的值)。
  • Key_upKey_down 为 0。
  • key_old 为其他按键值。

按下按键二时:

  • key_rval 更新为按键二的值(设为 0x02)。
  • key_rval ^ key_old 的结果不为 0。当两个不同的数进行按位异或运算时,对于每一位来说,如果两个数在这一位上的值不同(一个为 0,另一个为 1 或反之),那么异或的结果在这一位上就是 1,key_rval 会从之前的值变为对应按键的新值,而 key_old 仍然是之前的按键值

    因为两者不同,所以它们按位异或的结果就会有至少一位是 1,导致结果不为 0。这种按键值都是0000 0010  0000 0000这种形式如果与0000 0001 0000 0000异或结果为0000 0011 0000 0000,非0

    所以 Key_down 为 1
  • Key_up 为 0。
  • key_old 更新为 0x02。

在这个过程中,通过检测 Key_down 的值为 1,我们可以知道按键二被按下了。

3.为什么能消抖

这是通过逻辑运算来实现消抖的。

当有按键动作时,key_rval 会发生变化,key_rval ^ key_old 可以检测出变化的位,即判断是否有按键事件。

然后,Key_down 是通过 key_rval 与变化位进行与运算得到的,这样只有真正的按键按下事件才会被检测到,因为抖动产生的短暂变化在与运算中会被过滤掉。

同样,Key_up 是通过对 key_rval 取反后与变化位进行与运算得到的,能够准确检测按键的释放。

最后,通过将 key_rval 更新为 key_old,为下一次检测做准备。这样不断循环,就能够有效地消除按键抖动的影响。

它的基本原理是通过对信号进行连续采样,并根据一定的逻辑判断来确定信号的真实状态。在消抖滤波中,通常会设置一个时间窗口,只有在这个窗口内信号保持稳定的状态,才被认为是有效的信号变化,从而避免了因短时间内的抖动或干扰而产生的误判。

二、

1.长按与短按(含详细解释)

消抖算法如上

#include "headfile.h"

void led_show(uint8_t led,uint8_t mode)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	if(mode)
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led-1),GPIO_PIN_RESET);
    else
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led -1),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;
}
extern uint8_t key_rval;
uint8_t Key_up,Key_down,key_old;
uint32_t keytime;//加入了计时的功能,在SysTick_Handler 是系统节拍中断处理函数。keyyime是在stm32g4**——it.c中定义
//在嵌入式系统中,系统节拍定时器(SysTick)会周期性地产生中断,SysTick_Handler 就是用来处理这些中断的函数。
//它通常用于进行一些定时相关的操作或任务调度等。
void Key_Proc(void)	
{
	key_rval=Key_Scan();
	Key_down=key_rval&(key_rval^key_old);
	Key_up=~key_rval&(key_rval^key_old);
	key_old=key_rval;//原理看上文
	
	if(Key_down==1)//如果检测到按键按下
	{
		keytime=0;//给系统计时器清0,开始计时
	}
	if(keytime<800)//如果计时时间小于800ms
	{
		if(Key_up==1)//检测到松手,则系统判断为单击
		{
			led_show(1,1);
		}
	}
	else//如果计时大于800ms
	{
		if(key_rval==1)//如果此时按键仍处于按下状态,则进行长按相关的操作。
		{
		   led_show(2,1);
			led_show(1,0);//长按亮LED2,熄灭LED1
		}
	}
}

2.单击与双击(含详细解释)

#include "headfile.h"

void led_show(uint8_t led,uint8_t mode)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	if(mode)
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led-1),GPIO_PIN_RESET);
    else
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led -1),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;
}
extern uint8_t key_rval;
uint8_t Key_up,Key_down,key_old;
uint32_t keytime;
uint8_t key_temp,key_flag;//temp保存第一次的按键值,flag用来判断是否可以计时
void Key_Proc(void)	
{
	key_rval=Key_Scan();
	Key_down=key_rval&(key_rval^key_old);
	Key_up=~key_rval&(key_rval^key_old);
	key_old=key_rval;
    if(Key_up)//如果检测到松手
	{   
		key_temp=Key_up;//将当前释放值保存到 key_temp,并根据标志变量 key_flag 的状态进行相应操作。
		if(key_flag==0)//变量定义时,没有显式地给 key_flag 赋值,编译器会自动将其初始化为默认值 0。
		{
			keytime=0;
			key_flag=1;
		}
		else
		key_flag=0;//目的是将key_flag双击结束后的下一次可以开始计时
	}
	if(key_flag==1)//key_flag=1
	{
		if(keytime<300)//如果300ms内
		{
		if(Key_down==1&&key_temp==1)//检测到按键按下最开始松手一致
		{
		led_show(2,1);//则执行
			led_show(1,0);
		}	
//		if(Key_down==2&&key_temp==2)//多按键
//		{
//		led_show(3,1);//
//			led_show(4,0);
//		}	
		}
		else
			{
				if(key_temp==1)//如果只检测到开始保存键值,则视为单击
			{
			led_show(1,1);//则执行
				led_show(2,0);
			}
			key_flag=0;//并将key_flag置0为下一次做准备
//			if(key_temp==2)//
//			led_show(4,1);//则执行
//				led_show(3,0);
//			}
//			key_flag=0;//并将key_flag置0为下一次做准备
		}
	}
}

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值