单片机 矩阵键盘实验 实验报告

  • 格式:doc
  • 大小:70.50 KB
  • 文档页数:9

实验五 矩阵键盘实验

一、实验内容

1、编写程序,做到在键盘上每按一个数字键(0-F)用发光二极管将该代码显示出来。按其它键退出。

2、加法设计计算器,实验板上有12个按键,编写程序,实现一位整数加法运算功能。可定义“A”键为“+”键,“B”键为“=”键。

二、实验目的

1、 学习独立式按键的查询识别方法。

2、 非编码矩阵键盘的行反转法识别方法。

三、实验说明

1、MCS51系列单片机的P0~P3口作为输入端口使用时必须先向端口写入“1”。

2、用查询方式检测按键时,要加入延时(通常采用软件延时10~20mS)以消除抖动。

3、识别键的闭合,通常采用行扫描法和行反转法。行扫描法是使键盘上某一行线为低电平,而其余行接高电平,然后读取列值,如读列值中某位为低电平,表明有键按下,否则扫描下一行,直到扫完所有行。

行反转法识别闭合键时,要将行线接一并行口,先让它工作在输出方式,将列线也接到一个并行口,先让它工作于输入方式,程序使CPU通过输出端口在各行线上全部送低电平,然后读入列线值,如此时有某键被按下,则必定会使某一列线值为0。然后,程序对两个并行端口进行方式设置,使行线工作于输入方式,列线工作于输出方式,并将刚才读得的列线值从列线所接的并行端口输出,再读取行线上输入值,那么,在闭合键所在行线上的值必定为0。这样,当一个键被接下时,必定可以读得一对唯一的行线值和列线值。

由于51单片机的并口能够动态地改变输入输出方式,因此,矩阵键盘采用行反转法识别最为简便。

行反转法识别按键的过程是:首先,将4个行线作为输出,将其全部置0,4个列线作为输入,将其全部置1,也就是向P1口写入0xF0;假如此时没有人按键,从P1口读出的值应仍为0xF0;假如此时1、4、7、0四个键中有一个键被按下,则P1.6被拉低,从P1口读出的值为0xB0;为了确定是这四个键中哪一个被按下,可将刚才从P1口读出的数的低四位置1后再写入P1口,即将0xBF写入P1口,使P1.6为低,其余均为高,若此时被按下的键是“4”,则P1.1被拉低,从P1口读出的值为0xBE;这样,当只有一个键被按下时,每一个键只有唯一的反转码,事先为12个键的反转码建一个表,通过查表就可知道是哪个键被按下了。

四、接线方法

键盘连接成4×4的矩阵形式,占用单片机P1口的8根线,行信号是P1.0-1.3,列信号是P1.4-1.7。

五、实验电路

参考学习板说明书P14。

六、参考程序

程序一:

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

功能:4*4矩阵键盘,LED显示所按的键

作者:txl

时间:2009-04

版本:V1.0

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

#include

#define uint unsigned int

#define uchar unsigned char

sbit wei1=P2^0;

uchar code table[]={0xC0,0xF9,0xA4,0xB0,

0x99,0x92,0x82,0xF8,

0x80,0x90,0x88,0x83,

0xC6,0xA1,0x86,0x8E};//共阳数码管码表

//全局变量

uchar num,temp,num1; //函数声明

void delay(uint z);

uchar keyscan();

void display(uchar aa);

void main()

{

num=1;

wei1=0;

P0=0xC0;

while(1)

{

display(keyscan());

}

}

void display(uchar aa)

{

P0=table[aa-1];

}

uchar keyscan()

{

P1=0xfe;

temp=P1;

temp=temp&0xf0;

while(temp!=0xf0)

{

delay(5);

temp=P1;

temp=temp&0xf0;

while(temp!=0xf0)

{

temp=P1; switch(temp)

{

case 0xee:num=1;

break;

case 0xde:num=2;

break;

case 0xbe:num=3;

break;

case 0x7e:num=4;

break;

}

while(temp!=0xf0)

{

temp=P1;

temp=temp&0xf0;

}

}

}

P1=0xfd;

temp=P1;

temp=temp&0xf0;

while(temp!=0xf0)

{

delay(5);

temp=P1;

temp=temp&0xf0;

while(temp!=0xf0)

{

temp=P1;

switch(temp)

{

case 0xed:num=5;

break;

case 0xdd:num=6;

break;

case 0xbd:num=7;

break;

case 0x7d:num=8;

break; }

while(temp!=0xf0)

{

temp=P1;

temp=temp&0xf0;

}

}

}

P1=0xfb;

temp=P1;

temp=temp&0xf0;

while(temp!=0xf0)

{

delay(5);

temp=P1;

temp=temp&0xf0;

while(temp!=0xf0)

{

temp=P1;

switch(temp)

{

case 0xeb:num=9;

break;

case 0xdb:num=10;

break;

case 0xbb:num=11;

break;

case 0x7b:num=12;

break;

}

while(temp!=0xf0)

{

temp=P1;

temp=temp&0xf0;

}

}

}

P1=0xf7;

temp=P1;

temp=temp&0xf0;

while(temp!=0xf0)

{

delay(5);

temp=P1;

temp=temp&0xf0;

while(temp!=0xf0)

{

temp=P1;

switch(temp)

{

case 0xe7:num=13;

break;

case 0xd7:num=14;

break;

case 0xb7:num=15;

break;

case 0x77:num=16;

break;

}

while(temp!=0xf0)

{

temp=P1;

temp=temp&0xf0;

}

}

}

return num;

}

void delay(uint z)

{

uint x,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--); }

程序二:

#include

#define U8 unsigned char

#define key_port P1

code U8

kcode[]={0xb7,0xbe,0xde,0xee,0xbd,0xdd,0xed,0xbb,0xdb,0xeb,0xd7,0xe7};

//反转码对应键值 0 1 2 3 4 5 6 7 8 9 A

B

code U8 disp[]={0xa0,0xbb,0x62,0x2a,0x39,0x2c,0x24,0xba,0x20,0x28,0xff};

U8 buf[4]={0,0,0,0};

U8 cnt=0;

U8 scn[]={0x7f,0xbf,0xdf,0xef};// 先点亮左边一个数码管

void delay_ms(U8 ms)

{ U8 i,j;

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

{ for(j=0;j

}

U8 key(void)

{ U8 a,r;

delay_ms(20); // 延时20毫秒,消除按键抖动

if(key_port == 0xf0) goto rn;

a = key_port;

key_port = a | 0x0f;

delay_ms(20);

a = key_port;

for (r = 0;r <= 11;r++)

{ if(a == kcode[r]) break;};

if(r > 11) r = 0xff; //0xff表示无效

rn: key_port = 0xf0;

return r;

}

void main(void)

{ U8 k,i,pf; // pf为按过加号键的标志

int p,p1,p2, // p1,p2为两个加数,p为和

TMOD = 0x01; // 设定时器0为模式1(16位)

TH0 = 0xee; // 晶振11.0592MHz,5mS

TL0 = 0;

TR0 = 1; // 开始计数

EA = 1; // 允许中断

ET0 = 1; // 定时器0中断允许

key_port = 0xf0;

pf = 0; // 清除加号标志

p = 0;