51单片机综合学习系统之矩阵键盘篇 《电子制作》2007年11月 站长原创,如需引用请注明出处

    大家好,通过以前的学习,我们已经对51单片机综合学习系统的使用方法及学习方式有所了解与熟悉,学会了单片机控制数码管显示的基本知识,体会到了综合学习系统的易用性与易学性,这一期我们将来一起学习矩阵键盘的基本原理与使用方法。

矩阵键盘应用实例

    本期介绍了独立按键的应用,独立按键具有编程简单但占用I/O口资源的特点,不适合在按键较多的场合应用。在实际应用中经常要用到输入数字、字母等功能,如电子密码锁、电话机键盘等一般都至少有12到16个按键,在这种情况下如果用独立按键的话显然太浪费I/O口资源,为此我们就引入了矩阵键盘的应用。

矩阵键盘简介

    矩阵键盘又称行列键盘,它是用四条I/O线作为行线,四条I/O线作为列线组成的键盘。在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4*4个。这种行列式键盘结构能有效地提高单片机系统中I/O口的利用率。

矩阵键盘的工作原理

    最常见的键盘布局如图1所示。一般由16个按键组成,在单片机中正好可以用一个P口实现16个按键功能,这也是在单片机系统中最常用的形式,4*4矩阵键盘的内部电路如图2所示。

 

图1 矩阵键盘布局图

 

 

图2 矩阵键盘内部电路图

    当无按键闭合时,P10~P13与P14~P17之间开路。当有键闭合时,与闭合键相连的两条I/O口线之间短路。判断有无按键按下的方法是:第一步,置列线P14~P17为输入状态,从行线P10~P13输出低电平,读入列线数据,若某一列线为低电平,则该列线上有键闭合。第二步,行线轮流输出低电平,从列线P14~P17读入数据,若有某一列为低电平,则对应行线上有键按下。综合一二两步的结果,可确定按键编号。但是键闭合一次只能进行一次键功能操作,因此须等到按键释放后,再进行键功能操作,否则按一次键,有可能会连续多次进行同样的键操作。

矩阵键盘软硬件设计实例

    本期以51单片机综合学习系统为硬件平台,介绍矩阵式键盘的编程方法。实验通过按下相应键后在一位数码管上显示出键值。0到16个键分别对应显示0到F。

 

 

图3 矩阵键盘实验演示图

1013硬件原理图

    本实验可以直接在配套开发板上完成,其硬件原理图如图4所示:

图4 硬件原理图

    根据4电路原理图,键盘扫描方法是:行线P10~P13为输出线,列线P14~P17为输入线。一开始单片机将行线(P10~P13)全部输出低电平,此时读入列线数据,若列线全为高电平则没有键按下,当列线有出现低电平时调用延时程序以此来去除按键抖动。延时完成后再判断是否有低电平,如果此时读入列线数据还是有低电平,则说明确实有键按下。最后一步确定键值。现在我们以第二行的S5键为例,若按下S5后我们应该怎么得到这个键值呢?当判断确实有键按下之后,行线轮流输出低电平,根据读入列线的数据可以确定键值。首先,单片机将P10输出为低电平,其它P11~P13输出高电平,此时读取列线的数据全为高电平,说明没有在第一行有键按下;其次,单片机将P11输出低电平,其它P10、P12、P13仍为高电平,此时再来读取列线数据,发现列线读到的数据有低电平,数值为1011(0x0B),如果我们的键盘布局已经确定,那么0x0B就代表S5的值了。转到S5键功能处理子程序就可以达到目的。

程序流程图

 

 

10-5 软件流程图

    51单片机综合学习系统资源丰富,可做实验有:8位LED数码管、32路LED、4x4矩阵键盘、4个直控键盘、蜂鸣器喇叭、继电器试验、I2C总线接口、SPI总线接口、160X液晶、128X64液晶、红外接收头接口、支持PS/2接口的104键标准键盘、步进电机驱动接口、ADC0832模/数转换接口、PC817光电耦合器、串行时钟芯片DS1302、温度传感器DS18B20接口、RS232串口通讯、外扩展接口以便外接更多的实验资源。

软件代码

/***************************************************************************/

/*杭州晶控电子有限公司*/

 

/*https://www.hificat.com*/

 

/*矩阵键盘测试程序*/

 

/*目标器件:AT89S51*/

 

/*晶振:11.0592MHZ*/

 

/*编译环境:Keil 7.50A*/

 

/***************************************************************************/

 

/*********************************包含头文件********************************/

 

#include<reg51.h>

 

/*********************************数码管表格********************************/

 

unsigned char table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,

 

0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};

 

/****************************************************************************

 

函数功能:延时子程序

 

入口参数:

 

出口参数:

 

****************************************************************************/

 

void delay(void)

 

{

 

unsigned char i,j;

 

for(i=0;i<20;i++)

 

for(j=0;j<250;j++);

 

}

 

/****************************************************************************

 

函数功能:LED显示子程序

 

入口参数:i

 

出口参数:

 

****************************************************************************/

 

void display(unsigned char i)

 

{

 

P2=0xfe;

 

P0=table[i];

 

}

 

/****************************************************************************

 

函数功能:键盘扫描子程序

 

入口参数:

 

出口参数:

 

****************************************************************************/

 

void keyscan(void)

 

{

 

unsigned char n;

 

//扫描第一行

 

P1=0xfe;

 

n=P1;

 

n&=0xf0;

 

if(n!=0xf0)

 

{

 

delay();

 

P1=0xfe;

 

n=P1;

 

n&=0xf0;

 

if(n!=0xf0)

 

{

 

switch(n)

 

{

 

case(0xe0):display(3);break;

 

case(0xd0):display(2);break;

 

case(0xb0):display(1);break;

 

case(0x70):display(0);break;

 

}

 

}

 

}

 

//扫描第二行

 

P1=0xfd;

 

n=P1;

 

n&=0xf0;

 

if(n!=0xf0)

 

{

 

delay();

 

P1=0xfd;

 

n=P1;

 

n&=0xf0;

 

if(n!=0xf0)

 

{

 

switch(n)

 

{

 

case(0xe0):display(7);break;

 

case(0xd0):display(6);break;

 

case(0xb0):display(5);break;

 

case(0x70):display(4);break;

 

}

 

}

 

}

 

//扫描第三行

 

P1=0xfb;

 

n=P1;

 

n&=0xf0;

 

if(n!=0xf0)

 

{

 

delay();

 

P1=0xfb;

 

n=P1;

 

n&=0xf0;

 

if(n!=0xf0)

 

{

 

switch(n)

 

{

 

case(0xe0):display(11);break;

 

case(0xd0):display(10);break;

 

case(0xb0):display(9);break;

 

case(0x70):display(8);break;

 

}

 

}

 

}

 

//扫描第四行

 

P1=0xf7;

 

n=P1;

 

n&=0xf0;

 

if(n!=0xf0)

 

{

 

delay();

 

P1=0xf7;

 

n=P1;

 

n&=0xf0;

 

if(n!=0xf0)

 

{

 

switch(n)

 

{

 

case(0xe0):display(15);break;

 

case(0xd0):display(14);break;

 

case(0xb0):display(13);break;

 

case(0x70):display(12);break;

 

}

 

}

 

}

 

}

 

/****************************************************************************

 

函数功能:主程序

 

入口参数:

 

出口参数:

 

****************************************************************************/

 

void main(void)

 

{

 

while(1)

 

{

 

keyscan();

 

}

 

}