6225|13

1193

帖子

0

TA的资源

纯净的硅(高级)

楼主
 

关于矩阵键盘,使用电子表格辅助编程 [复制链接]

 
本帖最后由 qiushenghua 于 2015-5-10 01:19 编辑

最近在某个项目中需要用到按键检测,常规想法是矩阵键盘,于是就这么做下去了。
后来在编程的时候发现,实现按键检测并不是一件容易的事情,特别是有多个按键同时按下的情况下。
在这个过程中逻辑太容易乱了,于是借助了电子表格工具(WPS或者Excel),试图节省工作量。
后来发现效果确实不错,于是在这里分享一下。

绘制PCB使用的是Altium Designer 10,但是家中未安装该软件,于是使用DesignSparkPCB将原理图重新绘制了一遍,大家将就着看。


我们的目的是实现2*3的矩阵键盘的检测,思路大概是这样的:
1.将Row1置低,其他管脚设置为带有上拉的输入状态,将其状态记录下来。
2.将Row2置低,其他管脚设置为带有上拉的输入状态,记录输入结果并计算按键状态。

或许大家觉得这个过程很容易,一看Col哪个被拉低就知道是哪个按键被按下了。
其实却不是这样,有可能存在多个按键共同作用导致某个Col被拉低的情况。
为什么不用Col来扫描?——因为扫描Row只需要扫描2回,扫描Col需要扫描3回。

为了解决这个问题,尽可能多的检测出多个按键按下的不同状况,我使用了大名鼎鼎的电子表格(俗称Excel),来实现这个检测。

作为6个按键,有2^6=64种不同的状态,所以我们可以通过电子表格的自动填充功能实现这个工作。
我们将A列定义为64种不同状态(0-63)
然后在B2单元格内输入“=dec2bin(A2,6)”,将A列的数据转换为二进制数
C列表头为SW1,C2单元格“=LEFT(B2,1)”,即二进制数左端第1个数
D列表头为SW2,D2单元格“=RIGHT(LEFT(B2,2),1)”,即二进制数左端取2个,再从这两个里取右端的一个,也就是左起第二个数

同理:
E列表头SW3,E2单元格“=RIGHT(LEFT(B2,3),1)”
F列表头SW4,F2单元格“=RIGHT(LEFT(B2,4),1)”
G列表头SW5,G2单元格“=RIGHT(LEFT(B2,5),1)”
H列表头SW6,H2单元格“=RIGHT(B2,1)”

完成上述步骤之后,我们空出一列来(I列),接下来计算按键按下之后产生的逻辑关系,这也是最让人头疼的问题。

为了节省列宽(屏幕大小有限,可以显示更多内容),我们将J1单元格输入R2(Row_2),K1单元格输入C1(Col_1),L1=C2,M1=C3
为什么没有R1?——这里计算的是R1设定为低的情况下其他信号线的输入状态,R1一定为0。
接下来就是信号怎么判断了。

由于上拉是弱上拉,在按键按下的时候,如果对应行是低电平,那么列会被拉低。
在这里我们约定,如果SW1=1,表示SW1按下,其余按键以此类推。
在R1=0时,要让R2也等于0,那么需要SW1和SW4同时按下,或者SW2和SW5同时按下,又或者SW3和SW6同时按下。
于是,J2单元格(Row2列)的逻辑就是“=IF(C2*F2+D2*G2+E2*H2,0,1)”(组合逻辑不要忘记了)

接下来计算Col1列,这个时候刚刚计算得到的Row2列的结果可以用到。
我们知道,如果Row1为低,且SW1按下,那么Col为低,如果Row2为低,且SW4为低,那么Col也为低。
故K2单元格:“=IF(C2+F2*(1-J2),0,1)”
L2:“=IF(D2+G2*(1-J2),0,1)”
M2:“=IF(E2+H2*(1-J2),0,1)”

继续空一列(N列),有了之前的经验,很容易填写下面的单元格:
O2:“=IF(C2*F2+D2*G2+E2*H2,0,1)”
P2:“=IF(F2+C2*(1-O2),0,1)”
Q2:“=IF(G2+D2*(1-O2),0,1)”
R2:“=IF(H2+E2*(1-O2),0,1)”

然后选中这一行的所有数据,向下填充到65行(表头占一行,数据有64行)
效果如下图所示:


有人要问了,不就是计算个逻辑吗,何必搞的那么复杂呢?又是公式又是填充的。
请稍等,先来段广告,精彩稍后继续。。。


刚刚说了那么久,还没提到电气连接是怎么样的。
这个项目原本我是用STM32实现的,但是,这里是MSP430板块嘛,那么我就移植一下咯,用最常见的MSP430G2553来做。
R1:P1.4
R2:P1.3
C1:P1.2
C2:P1.1
C3:P1.0
初始化的代码就不写了,定义两个宏:
  1. #define R1OUT() do{\
  2. P1DIR &= ~BIT3;\
  3. P1OUT |= BIT3;\
  4. P1REN |= BIT3;\
  5. P1REN &= ~BIT4;\
  6. P1OUT &= ~BIT4;\
  7. P1DIR |= BIT4;\
  8. }while(0)

  9. #define R2OUT() do{\
  10. P1DIR &= ~BIT4;\
  11. P1OUT |= BIT4;\
  12. P1REN |= BIT4;\
  13. P1REN &= ~BIT3;\
  14. P1OUT &= ~BIT3;\
  15. P1DIR |= BIT3;\
  16. }while(0)
