C51单片机4X4矩阵键盘检测程序问题

C51单片机4X4矩阵键盘检测程序问题,第1张

P3=0xfe;

//P3=0b1111

1110,令P30=0,同时令高四位为高电平,作好读端口准备(51IO特点)

temp=P3;

//读回P3口的状态

temp=temp&0xf0;

//temp&1111

0000,0与任何数结果为0,把temp变量的低四位屏蔽了,高四位因为任何数与1等于它本身,所以把高四位对应的端口状态读进来。

while(temp!=0xf0)

//上步处理后,高四为不全为1,说明有按键按下(结合矩阵键盘的电路结构才能理解,这里不方便上图)

{

delay(5);

temp=P3;

temp=temp&0xf0;//这三句跟上面重复,功能是软件消抖

while(temp!=0xf0)

//延时一段时间后判断还有按键按下,说明是真有按键按下,进入按键扫描与键值的判断,否则可能是意外抖动引起的,就不进行按键扫描。

{

temp=P3;

switch(temp)

我想注释完应该能读懂,关键是要理解矩阵键盘的扫描原理。

C51 P1端口 4X4键盘说明

这是一个用C51单片机P1端口制作的4X4键盘,p1端口低4位是键盘列扫描线,高4位是键盘行扫描线,

列扫描线是输出,行扫描线是输入。

下面就程序作一个说明

()表示注意点

1、首先判断整个键盘有无按下键,只要行扫描线输入不为全1,(1111)即有键按下;

P1 = 0xf0;if((P1&0xf0)!=0xf0) 如果无按键按下,全1,则返回return -1;

如果有键按下则延时,再次判断有无按键按下,Delay();if((P1&0xf0)!=0xf0)如果无按键按下则返回return -1。

有键按下则继续,这个过程就是判键消抖,避免多次读键值,或者因为按键抖动到读键值的时候无键按下,发生错误,列扫描线是输出全0,P1 = 0xf0。

2、进入读键值了,与上面不同,每一次判断,列扫描线只有一根输出为0,即P1=0xfe,0xfd,0xfb,0xf7;

首先列扫描线P10,sCode = 0xfe;如果行扫描线全1,则本列无键按下,扫描下一列

sCode = _crol_(sCode,1); sCode左移一位,即0xfd,如此扫描4次,行扫描线都全0,则无键按下,

返回return -1;

如果行扫描线不全0,就是有键按下,现在可以读键值了

kCode = ~P1; //P1=EE,ED

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

{

if(kCode == KeyCodeTable[i])

return i;

}

1首先kCode = ~P1;p1值取反行扫描线可能的是1,2,4,8;同样列扫描线对应值1,2,4,8

合起p1有16个值,就是KeyCodeTable[i]表的x11,0x12,0x14,0x18,0x21,0x22,0x24,0x28,

0x41,0x42,0x44,0x48,0x81,0x82,0x84,0x88

如果 if(kCode == KeyCodeTable[i]) 成立,对应的 i 值就是键号。

2返回i值就是键号,return i;。

uchar Keys_Scan()

{

uchar sCode,kCode,i,k;

P1 = 0xf0;

if((P1&0xf0)!=0xf0) //扫描列

{

Delay();

if((P1&0xf0)!=0xf0)//消抖

{

sCode = 0xfe;

for(k=0;k<4;k++)

{

P1 = sCode;//查找低位

if((P1&0xf0)!=0xf0)//只有等于才执行else P1和0xf0作与为0xf0 与 同真为真,一假为假

{

kCode = ~P1; //P1=EE,ED

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

{

if(kCode == KeyCodeTable[i])

return i;

}

}

else

sCode = _crol_(sCode,1);

}

}

}

return -1;

}

我这里有一个程序,

#include<reg51h>

#define rowkey() (~P2)&0x0f//键盘输入端

#define OUT P0                  //数码管显示输出端

unsigned char code TAB[]=

{  0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,

0x88,0x83,0xC6,0xA1,0x86,0x8E,0x89,0xC7,0xC8,0xC1,

0x8C,0xA3,0xBF,0xFF,0xFF

};

void debouncer()

{ int i;

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

}

void scanner()//键盘扫描程序

{ unsigned char data row,col;

unsigned char data scan;

unsigned char data keyin;

scan=0xef;

for(row=0;row<4;row++)

{ P2=scan;

keyin=rowkey();

debouncer();

if(keyin!=0)

{ for(col=0;col<4;col++)

{ keyin>>=1;

if(CY)

{ OUT=TAB[col4+row];//数码管显示

break;

}

}

}

scan=(scan<<1)|0x01;

}

}

void main()

{ while(1)

{ scanner();

}

}

#include<pich>//矩阵键盘与数码管:当s1按下时6个显示全0,当s2按下时6个显示全1,当s16按下时6个显示全F

#define uchar unsigned char//宏定义

#define uint unsigned int

__CONFIG(0x3b31);//设置配置位

const uchar table[]={0x3f,0x06,0x5b,0x4f,//注意code是用在51单片机中的程序储存器中,const是一个常量,pic和51的单片机也可以共用的常量,但要写在前头

0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71,0x20};//数码管数字表从0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,无显示

uchar key_num;//先定义一个变量为RB口低4位的检测

void delay(uint x);//声明

void init();

void scan();

void didi(uchar);

void disp();//在这里用的是静态显示全部管是一样的,所以不用加动态扫描时的变量

void main()

{

init();//调用初始化

while(1)//因为要不断地循环扫描键盘检测是否按下所以要进行死循环

{

scan();//调用键盘扫描程序

disp();//在调用键盘扫描的同时调用数码管

}

}

void delay(uint x)//延迟函数x表示毫秒

{

uint a,b;

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

for(b=110;b>0;b--);//嵌套

}

void init()

{

TRISB=0x0f;//因为RB口的高4位RB4-RB7为输出状态,低4位RB0-RB3为输入状态

TRISD=0;//因为RD接的是数码管段选设置全为输出状态

TRISE0=0;//设置RE0蜂鸣器为输出状态

TRISA=0;//设置数码管的位选为全输出状态

RE0=0;//先设置蜂鸣器为关闭不响

PORTD=0;//设置数码管的输出先全部关闭

PORTA=0xff;//设置数码管全部打开

}

void scan()//键盘扫描程序

{

/检测最后一行RB7是否有键按下/

uchar key_tem;//定义一个松手后才有变化的变量,可不加,但按下时数码管就会变化

PORTB=0x7f;//01111111先从最高位RB7开始,又因为低4位是输入状态,所以写什么都不影响,因为是不能输出的

key_num=PORTB;//将RB端口读回来

key_num=key_num&0x0f;//与00001111比较判断如果RB7这行的s13-s16是否有键按下,如果按下则RB低4位其中一个为0,再附给回key_num,这是判断哪一列

if(key_num!=0x0f)//判定运算与之后如果不等0x0f,则有按键按下

{

delay(10);//去抖,再判断多一次

key_num=PORTB;//将RB端口读回来附给key_num

key_num=key_num&0x0f;//与00001111比较判断如果RB7这行的s13-s16是否有键按下,如果按下则RB低4位其中一个为0,再附给回key_num,这是判断哪一列

if(key_num!=0x0f)//确定不等于0x0f,有键按下但未知是哪一列

{ //////////////////////////////////////////////////////松手后才有变化,可不加

key_tem=key_num;//将key_num也同时附给tem,这样就不影响松手后才能读到key_num的附回的值了,为作松手后才有变化

didi(1);//调用蜂鸣器

while(key_tem!=0x0f)//这个是松手检测,如果不加则按下的同时数码管就会有变化

{

key_tem=PORTB;//将RB端口读回来附给key_tem

key_tem=key_tem&0x0f;//与00001111比较

}//////////////////////////////////////////////////////松手后才有变化,可不加

key_num=key_num|0x70;//和01110000运算或比较,到这里0x7f先是和0x0f与运算但未知是哪一列,再和0x70或运算判断哪一列得出了具体的按键,再附给回key_num

}

}

/检测第三行RB6是否有键按下/

else

{

PORTB=0xbf;//10111111检测第三行RB6因为低4位是输入状态,所以写什么都不影响,因为是不能输出的

key_num=PORTB;//将RB端口读回来

key_num=key_num&0x0f;//与00001111比较判断如果RB6这行的s9-s12是否有键按下,如果按下则RB低4位其中一个为0,再附给回key_num,这是判断哪一列

if(key_num!=0x0f)//判定运算与之后如果不等0x0f,则有按键按下

{

delay(10);//去抖,再判断多一次

key_num=PORTB;//将RB端口读回来附给key_num

key_num=key_num&0x0f;//与00001111比较判断如果RB6这行的s9-s12是否有键按下,如果按下则RB低4位其中一个为0,再附给回key_num,这是判断哪一列

if(key_num!=0x0f)//确定不等于0x0f,有键按下但未知是哪一列

{ //////////////////////////////////////////////////////松手后才有变化,可不加

key_tem=key_num;//将key_num也同时附给tem,这样就不影响松手后才能读到key_num的附回的值了,为作松手后才有变化

didi(1);//调用蜂鸣器

while(key_tem!=0x0f)//这个是松手检测,如果不加则按下的同时数码管就会有变化

{

key_tem=PORTB;//将RB端口读回来附给key_tem

key_tem=key_tem&0x0f;//与00001111比较

}//////////////////////////////////////////////////////松手后才有变化,可不加

key_num=key_num|0xb0;//和10110000运算或比较,到这里0xbf先是和0x0f与运算但未知是哪一列,再和0xb0或运算判断哪一列得出了具体的按键,再附给回key_num

}

}

/在第一个else里继续第二个else检测第二行RB5是否有键按下/

else

{

PORTB=0xdf;//11011111检测第二行RB5因为低4位是输入状态,所以写什么都不影响,因为是不能输出的

key_num=PORTB;//将RB端口读回来

key_num=key_num&0x0f;//与00001111比较判断如果RB5这行的s5-s8是否有键按下,如果按下则RB低4位其中一个为0,再附给回key_num,这是判断哪一列

if(key_num!=0x0f)//判定运算与之后如果不等0x0f,则有按键按下

{

delay(10);//去抖,再判断多一次

key_num=PORTB;//将RB端口读回来附给key_num

key_num=key_num&0x0f;//与00001111比较判断如果RB5这行的s5-s8是否有键按下,如果按下则RB低4位其中一个为0,再附给回key_num,这是判断哪一列

if(key_num!=0x0f)//确定不等于0x0f,有键按下但未知是哪一列

{ //////////////////////////////////////////////////////松手后才有变化,可不加

key_tem=key_num;//将key_num也同时附给tem,这样就不影响松手后才能读到key_num的附回的值了,为作松手后才有变化

didi(1);//调用蜂鸣器

while(key_tem!=0x0f)//这个是松手检测,如果不加则按下的同时数码管就会有变化

{

key_tem=PORTB;//将RB端口读回来附给key_tem

key_tem=key_tem&0x0f;//与00001111比较

}//////////////////////////////////////////////////////松手后才有变化,可不加

key_num=key_num|0xd0;//和11010000运算或比较,到这里0xdf先是和0x0f与运算但未知是哪一列,再和0xd0或运算判断哪一列得出了具体的按键,再附给回key_num

}

}

/在第二个else里继续第三个else检测第一行RB4是否有键按下/

else

{

PORTB=0xef;//11101111检测第一行RB4因为低4位是输入状态,所以写什么都不影响,因为是不能输出的

key_num=PORTB;//将RB端口读回来

key_num=key_num&0x0f;//与00001111比较判断如果RB4这行的s1-s4是否有键按下,如果按下则RB低4位其中一个为0,再附给回key_num,这是判断哪一列

if(key_num!=0x0f)//判定运算与之后如果不等0x0f,则有按键按下

{

delay(10);//去抖,再判断多一次

key_num=PORTB;//将RB端口读回来附给key_num

key_num=key_num&0x0f;//与00001111比较判断如果RB4这行的s1-s4是否有键按下,如果按下则RB低4位其中一个为0,再附给回key_num,这是判断哪一列

if(key_num!=0x0f)//确定不等于0x0f,有键按下但未知是哪一列

{ //////////////////////////////////////////////////////松手后才有变化,可不加

key_tem=key_num;//将key_num也同时附给tem,这样就不影响松手后才能读到key_num的附回的值了,为作松手后才有变化

didi(1);//调用蜂鸣器

while(key_tem!=0x0f)//这个是松手检测,如果不加则按下的同时数码管就会有变化

{

key_tem=PORTB;//将RB端口读回来附给key_tem

key_tem=key_tem&0x0f;//与00001111比较

}//////////////////////////////////////////////////////松手后才有变化,可不加

key_num=key_num|0xe0;//和11100000运算或比较,到这里0xef先是和0x0f与运算但未知是哪一列,再和0xe0或运算判断哪一列得出了具体的按键,再附给回key_num

}

}

}

}

}

}

void didi(uchar num)//蜂鸣器程序,num表示响多少声

{

uchar di_num;

for(di_num=num;di_num>0;di_num--)

{

RE0=1;//蜂鸣器响

delay(100);//响100ms

RE0=0;//蜂鸣器关闭

delay(50);//关闭50ms

}

}

void disp()//数码管

{

switch(key_num)//多选择语句,这前提要知道它的值再相应输出相对应的数

{

case 0xee:PORTD=table[0];break;//0xee(01110111)表示第一个键按下时,段选显示0字,位选在初始化中已打开

case 0xed:PORTD=table[1];break;

case 0xeb:PORTD=table[2];break;

case 0xe7:PORTD=table[3];break;

case 0xde:PORTD=table[4];break;

case 0xdd:PORTD=table[5];break;

case 0xd7:PORTD=table[6];break;

case 0xbe:PORTD=table[7];break;

case 0xbd:PORTD=table[8];break;

case 0xbb:PORTD=table[10];break;

case 0xb7:PORTD=table[11];break;

case 0x7e:PORTD=table[12];break;

case 0x7d:PORTD=table[13];break;

case 0x7b:PORTD=table[14];break;

case 0x77:PORTD=table[15];break;

}

}

/按键扫描函数/

void keyScan(void)

{

//P3=0x00;

col1=0;col2=1;col3=1;col4=1;

temp=P2&0x3f;

if(col1==0) //假设第一列有按键

{

if(temp!=0x3f) //没有按键退出这次对第一列键盘扫描

{

temp=P2&0x3C; // 3CH=00111100,目的是先把P22、P23、P24、P25 这中间四位先置1,即预读先置1,做好输入的准备

switch(temp)

{

case 0x38: key=12; break;

// 38H=00111000,只看中间四位,其中只有P22=0,代表第4行第1列为低电平,所在键值恰好是12(即C)

case 0x34:key=8;break;

// 34H=00110100,只看中间四位,其中只有P23=0,代表第3行第1列为低电平,所在键值恰好是8

case 0x2C:key=4;break;

// 2CH=00101100,只看中间四位,其中只有P24=0,代表第2行第1列为低电平,所在键值恰好是4

case 0x1C:key=0;break;

// 1CH=00011100,只看中间四位,其中只有P25=0,代表第0行第1列为低电平,所在键值恰好是0

}

}

}

col1=1;col2=0;col3=1;col4=1;

temp=P2;

temp=temp&0x3f;

if(col2==0)

{

if(temp!=0x3f)

{

temp=P2&0x3C;

switch(temp)

{

case 0x38: key=13; break; //’0’键被按下时导通,则对应端口变为低电平

case 0x34:key=9;break;

case 0x2C:key=5;break;

case 0x1C:key=1;break;

}

}

}

col1=1;col2=1;col3=0;col4=1;

temp=P2;

temp=temp&0x3f;

if(temp!=0x3f)

{

temp=P2&0x3C;

switch(temp)

{

case 0x38: key=14; break; //’0’键被按下时导通,则对应端口变为低电平

case 0x34:key=10;break;

case 0x2C:key=6;break;

case 0x1C:key=2;break;

}

}

col1=1;col2=1;col3=1;col4=0;

temp=P2;

temp=temp&0x3f;

if(temp!=0x3f)

{

temp=P2&0x3C;

switch(temp)

{

case 0x38: key=15; break; //’0’键被按下时导通,则对应端口变为低电平

case 0x34:key=11;break;

case 0x2C:key=7;break;

case 0x1C:key=3;break;

}

}

}

定义一个按键缓冲区

用普通的按键扫描程序,当扫描到有按键按下的时候。按键键的值写入缓冲区。继续扫描直到完成。

然后返回缓冲区地址就可以得到多个按键的数据了。

这样只要定义16字节的缓冲区全部按键都能检测到。(一般不需要那么多6个足够)

还有一种方式 是 如果只返回2个按键的话。

可以这样

常规按键扫描 返回范围在0-15也就是0-F

读取到一个值后把这个值左移4位

再继续读取。当读取到第二个值的时候与上第一个值。就能获取2个按键的值了。

以上就是关于C51单片机4X4矩阵键盘检测程序问题全部的内容,包括:C51单片机4X4矩阵键盘检测程序问题、C51矩阵键盘扫描 请解释一下程序 特别是关键步骤 急!!!、求基于8051单片机用C语言编写的双矩阵键盘扫描程序(5个IO口控制25个按键)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9313857.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-27
下一篇 2023-04-27

发表评论

登录后才能评论

评论列表(0条)

保存