一、查阅相关资料
想要进行一块板子的开发,需要先查阅资料了解器件连接。
从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