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

键盘电路主要扫描方法有逐行扫描法以及反转扫描法,可惜课本上没有逐行扫描的程序,只有一个反转扫描的。
什么是逐行扫描呢?
书上是这么写的:

将接在4个列端的I/O引脚(Y1,Y2,Y3,Y4)置为输入,接在4个行端的I/O引脚(X1,X2,X3,X4)置为输出。
先定义键盘输入I/O口内部上拉电阻有效,当没有键按下时,读Y端得到高电平。

将X1,X2,X3,X4依次置零,另外三个置1,依次测试是哪一行键按下,根据读入的列值即可判断哪行哪列按下了。

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

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.课本

单片机 c

发表新评论