打印

51单片机4X4矩阵键盘检测。。。为啥不行啊。。求大神

[复制链接]
13103|61
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hunxiyi|  楼主 | 2012-12-12 16:56 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 hunxiyi 于 2012-12-13 12:13 编辑

4X4矩阵键盘,四行依次与P3口的0、1、2、3口相连。。

四列依次与4、5、6、7口相连
      
编写下列程序。。。感觉没有什么问题。。但是烧进板子里,只有0、4、8、c可以显示,其它12个键都没效果、、
想了N天都没办法。。。请大神出马、、、
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit weix =  P2^7;
sbit duanx = P2^6;
uchar code table[] = {0x3f,0x06,0x5b,0x4f,
                                        0x66,0x6d,0x7d,0x07,
                                        0x7f,0x6f,0x77,0x7c,
                                        0x39,0x5e,0x79,0x71
                                        };
void init();
void keyscan();
void display();
void delay(uint x);
uchar i,key,k = 88;

void main()
{
        init();                        //初始化
        while(1)               
        {
                keyscan();                        //矩阵键盘扫描
                display();                        //显示
        }
}


void init()                           //初始化
{
        weix = 1;
        P0=0xea;
        weix = 0;

        P0 = 0x00;

        duanx = 1;
        P0 = 0x00;
        duanx = 0;
}

void keyscan()                         //矩阵键盘扫描
{
        uchar i,key;
        P3 = 0x0f;
        if(P3 != 0x0f)                 
        {
                delay(10);                                //按键是否按下检测延时
                if(P3 != 0x0f)                  
                {
                        P3 = 0xef;                        
                        for(i = 0;i < 4;i++)
                        {
                                key = P3  & 0x0f;         //屏蔽高四位,只对比检测到的第四位
                                switch(key)
                                {
                                        case 0x0e:k = i + 0;break;                                    
                                        case 0x0d:k = i + 4;break;
                                        case 0x0b:k = i + 8;break;
                                        case 0x07:k = i + 12;break                                            default:k = 88;    //经15楼朋友提示,加上这句话,程序就没问题了                                }
                                P3  = (P3 <<1) + 1;                 //P3口数据左移一位 再加1
                                if(k != 88)                 //在此次for循环中 switch中如果匹配到
                                        break;                 //k被重新赋值,则退出for循环
                        }
                        P3  = 0x0f;                          //松手检测
                        while(P3 != 0x0f)          //未松手则一直在此等待
                                ;                                  //松手则退出
                }
        }
}

void display()                                   //显示
{
        duanx = 1;
        P0 = table[k];
        duanx = 0;
}

void delay(uint x)
{
        uint j;
        while(x--)
                for(j=110;j>0;j--);
}

相关帖子

沙发
hunxiyi|  楼主 | 2012-12-12 17:00 | 只看该作者
期盼大神。。。我实在是无能为力了。。感觉思路很清晰啊

使用特权

评论回复
板凳
hunxiyi|  楼主 | 2012-12-12 17:06 | 只看该作者
我用这个键盘扫描程序替换就可以。。。这是为什么啊。。。这两个道理是一模一样的啊

void matrix_keyscan()
{
        P3 = 0x0f;
        if(P3 != 0x0f)
        {
                delay(10);                                //键盘是否按下 检测延时
                if(P3 != 0x0f)
                {                       
                        P3=0xf0;                //检测高4位,因低4位被拉低
                         switch(P3)        //此时按键被按下,高位必有1位也被拉低
                         {
                                 case 0xe0: key1=0; break;
                                 case 0xd0: key1=1; break;
                                 case 0xb0: key1=2; break;
                                 case 0x70: key1=3; break;
                         }

                         P3=0x0f;                //再检测低4位
                         switch(P3)        //为何加0—12可画图理解
                         {
                                 case 0x0E: key=key1+0; break;
                                 case 0x0D: key=key1+4; break;
                                 case 0x0B: key=key1+8; break;
                                 case 0x07: key=key1+12;break;
                         }
                        P3 = 0x0f;
                        while(P3 != 0x0f)        // 松手检测
                                ;
                }
        }
}

使用特权

评论回复
地板
ayb_ice| | 2012-12-12 17:27 | 只看该作者
U8 key_delay;
U8 key_number;


void scan_key(void)
{
        U8 x,k;

        P3 = 0x0f;
        x = P3;

        P3 = 0xf0;
        k = P3;

        k = x + k;
        if(k == 0xff){
                key_delay = 0;
                return;
        }

        if((key_delay < 100) && (++key_delay == 3)){
                key_number = k;                // 此处设置断点,用于记录按键号
        }
}

间隔5~100MS调用即可,在 “key_number = k;”处设置断点,按下按键记录按键号,按键号等于k值。

使用特权

评论回复
评分
参与人数 1威望 +2 收起 理由
duoduo1989 + 2 赞一个!
5
yirongfu| | 2012-12-12 18:05 | 只看该作者

                                       break;                 //k被重新赋值,则退出for循环
                        }
                        temp = 0x0f;                          //松手检测
