今天,跟同学讨论单片机的时候,在看到键盘电路的时候看到了逐行扫描法。 看着挺简单的,只是一到程序实现就感觉有点难了,结合百度加讨论弄明白了。

键盘电路主要扫描方法有逐行扫描法以及反转扫描法,可惜课本上没有逐行扫描的程序,只有一个反转扫描的。 什么是逐行扫描呢? 书上是这么写的: >将接在4个列端的I/O引脚(Y1,Y2,Y3,Y4)置为输入,接在4个行端的I/O引脚(X1,X2,X3,X4)置为输出。 先定义键盘输入I/O口内部上拉电阻有效,当没有键按下时,读Y端得到高电平。 将X1,X2,X3,X4依次置零,另外三个置1,依次测试是哪一行键按下,根据读入的列值即可判断哪行哪列按下了。

矩阵键盘原理图 矩阵键盘 嗯,确实挺容易理解的。跟同学商量的时候也是弄懂的差不多了,但是怎么用程序写出来的时候有点蒙了。 怎么实现?刚开始我想着干脆直接16个switch,然后感觉效率太低,同学往后一翻,反转扫描法跟这个程序差不多。 不能这么写啊!这重复度太高啦! 好吧,就直接百度吧。然后看到了程序,直接一看,还没弄懂,这么多与非加移位表达什么意思? 结合着图像加课本,总算弄懂啦!记录下来! 这个是百度上的程序,直接搬下来!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
unsigned char read_key(){
	unsigned char a,i,k=0xfe;
	for(i=0;i<4;i++){
		P1=k;
		if((P1&0xf0)!=0xf0){
			switch(P1&0xf0){
				case 0x70:
					a=(i<<2)+1;break;
				case 0xb0:
					a=(i<<2)+2;break;
				case 0xd0:
					a=(i<<2)+3;break;
				case 0xe0:
					a=(i<<2)+4;break;
				default:
					a=0;break;
			}
			return (a);
		}
		k=k<<1|0x01;
	}
	return (0);
}

这个就是逐行扫描法的核心代码了,其他的指定管脚都无关紧要。 根据程序中P1一直与0xf0进行与运算,可以看到将高四位作为输入端了,是否按下按键都是使用高四位的电压值进行判断的。 低四位作为单片机的输出端,即io口输出电平值控制开关轮流置0。 将这些弄明白了就开始看程序。 首先将k=0xfe,即二进制的1111 1110. 为了便于理解,这个相当于将x1置零(图片的5脚),x2,x3,x4置1(图片的678脚),y1到y4均为高电平(图片的1234管脚)。(下面就不解释x,y所代表的含义了。) 由于按键按下电平值就变成低电平了,所以务必置成高电平,要不然没法检测了。 然后i=0;相当于第一行按键,原因一会说。 为了方便说,就是p1=k后然后按键就按下啦,那么假设Y1被按下,则p1管脚值为0111 1110. 将p1与0xf0相与运算,得到结果就是0111 0000->0x70.就是按键1. 现在i的值为0,不管怎么移位都是0,加上1之后是0000 0001,就是16进制的1. return a就把按键返回啦。 很容易知道一个数左移2为将相当于乘以4,当i为1的时候,检测到了就是5,6,7,8. 其他类比。 最下面的k=k<<1|0x01;就是换x1,x2,x3,x4谁为0谁为1啦。当i为几,就正好是第几行置0。 这个肯定没法直接判断,得在死循环里一直执行,并且在if这个地方还最好加个延时函数作为去抖,要不然容易出错。这些就没必要多说啦。 我是看着课本说的,或许电路理解方式跟附图有点差别,不过无所谓,能理解就好.

参考文献: 1.百度文库 2.课本