微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 用逐行扫描法读取4X4键盘矩阵,不能扫描出第一列按键?

用逐行扫描法读取4X4键盘矩阵,不能扫描出第一列按键?

时间:10-02 整理:3721RD 点击:



问题描述:
用逐行扫描法能够检测出按键2 3 4  ,6 7 8 ,10 11 12 ,14 15 16,不能检测出1 5 9 13,而且不能从1 5 9 13 中退出来,估计是进入了死循环,但是我找了好久,都没发现哪里有问题,求帮忙看下一下。

以下是C语言程序:

/*  逐行扫描法在数码管上显示相应按键编号 */
#include <reg51.h>
#define uchar unsigned char
#define DIG P0    //数码管对应接口
uchar num,temp;   //两个全局变量,数码管显示数字用num,temp是扫描控制变量
uchar code DIG_NUM[16]={~0x3f,~0x06,~0x5b,~0x4f,~0x66,~0x6d,~0x7d,~0x07,~0x7f,~0x6f,
                        ~0x77,~0x7c,~0x39,~0x5e,~0x79,~0x71};//0~F
void display();//按键扫描函数
void delay();//延时函数
void main()
{
    DIG=0xff; //数码管全灭
    while(1)
    {
        display();
    }
}
void display()     //逐行扫描法
{
    P3=0xfe;       //扫描第一行
    temp=P3&0xf0;  
    if(temp!=0xf0)
    {
        delay();
        temp=P3&0xf0;
        if(temp!=0xf0)
        {
            temp=P3;
            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=P3&0xf0;
            }
            DIG = DIG_NUM[num-1];  
        }
    }
    P3=0xfd;       //扫描第二行
    temp=P3&0xf0;
    if(temp!=0xf0)
    {
        delay();
        temp=P3&0xf0;
        if(temp!=0xf0)
        {
            temp=P3;
            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=P3&0xf0;
            }
            DIG = DIG_NUM[num-1];  
        }
    }
    P3=0xfb;       //扫描第三行
    temp=P3&0xf0;
    if(temp!=0xf0)
    {
        delay();
        temp=P3&0xf0;
        if(temp!=0xf0)
        {
            temp=P3;
            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=P3&0xf0;
            }
            DIG = DIG_NUM[num-1];  
        }
    }
    P3=0xf7;       //扫描第四行
    temp=P3&0xf0;
    if(temp!=0xf0)
    {
        delay();
        temp=P3&0xf0;
        if(temp!=0xf0)
        {
            temp=P3;
            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=P3&0xf0;
            }
            DIG = DIG_NUM[num-1];  
        }
    }
}
void delay()
{
    uchar a;
    for(a=500;a>0;a--);
}

各位前辈,再次谢了!