//这里的temp被赋值,下面的while表达式括号内的条件就一直为False,temp不会自动同步P3的
                        while(temp != 0x0f)          //未松手则一直在此等待
                                ;                                  //松手则退出

问题似乎不在于只能检测到那四个键吧?

使用特权

评论回复
6
yirongfu| | 2012-12-12 18:08 | 只看该作者
两种代码的差异就在于你在前一种代码中设置了一个变量temp,您好好分析一下你的代码流程

使用特权

评论回复
7
hunxiyi|  楼主 | 2012-12-12 20:27 | 只看该作者
yirongfu 发表于 2012-12-12 18:08
两种代码的差异就在于你在前一种代码中设置了一个变量temp,您好好分析一下你的代码流程 ...

早上问老师,他接到个电话有事,急急忙忙的就看了一下说把P3用个变量代替试试。。。所以我才加了temp
之前是没有temp直接用变量p3的。。。仍然是不能正常工作,只能检测到0、4、8、12。。。

使用特权

评论回复
8
hunxiyi|  楼主 | 2012-12-12 20:38 | 只看该作者
ayb_ice 发表于 2012-12-12 17:27
U8 key_delay;
U8 key_number;

这程序也太简洁了吧。。。。。。好高级。。。可惜没看懂。。。。:Q

使用特权

评论回复
9
xuyaqi| | 2012-12-12 20:48 | 只看该作者
键扫描要求变输出脚电平读输入脚电平再来判断,可是你在变temp这时输出脚电平会变吗?

使用特权

评论回复
10
hunxiyi|  楼主 | 2012-12-12 21:13 | 只看该作者
xuyaqi 发表于 2012-12-12 20:48
键扫描要求变输出脚电平读输入脚电平再来判断,可是你在变temp这时输出脚电平会变吗? ...

我错了。。这个temp是后来加的。。。之前是直接用P3的。。。仍然是只能检测4个键。。
上面的代码我已经改过来了。。。麻烦你再劳神下

使用特权

评论回复
11
pc1969| | 2012-12-12 22:15 | 只看该作者
把P3改成按位操作可能才行

使用特权

评论回复
12
yirongfu| | 2012-12-13 01:47 | 只看该作者
可能你的思路真的是清晰的,可是你对51单片机的操作看来还比较混沌

1. 像 P3  = (P3 <<1) + 1; 这样的操作是在直接操作IO口的输入输出寄存器,而你的P3口一半是输入一半是输出,假设某个输入口被外部按键动作拉到地,你又同时给该口输出高电平,这个电气上比较危险。所以,建议输入口就是输入,输出口就是输出,不要变来变去,51跟其他单片机不一样,你往Port写数据,就直接变成输出并反映到引脚电平,不需要另外设置为输入或输出方向。回头来说,你这句的本意是前面赋的扫描初值的移位,但运行到这一步,左移符号前的P3实际是去读取口的当前状态,而不是原来的那个定值了(P3 = 0xef以及你所设想的移位后的值)。你的老师让你加个中间变量,估计他也是初步发现了这里的问题,所以,建议你在这里再自己细细分析一下,用单步调试跟踪一下应该能很快找到问题,也能让你更好地掌握。

2. 1楼和3楼的代码要实现的按键布局我理解是不一样的,好像硬件原理也不尽相同。楼主你要实现的是矩阵扫描16键,3楼是简单按键扫描,或者说是IO口扫描,仅8键。所以,不要被3楼的代码所牵引。如果实在没理解透按键扫描的原理,建议你就直接找些4×4的C代码贴过来改造一下,网上很多的。

