蓝桥杯嵌入式学习日记(三)——按键的长按、短按与双击(三行按键法)【STM32】【HAL库】

发布于:2024-04-20 ⋅ 阅读:(23) ⋅ 点赞:(0)

一、查阅相关资料

  想要进行一块板子的开发,需要先查阅资料了解器件连接。
在这里插入图片描述
  从CT117E-M4产品手册中不难发现,按键分别有PB0、PB1、PB2、PA0分别对应B1、B2、B3、B4四个按键。

按键抖动
在这里插入图片描述
在这里插入图片描述
  我们所使用这类按键时,当按键按下,内部的机械触点因为弹性,并不会立马导通,同样松开时也不是立马分离,而是会产生一连串的抖动,这段时间大概在5~10ms,为了防止紊乱我们要进行消抖。这里我选择利用uwTick进行软件延时,实际情况中也可以使用定时器,但不建议使用HAL_Delay函数进行延时。

	if( uwTick - KeyTick < 10) return ;//建议至少大于等于10ms,但不要过大,例如超过100ms
	KeyTick = uwTick ;

了解了这些,我们可以进行STM32cubemx工程创建。依旧是上一篇的工程进行延展。

二、程序的编写

1、创建工程

在这里插入图片描述
如图设置完以后便可以生成工程进行编写,不会利用STM32cubemx生成工程的可以参考上一篇利用STM32cubemx创建工程并以STM32G4点灯【HAL库】
依旧是照例创建key.c和key.h方便管理。

2、三行按键法

#define B1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) 
#define B2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) 
#define B3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) 
#define B4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) 
#define Key_Flag  B1 | (B2<<1) | (B3<<2) | (B4<<3) | 0xf0      //初始端口状态

u8 Trg ;//Triger
u8 Cont ;//Continue

void Key_Scan()
{
	u8 ReadDate = Key_Flag ^ 0xff ;
	Trg = ReadDate & (ReadDate ^ Cont) ;
	Cont = ReadDate ;
}

想要理解这三行代码需要了解下最基本的与或知识,对于学过数电的同学可能已经掌握,可以直接跳过。

1为真值
0 为假值

与(and)(&)
逻辑表达式:F=AB
运算规则为:全1为1 ,有0为0 。真值表为

操作数1 操作数2 结果值
1 1 1
1 0 0
0 1 0
0 0 0

或(or)(|)
逻辑表达式:F=A+B
运算规则为:全0为0,有1为1 。真值表为

操作数1 操作数2 结果值
1 1 1
1 0 1
0 1 1
0 0 0

异或(XOR)(^)
运算规则为:相异为1,相同为0 。真值表为

操作数1 操作数2 结果值
1 1 0
1 0 1
0 1 1
0 0 0

了解了基础知识再来进行推理就很简单了。

1、当没有按键按下的初始状态

Key_Flag = 0xff ;
ReadDate = 0xff^0xff = 0000 0000 ;
Trg = 0000 0000 ;
Cont = 0000 0000 ;

2、当B1被按下

Key_Flag = 0xfe ;
ReadDate = 0xfe ^ 0xff = 0x01 ; 
Trg = 0x01 & (0x01 ^ 0x00) = 0x01 ;
Cont = 0x01 ;

3、当B1被长按

Key_Flag = 0xfe ;
ReadDate = 0xfe ^ 0xff = 0x01 ;
Trg = 0x01 & (0x01 ^ 0x01) = 0x00 ;
Cont = 0x01 ;
一步步来理解就是当初始状态没有按键被按下时,Key_Flag 为0xff

ReadDate = Key_Flag ^ 0xff = 0xff ^ 0xff // 对于0xff取反则为0000 0000 ;
Cont默认为0x00 
Trg = ReadDate & (ReadDate ^ Cont) = 0x00 & ( 0x00 ^ 0x00) = 0x00


-------------------------------------------------------------------
当有按键被按下例如B1,则有 Key_Flag 为 0xfe