建议找成熟稳定的程序抄。以下程序来自好书《51单片机轻松入门-基于STC15W4K系列》
#include "STC15W4K.H"      // 注意宏定义后面没分号       
#include "KEY.H"
#include "Dynamic_Display.H"   // 动态显示相关
extern           unsigned char DispBuf[6];   // 6字节的显示缓冲区,DispBuf[0]是最低位;
#define         Hidden         16               // 高位消隐码在数据表中的位置,DispTab[15]=0xff
void delay10ms(void)          // 22.1184MHz
{
   unsigned char i,j,k;
   for(i=2;i>0;i--)       // 注意后面没分号
   for(j=114;j>0;j--)     // 注意后面没分号
   for(k=241;k>0;k--);    // 注意后面有分号
}
unsigned char  KeyScan()
{
        unsigned char key=0xff;     // 无键按下时,key=0xff;
        P2=0x0f;                                // 在IO口由输出方式变为输入方式时要延迟一个时钟周期。
        P2=0x0f;                                // 采取写2次的方法延时。
        if (P2!=0x0f)        
        {
                delay10ms();                // 键盘消抖,延时10MS
                if (P2!=0x0f)                         // 有键按下
                {                                            
                        P2=0xef;                                   // 扫描第1列(逐列扫描开始)
                        P2=0xef;                                   
                        switch (P2)                        
                        {
                                case 0xe7:key=0x00;break;
                                case 0xeb:key=0x04;break;
                                case 0xed:key=0x08;break;
                                case 0xee:key=0x0c;break;
                        }   
//说明:本switch语句执行结束后会接着执行下面的语句,但由于P2口输出的扫描码
//      发生变化,程序不会进入后面的switch语句,也就不会多次修改key值。
                        P2=0xdf;                                   // 扫描第2列(逐列扫描开始)
                        P2=0xdf;                                   
                        switch (P2)                        
                        {
                                case 0xd7:key=0x01;break;
                                case 0xdb:key=0x05;break;
                                case 0xdd:key=0x09;break;
                                case 0xde:key=0x0d;break;
                        }   
                        P2=0xbf;                                   // 扫描第3列(逐列扫描开始)
                        P2=0xbf;                                   
                        switch (P2)                        
                        {
                                case 0xb7:key=0x02;break;
                                case 0xbb:key=0x06;break;
                                case 0xbd:key=0x0a;break;
                                case 0xbe:key=0x0e;break;
                        }   
                        P2=0x7f;                                   // 扫描第4列(逐列扫描开始)
                        P2=0x7f;                                   
                        switch (P2)                        
                        {
                                case 0x77:key=0x03;break;
                                case 0x7b:key=0x07;break;
                                case 0x7d:key=0x0b;break;
                                case 0x7e:key=0x0f;break;
                        }   
                        P2=0x0f;                                   // 在IO口由输出方式变为输入方式时要延迟一个时钟周期。
                        P2=0x0f;                                   // 采取写2次的方法延时。
                        while(P2!=0x0f);                   // 等待按键释放
                }
        }
        return(key);
}  
void KeyHandle(unsigned char KeyValue)
{
        DispBuf[0] = KeyValue;                        // 个位显示按键值
    DispBuf[5] = Hidden;                        // 十万位消隐
        DispBuf[4] = Hidden;                        // 万位消隐
        DispBuf[3] = Hidden;                        // 千位消隐
        DispBuf[2] = Hidden;                        // 百位消隐
        DispBuf[1] = Hidden;                        // 十位消隐
}

谢谢,按书中列扫描的方式问题可以解决!但是按行扫描还是不行,依旧是第一列不能扫描,请问这是什么原因呢?
以下是两种扫描方式的C语言源程序:
/*  逐行扫描法(按列扫描)在数码管上显示相应按键编号 */
#include <reg51.h>
#define uchar unsigned char
#define DIG P0    //数码管对应接口
uchar code DIG_NUM[]={~0x3f,~0x06,~0x5b,~0x4f,~0x66,~0x6d,~0x7d,~0x07,~0x7f,~0x6f,
                      ~0x77,~0x7c,~0x39,~0x5e,~0x79,~0x71,~0x00};//0~F 最后一个不显示
uchar display(void);//按键扫描函数
void delay();//延时函数
uchar num;                        
void main()
{   
    num=17;         //无按键按下不显示
    while(1)
    {
        DIG=DIG_NUM[display()-1];
    }
}
uchar display(void)     //逐行扫描法
{
    P3=0x0f;      
    P3=0x0f;   
    if(P3!=0x0f)
    {
        delay();
        if(P3!=0x0f)
        {
            P3=0xef;//扫描第一列
            P3=0xef;
            switch(P3)
            {
                case 0xee: num=1;break;
                case 0xed: num=5;break;
                case 0xeb: num=9;break;
                case 0xe7: num=13;break;
             }
            P3=0xdf;//扫描第二列
            P3=0xdf;
            switch(P3)
            {
                case 0xde: num=2;break;
                case 0xdd: num=6;break;
                case 0xdb: num=10;break;
                case 0xd7: num=14;break;
             }
            P3=0xbf;//扫描第三列
            P3=0xbf;
            switch(P3)
            {
                case 0xbe: num=3;break;
                case 0xbd: num=7;break;
                case 0xbb: num=11;break;
                case 0xb7: num=15;break;
             }
            P3=0x7f;//扫描第四列
            P3=0x7f;
            switch(P3)
            {
                case 0x7e: num=4;break;
                case 0x7d: num=8;break;
                case 0x7b: num=12;break;
                case 0x77: num=16;break;
             }
            P3=0x0f;
            P3=0x0f;
            while(P3!=0x0f);//检测按键是否松开
        }
    }
    return num;
}
void delay()
{
    uchar a;
    for(a=100;a>0;a--);
}