3. 提问应该描述尽量详细些,比如哪几个口作为输入哪几个口作为输出(行和列都可以作为输入或输出),你的设计思路,同时最好把接口的电路贴上来,详细的描述可以节省大家的时间,也能尽快帮你找到问题。

以上意见仅供参考,希望对你有用。

使用特权

评论回复
评分
参与人数 2威望 +5 收起 理由
duoduo1989 + 3 很耐心的讲解 赞一个
hunxiyi + 2 赞一个!
13
hunxiyi|  楼主 | 2012-12-13 10:03 | 只看该作者
pc1969 发表于 2012-12-12 22:15
把P3改成按位操作可能才行

麻烦讲清楚点啊。。。。。我是菜鸟。。。。:(

使用特权

评论回复
14
ayb_ice| | 2012-12-13 10:08 | 只看该作者
hunxiyi 发表于 2012-12-12 20:38
这程序也太简洁了吧。。。。。。好高级。。。可惜没看懂。。。。

typedef unsigned char U8;

使用特权

评论回复
15
zhaoyu2005| | 2012-12-13 10:22 | 只看该作者
if(k != 88)                 //在此次for循环中 switch中如果匹配到
                                        break;                 //k被重新赋值,则退出for循环
问题在这儿,至于为什么,其实你用笔在纸上按程序执行顺序,写下各个变量的值,就清楚了,不知道是没掌握这个方法还是懒,如果养成用纸笔模拟程序运行的习惯,很多问题都会发现,不需要仿真器,也不需要问别人,熟练了速度还不慢
深说一点,你的按键扫描程序中的循环每次只执行了一次就结束了,至于为什么,还是自己发现吧

使用特权

评论回复
评分
参与人数 2威望 +4 收起 理由
duoduo1989 + 2 很给力!
hunxiyi + 2 很给力!
16
pc1969| | 2012-12-13 10:30 | 只看该作者
扫描键盘时,分别置位P3.0,P3.!,P3.2,P3.3,然后再检测P3.4,P3.5,P3.6,P3.7

使用特权

评论回复
17
hunxiyi|  楼主 | 2012-12-13 10:30 | 只看该作者
本帖最后由 hunxiyi 于 2012-12-13 10:49 编辑
yirongfu 发表于 2012-12-13 01:47
可能你的思路真的是清晰的,可是你对51单片机的操作看来还比较混沌

1. 像 P3  = (P3  ...

非常感谢你花这么多时间来为我解答,真的很感谢。。。
我确实是刚刚开始学。。感觉这个程序思路是很清晰的,但对于操作是一点头绪都没有
你说的单步调试跟踪,我还不会,现在去百度上学学。。。去
这个程序是我在网上找到的。。。最容易理解的矩阵键盘程序是书上写的,但太长了。。于是上网搜搜简单的。。。http://wenku.baidu.com/view/cd72f1bff121dd36a32d8253.html  发现了这个文件里最后一个程序感觉不错。。。于是按照我的这个线路加以改动
3楼那个也是我在网上看见的,稍微改一下确实可以运行。。。0——15都可以正常检测,你说的仅8键不太懂什么意思。。。

最后,这个帖子是第一次在这论坛发帖。。。不足之处你已指出,已经做出了一些修改。。以后绝对不会再犯!谢谢。。

使用特权

评论回复
18
hunxiyi|  楼主 | 2012-12-13 10:33 | 只看该作者
pc1969 发表于 2012-12-13 10:30
扫描键盘时,分别置位P3.0,P3.!,P3.2,P3.3,然后再检测P3.4,P3.5,P3.6,P3.7

那你的意思就是3楼那代码。。。对吧?

使用特权

评论回复
19
pc1969| | 2012-12-13 10:46 | 只看该作者
hunxiyi 发表于 2012-12-13 10:33
那你的意思就是3楼那代码。。。对吧?

直接用汇编写,直观又容易理解

使用特权

评论回复
20
hunxiyi|  楼主 | 2012-12-13 10:49 | 只看该作者
pc1969 发表于 2012-12-13 10:46
直接用汇编写,直观又容易理解

汇编不会;。。。。。比C难多了、、

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

41

帖子

0

粉丝