ReadDate = Key_Flag ^ 0xff = 0xfe ^ 0xff = 0x01 // 0000 0001
Trg = ReadDate & (ReadDate ^ Cont) = 0x01 & (0x01 ^ 0x00) = 0x01 & 0x01 = 0x01 
Cont = 0x01 


-------------------------------------------------------------------
当有按键被持续按下例如B1,则有 Key_Flag 为 0xfe

此事件发生前Cont = 0x01

ReadDate = Key_Flag ^ 0xff = 0xfe ^ 0xff = 0x01 // 0000 0001
Trg = ReadDate & (ReadDate ^ Cont) = 0x01 & (0x01 ^ 0x01) =  0x01 & 0x00 = 0x00 
Cont = 0x01 

在结束按按键之后即所有回复0x00的状态。
如有不懂的同学,可以自己动手推到一两次即可理解。

3、短按与长按

  在了解上述内容后,后续只需要进行逻辑判断即可。
  
短按
  判断Trg的值即可进行按键的判断

按键 KB1 KB2 KB3 KB4
Trg 0x01 0x02 0x04 0x08
void KEY_Judge()
{
	if( uwTick - KeyTick < 10) return ;
	KeyTick = uwTick ;
	
	Key_Scan() ;
//短按
	if(Trg & 0x01)  LED_Control(0x01) ; //B1
	if(Trg & 0x02)  LED_Control(0x02) ; //B2
	if(Trg & 0x04)  LED_Control(0x04) ; //B3
	if(Trg & 0x08)  LED_Control(0x08) ; //B4
}

通过上篇LED进行按键反馈。B1 ~ B4对于LED1 ~ LED4。

长按
  长按相较于短按只需要加入时间来进行判断Cont即可。

//长按
	if(Trg & 0x01)  ContTick = uwTick ; //B1
	if(Trg & 0x02)  ContTick = uwTick ; //B2
	if(Trg & 0x04)  ContTick = uwTick ; //B3
	if(Trg & 0x08)  ContTick = uwTick ; //B4
///B1
	if( Cont & 0x01 ) 
	{
		if(uwTick - ContTick < 1000) return ;
		{
			LED_Control (0x00) ;
		    ContTick = uwTick ;
		}
	}
//省略

这里设置短按B1则LED1亮起,长按一秒关闭。

4、双击

双击

  双击只需要加入标志位来判断,并且人手设置双击时间小于200ms即可(自适应)。这里需要填入一位变量来记录按键输入值。

#define Key_Temp  ((B1 | (B2<<1) | (B3<<2) | (B4<<3) ) ^ 0x0f)    //端口状态

经过上面学习应该对于Key_Temp的值有所了解,可以试着自己算一算。

	Key_Down = Key_Temp & (Key_Old ^ Key_Temp) ;   //按下为按键值
	Key_Up  = ~Key_Temp & (Key_Old ^ Key_Temp) ;  //松手为抬起前的按键值
	Key_Old = Key_Temp ;

这里跟上面三行按键类似不再进行分析,如果有不会的可以在评论区询问。

	if(Key_Up)	DoubleTick = uwTick;		//判断按键上升沿弹起并记录当前时间 

	if(uwTick - DoubleTick >=200 ) //200ms以内执行以下操作
	{
		switch(Key_Down) 
		{
			case 1 : LED_Control(0x01) ; break ;
			case 2 : break ;
			case 3 : break ;
			case 4 : break ;
		}
		if(Cont & 0x01)
		{
			if(uwTick - ContTick < 1000) return ;
			{
				LED_Control (0x00) ;
				ContTick = uwTick ;
		    }
		}
	}
	else //反之
	{
			switch(Key_Down) 
			{
				case 1 : LED_Control(0xff) ; break ;
				case 2 : break ;
				case 3 : break ;
				case 4 : break ;
			}
	}
}

这里只放出了B1的短按、长按和双击,对应的现象分别是,LED1亮起、LED1一秒熄灭和LED1~8全部亮起。如有不懂,可以在评论区留言。这里放上完整工程,如有需要自行下载。

链接:https://pan.baidu.com/s/1KmYiYB84tBnmpjXxt94sFg?pwd=1111
提取码:1111