/*  逐行扫描法(按行扫描)在数码管上显示相应按键编号 */
#include <reg51.h>
#define uchar unsigned char
#define DIG P0    //数码管对应接口
uchar code DIG_NUM[]={~0x3f,~0x06,~0x5b,~0x4f,~0x66,~0x6d,~0x7d,~0x07,~0x7f,~0x6f,
                      ~0x77,~0x7c,~0x39,~0x5e,~0x79,~0x71,~0x00};//0~F 最后一个不显示
uchar display(void);//按键扫描函数
void delay();//延时函数
uchar num;                        
void main()
{   
    num=17;         //无按键按下不显示
    while(1)
    {
        DIG=DIG_NUM[display()-1];
    }
}
uchar display(void)     //逐行扫描法
{
    P3=0xf0;      
    P3=0xf0;   
    if(P3!=0xf0)
    {
        delay();
        if(P3!=0xf0)
        {
            P3=0xfe;//扫描第一行
            P3=0xfe;
            switch(P3)
            {
                case 0xee: num=1;break;
                case 0xde: num=2;break;
                case 0xbe: num=3;break;
                case 0x7e: num=4;break;
             }
            P3=0xfd;//扫描第二行
            P3=0xfd;
            switch(P3)
            {
                case 0xed: num=5;break;
                case 0xdd: num=6;break;
                case 0xbd: num=7;break;
                case 0x7d: num=8;break;
             }
            P3=0xfb;//扫描第三行
            P3=0xfb;
            switch(P3)
            {
                case 0xeb: num=9;break;
                case 0xdb: num=10;break;
                case 0xbb: num=11;break;
                case 0x7b: num=12;break;
             }
            P3=0xf7;//扫描第四行
            P3=0xf7;
            switch(P3)
            {
                case 0xe7: num=13;break;
                case 0xd7: num=14;break;
                case 0xb7: num=15;break;
                case 0x77: num=16;break;
             }
            P3=0xf0;
            P3=0xf0;
            while(P3!=0xf0);//检测按键是否松开
        }
    }
    return num;
}
void delay()
{
    uchar a;
    for(a=100;a>0;a--);
}

我想问,根据你的电路连接,P3开始赋值0xfe。你觉得此时是选中第一行还是第四列?我怎么感觉你的应该是0x7f才能确保选择第一行

P3=0xfe是第一行(1 2 3 4),P3=0x7f第四列(4 8 12 16)啊,这个应该没什么问题,按行扫描不了我觉得是程序进入死循环无法退出,但是还找不出在哪里。

请注意,你的管脚是从下往上的,0Xfe说明,你的第一个1管脚处输出低电平,此时相当于选中最后一列,然后最后一列的哪个按键按下,例如S4按下,则8管脚点位等于1管脚等电位(低电平),于是你可以判断P3==0x7e,对应按键4。例如s8按下,则7管脚与1管脚等电位(低电平),于是你可以判断P3==0xbe,对应按键为8。以此类推

可以用temp=KEY2&0xf0,用&来判断第几行

受益匪浅受益匪浅受益匪浅

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top