正点原子—按键输入代码解析

前言

相信很多人学习STM32看的教程资料什么的,不是正点原子就是野火,这两家的资料都是比较有名的,我用的就是正点原子的,这篇博客我来讲一下我当初学习按键输入例程时的疑惑,我到论坛上看了,大部分初学者跟我有同样的问题,究尽是什么问题呢?我们先上代码:

代码讲解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按键按松开标志
if(mode)key_up=1; //支持连按
if(key_up&&(KEY1==0||KEY2==0))
{
delay_ms(10);//去抖动
key_up=0;
if(KEY1==0)return KEY_1;
else if(KEY2==0)return KEY_2;

}else if(KEY1==1&&KEY2==1)key_up=1;
return 0;// 无按键按下
}

问题就出在这个KEY_Scan()函数上(上面贴的代码我修改过,原版是有4个按键的,我改成2个,但实质上是一样的,这样方便大家理解),前面GPIO初始化部分,相信看过跑马灯例程过来的都没什么问题,我们主要看看KEY_Scan()这个函数,这个函数是带参数mode的,且有返回值,当初我跟大部分网友的疑惑在于为啥mode为1就支持连续按,为0就不支持呢,原理是啥?代码读一遍下来感觉为0为1没差啊。
为什么会有这样的疑惑,归结起来还是C语言基础太差,还有一个很重要的原因就是,大家阅读代码就只是这样读一遍下来,然而这里你要读上两遍才能看出问题所在。下面我们一点一点来讲……

1
2
3
4
5
6
	static u8 key_up=1;//按键按松开标志

/* 这句话咋一看没什么了不起,不就是定义key_up的值为1吗?是这样没错,但是大家可能忽视了前面
有个static,或者知道有static却不知道它的含义,这就是为什么我说C语言基础差的原因,static用
在这里相当于定义了一个static局部变量,下面是重点:static局部变量只被初始化一次,下一次依据
上一次结果值。意思也就是说,这句话只跑一次!!! */

1
2
3
4
5
6
	if(mode)
key_up=1; //是否支持连按

/* 这里我把原代码这样写,可能大家见这样形式的比较熟悉,很明显是个if判断语句,如果是真,执行
key_up=1;如果不为真,跳过,执行下一行;那么真不真,相信大家应该都明白,1真0不真咯,如果不
懂,还是先去翻翻C语言吧。 */
1
2
3
4
5
6
7
8
9
10
11
12
13
	if(key_up&&(KEY1==0||KEY2==0))
{
delay_ms(10);//去抖动
key_up=0;
if(KEY1==0)return KEY_1;
else if(KEY2==0)return KEY_2;

}else if(KEY1==1&&KEY2==1)key_up=1;
return 0;// 无按键按下

/* 剩下的我们合在一起看,前面我们定义了按键松开标志key_up=1,如果满足key_up为真且KEY1或
KEY2有一个为0(被按下为0),那么我们就把按键标志key_up置0,同时判断是哪个键被按下,然后输
出返回值;如果KEY1,KEY2都没被按下,则key_up还是置1,返回0。 */

好了,以上基本代码已经讲解完了,可能有的人已经领悟了问题所在,有的人还迷迷糊糊,没关系,我们接下来直击重点:
没有明白的人,我相信只剩逻辑问题了,我们代码中有这样一句话

1
if(key_up&&(KEY1==0||KEY2==0))

这句代码告诉我们,你想知道哪个键被按下不仅仅是判断是否有按键被按下这么简单,还要满足按键标志key_up为1才行;如果你不想支持连按,即mode=0,因为我们初始了key_up=1,当我们按下按键,确实能成功响应返回值,但同时key_up也被置0,如果你的手不放开,程序是永远无法进入下一次按键判断的,因为此时key_up为0,不满足条件;只有当你把手放开,程序执行

1
else if(KEY1==1&&KEY2==1)key_up=1;

这时key_up才被重新置1,下一次按键才能被检测判断,这就是所谓的不支持连按。

那么如果你是想支持连按的,因为mode=1,程序每次跑,判断到mode=1,为真,就自动将key_up置1了,尽管你的手不放开,程序都能进入按键检测,你一直按着哪个键,它就不停返回对应的返回值,这就是所谓的支持连按。

完结!!!