复制代码


那么我们可以分两轮扫描,定期执行。
第一轮扫描R2OUT()运行时的P1IN,读取完毕执行R1OUT()。
第二轮扫描R1OUT()运行时的P1IN,读取完毕执行R2OUT()。

那么我们可以知道,第一轮扫描的时候,R2是输出,我们需要读取P1.4 P1.2 P1.1 P1.0的键值。
第二轮扫描的时候,R1输出,我们需要读取P1.3 P1.2 P1.1 P1.0的键值。
由于使用了连续的寄存器,所以我们能够很方便的使用一个寄存器Key_Buffer来储存键码。
于是,我们只需要在第一轮扫描的时候将寄存器清除,再将键值搬运到寄存器的高4位,
在第二轮扫描的时候直接将寄存器加上P1IN的低4位即可。
  1. void Key_Scan()
  2. {
  3.         static unsigned char count=1;
  4.         static unsigned char Key_Buffer=0;
  5.         static unsigned char Key_States=Key_Old_States=Key_Press=Key_Bottom_up=0;

  6.         if(count&0x01)//奇数轮
  7.         {
  8.                 unsigned char temp=0;
  9.                 temp=P1IN;
  10.                 Key_Buffer=((temp&0x07)<<4)+((temp&0x10)<<3);
  11.                 R1OUT();               
  12.         }
  13.         else//偶数轮
  14.         {
  15.                 Key_Buffer+=(P1IN&0x0f);
  16.                 R1OUT();
  17.                
  18.         }
  19.         count++;
  20. }
复制代码


眼尖的可能见到了,我还定义了Key_States,Key_Old_States,Key_Press和Key_Bottom_up一共4个变量,它们是用来干嘛的呢?
我们接着看。
这个扫描结果对应的是表格里J-M,O-R列的数值,而我们需要的是C到H列里各个按键的状态,如果有办法将其转换一下就好了。
好吧,我们回到电子表格里继续计算。
老规矩,空出一列(S列)作为分隔,我们的Key_Buffer在经过奇偶两轮的运算之后,是J-M,O-R列数据拼接而成的数值。
于是我们在T2单元格模仿这个运算,填入“=J2&K2&L2&M2&O2&P2&Q2&R2”,在电子表格里,&既不是与运算也不是按位与运算,而是字符串拼接运算。
继续往后看,U2单元格“=bin2dec(T2)”将这个结果向下填充,得到了最终版本的Sheet1。
(后续运算如果在这个工作表基础上继续下去,将破坏本表格的完整性,所以将Sheet中所有数据复制到Sheet2中继续进行。)
现在表格长这个样子了:


刚刚说了,将Sheet1复制了一份在Sheet2表,我们接着算。
我们留意到,在U2列里出现了好多相同的数据,这说明扫描得到的结果是一样的,但是键码却不一样。于是我们要找出这些无法判断键码的键值来。
在V2单元格填入“=COUNTIF(U:U,U2)”,向下填充。
于是看到了好多次数超过一次的。选中A-V列,自定义排序,选择有标题行,按照V列降序,U列升序,A列升序的次序排列。
我们截选了一段键值一样的扫描结果:

从这段表格可以看出,在SW1,SW2,SW4同时按下的时候,无法判断SW5是否按下。
结合原理图,我们发现,在在SW1,SW2,SW4同时按下的时候,
Row1,Row2,Col1,Col2均被短路,按下或者不按下SW5,均无法改变这个结果。
换句话说就是在这样的情况下从电路上就没办法检测出SW5了。
对于这样的检测结果,最好的处理办法就是认为它就是上一次的键码。
于是,我们先在表格里删除这些扫描结果重复了的行(一共有34行,超过了一半)。

回到IDE里面,Key_Buffer这个变量是在偶数轮扫描完成之后得到结果的,也就是我们的扫描键值。
那么最简单的处理方式就是:
  1.                 Key_Old_States=Key_States;
  2.                 switch(Key_Buffer)
  3.                 {
  4.                 case 51:Key_States=36;break;
  5.                 case ……
  6.                 }
复制代码

虽然就已经删除了三十多行,可还有三十行呢,一个个数敲进去简直痛苦死了。那么我们继续:
我们发现,关键就在于“case 51:Key_States=36;break;”,如果能够自动生成这样的语句,那么就简单多了。
于是在W2单元格内敲入:
  1. ="case "&U2&":Key_States="&A2&";break;"
复制代码

向下填充:

开开心心将其复制进IDE里,代码就完成了。
最后别忘记补充一句“default:break;”
毕竟我们删除了那么多的重复键值,直接保持Key_State的结果不变就好了。

然后,Key_Press和Key_Bottom_up怎么办呢?
很简单,检查到Key_States==Key_Old_States,那就可以认为没发生按键动作。
  1. Key_Press=((Key_States^Key_Old_States)&Key_States);
  2. Key_Bottom_up=((Key_States^Key_Old_States)&Key_Old_States);
复制代码


怎么根据按键来实现具体功能就不提了,大家都会的。等会沙发楼上完整代码。

按键扫描辅助编程.xls

95 KB, 阅读权限: 5, 下载次数: 29

最新回复

这个工程实际测试效果怎么样  详情 回复 发表于 2018-1-27 22:49

赞赏

3

查看全部赞赏

 
点赞(1) 关注(4)

回复
举报

1193

帖子

0

TA的资源

纯净的硅(高级)

沙发
 
本帖最后由 qiushenghua 于 2015-5-9 21:01 编辑





















  1. void Key_Scan()
  2. {
  3.         static unsigned char count=1;
  4.         static unsigned char Key_Buffer=0;
  5.         static unsigned char Key_States=0;
  6.         static unsigned char Key_Old_States=0;
  7.         if(count&0x01)//奇数轮
  8.         {
  9.                 unsigned char temp=0;
  10.                 temp=P1IN;
  11.                 Key_Buffer=((temp&0x07)<<4)+((temp&0x10)<<3);
  12.                 R1OUT();               
  13.         }
  14.         else//偶数轮
  15.         {
  16.                 Key_Buffer+=(P1IN&0x0f);
  17.                 R1OUT();
  18.                 Key_Old_States=Key_States;
  19.                 switch(Key_Buffer)
  20.                 {
  21.                         case 51:Key_States=36;break;
  22.                         case 85:Key_States=18;break;
  23.                         case 102:Key_States=9;break;
  24.                         case 143:Key_States=56;break;
  25.                         case 158:Key_States=49;break;
  26.                         case 159:Key_States=48;break;
  27.                         case 173:Key_States=42;break;
  28.                         case 175:Key_States=40;break;
  29.                         case 188:Key_States=35;break;
  30.                         case 189:Key_States=34;break;
  31.                         case 190:Key_States=33;break;
  32.                         case 191:Key_States=32;break;
  33.                         case 203:Key_States=28;break;
  34.                         case 207:Key_States=24;break;
  35.                         case 218:Key_States=21;break;
  36.                         case 219:Key_States=20;break;
  37.                         case 222:Key_States=17;break;
  38.                         case 223:Key_States=16;break;
  39.                         case 233:Key_States=14;break;
  40.                         case 235:Key_States=12;break;
  41.                         case 237:Key_States=10;break;
  42.                         case 239:Key_States=8;break;
  43.                         case 248:Key_States=7;break;
  44.                         case 249:Key_States=6;break;
  45.                         case 250:Key_States=5;break;
  46.                         case 251:Key_States=4;break;
  47.                         case 252:Key_States=3;break;
  48.                         case 253:Key_States=2;break;
  49.                         case 254:Key_States=1;break;
  50.                         case 255:Key_States=0;break;
  51.                         default:break;
  52.                 }
  53.                 Key_Press=((Key_States^Key_Old_States)&Key_States);
  54.                 Key_Bottom_up=((Key_States^Key_Old_States)&Key_Old_States);
  55.         }
  56.         count++;
  57. }
复制代码
 
 

回复

846

帖子

0

TA的资源

纯净的硅(中级)

板凳
 
多谢分享!!学习了
 
 
 

回复

3416

帖子

0

TA的资源

纯净的硅(高级)

4
 
真不错
顶一个,过段时间也许会用得上
 
个人签名

So TM what......?

 

 

回复

2886

帖子

0

TA的资源

五彩晶圆(初级)

5
 
赞一个,他山之石,可以攻玉
 
 
 

回复

57

帖子

0

TA的资源

一粒金砂(中级)

6
 
不错,很棒的方法
 
 
 

回复

172

帖子

3

TA的资源

一粒金砂(中级)

7
 
厉害啊
 
 
 

回复

2453

帖子

19

TA的资源

五彩晶圆(中级)

8
 
Mark,用电脑的时候看
 
个人签名    懒得很
 
 

回复

248

帖子

0

TA的资源

一粒金砂(中级)

9
 
不错不错,学习到了
 
 
 

回复

2549

帖子

0

TA的资源

五彩晶圆(初级)

10
 
好复杂的说。。。。。。。
 
 
 

回复

40

帖子

0

TA的资源

一粒金砂(中级)

11
 
学习了,顺便收藏
 
 
 

回复

458

帖子

1

TA的资源

一粒金砂(高级)

12
 
好资源,真心好楼主,学习学习,真心希望电子工程世界这个论坛越来越好,希望大家都能来支持楼主
 
 
 

回复

72

帖子

0

TA的资源

一粒金砂(高级)

13
 
6个按键有这么多组合啊!!!
我们一般用不上啊...
我这里有个项目也是6个按键...有长按,短按,组合按...程序我没有做得这么复杂...
 
 
 

回复

9803

帖子

24

TA的资源

版主

14
 
这个工程实际测试效果怎么样
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表