标题: 三行按键 单片机程序分析 [打印本页]
作者: RMLS 时间: 2019-9-8 16:48
标题: 三行按键 单片机程序分析
今天写一个进阶级的帖子分享一下,记录过程。
三行按键由烟台南山学院-零点工作室原创,如转载,请标明出处,并附本链接。
我看CSDN上有三行按键相关的分析,但并不是原创作者以及我们工作室相关学长。
三行按键从出生到现在已经很多个年头了,经过几代优化,现在有两个版本,今天分析一下,也在本论坛扩充一下资源。
我在本论坛搜索三行按键,并没有相关的帖子。
首先说明一下什么是三行按键,有什么用,什么好处,以及弊端。
三行按键,顾名思义,代码只有三行;
用处:在咱日常生活中,运用按键时(矩阵按键除外),例如四个独立按键甚至八个。完全可以使用。
最大的好处就是,平时按键会有长按和短按,不难理解,一个是触发就松手,另一就是按下不松手,第二个针对按下就执行某个程序,松开就停止执行,比如手表上调时间的按钮,分钟在长按0.8s之后自己会自加,当松开按钮时,停止自加。
好处:代码简介,但是分析过程比较困难,接下来会进行分析。
弊端:下面两种方法都有各自的弊端,在下面有详细说明。
首先写出三行按键的两个版本:
void Threekey(uchar *Trg,uchar *Cont)
{
unsigned char ReadData = (P3 & 0x0f) ^ 0xff;
(*Trg) = ReadData & (ReadData ^ (*Cont));
(*Cont) = ReadData;
}
void ThreeKey(void)
{
unsigned char ReadDat = (P3 ^ 0xff) & 0x0f;
Trg = (ReadDat ^ Cont)& ReadDat;
Cont = ReadDat;
}
最大的区别不在指针,而是在相与以及或运算的先后顺序。
导致最后当按键触发,运算出来的结果不相同,。
代码分析如下:
//第一种程序解析
/*******************************************/
void key(void)
{
unsignedchar ReadData = (P3 & 0x0f)^ 0xff;
Trg)=ReadData & (ReadData^ Cont);
Cont)=ReadData;
}
//短按
//没有按下情况下:
ReadData= (0xff & 0x0f) ^ 0xff = 0xf0
Trg= 0xf0 & (0xf0 ^ 0x00) = 0xf0
Cont= 0xf0
//第二次扫描未按下
ReadData= (0xff & 0x0f) ^ 0xff = 0xf0
Trg= 0xf0 & ( 0xf0 ^ 0xf0) = 0x00
Count= 0xf0
//第三次扫描未按下
ReadData= (0xff & 0x0f) ^ 0xff = 0xf0
Trg= 0xf0 & (0xf0 ^ 0xf0) = 0x00
Cont= 0xf0
//当第一个按键按下情况
ReadData= (0xfe & 0x0f) ^ 0xff = 0xf1
Trg= 0xf1 & ( 0xf1 ^ 0xf0) = 0x01
Cont= 0xf1
//长按
//当按键按下并且不放手情况
ReadData= (0xfe & 0x0f ) ^ 0xff = 0xf1
Trg= 0xf1 & (0xf1 ^ 0xf1 ) = 0x00
Cont= 0xf1
//按键松手
ReadData= (0xff & 0x0f) ^ 0xff = 0xf0
Trg= 0xf0 & (0xf0 ^ 0x00) = 0xf0
Cont= 0xf0
以此类推 短按情况下 Trg = 0x01
0x02
0x04
0x08
长按情况下 Count = 0xf1
0xf2
0xf4
0xf8
弊端:当按键没有按下,第一次扫描的Trg第一次会有一个值的变化,Trg= 0xf0;现在还没有试出来对执行程序有什么影响。
//第二种程序解析
/*******************************************/
void ThreeKey(void)
{
unsignedchar ReadDat = (P3 ^ 0xff)& 0x0f;
Trg= (ReadDat ^ Cont)&ReadDat;
Cont= ReadDat;
}
//短按
//按键没有按下情况
ReadDat= (0xff ^ 0xff) & 0x0f = 0x00
Trg= (0x00 ^ 0x00 ) & 0x00 = 0x00
Cont= 0x00
//按键按下情况 第一个按键按下
ReadDat= (0xfe ^ 0xff) & 0x0f = 0x01
Trg= (0x01 ^ 0x00) & 0x01 = 0x01
Cont= 0x01
//长按
//按键按下没有松手情况
ReadDat= (0xfe ^ 0xff ) & 0x0f = 0x01
Trg= (0x01 ^ 0x01) & 0x01 = 0x00
Cont= 0x01
//按键松手
ReadDat= (0xff ^ 0xff) & 0x0f = 0x00
Trg= (0x00 ^ 0x01) & 0x00 = 0x00
Count = 0x00
以此类推 短按情况下 Trg = 0x01
0x02
0x04
0x08
长按情况下 Count = 0x01
0x02
0x04
0x08
弊端:短按Trg和长按Count运算结果是一样的,也就是说当执行程序的时候需要分明。第二种比较好用。
附件文件和本文程序一样。
主要就是讲这个算法如何用,而不是拿现成的程序来给你们,这样这段算法的意义并不大。
说明一下,第二个代码的Trg以及Count是全局变量,可以在执行按键的函数里面进行调用。
这段例程里面,按键可以放在P30,P31,P32,P33口,四个按键进行举例的。
完整的pdf格式文档51黑下载地址:
三行按键.pdf
(128.32 KB, 下载次数: 30)
作者: m182892 时间: 2019-9-9 08:30
有没有人在项目中用到这个按键
作者: bhjyqjs 时间: 2019-9-9 08:37
第二种方法我一直在用,实用性较高。
作者: bhjyqjs 时间: 2019-9-9 08:43
void ThreeKey()
{
ReadData = ~ReadData; // 1
Trg = ReadData & ~Cont; // 2 注“~”优先级高于& ;ReadData为本次键状态,Cont为上次键状态
Cont = ReadData; // 3
}
这是改进版,更好理解。编译后代码量一样。
作者: HSZ 时间: 2019-9-9 21:54
优秀啊
作者: zhangjianhu 时间: 2019-11-16 09:30
在实际项目中,实际使用下。
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |