小弟的中断扫描键盘又来了,这次不能移位显示,求助


按键能在第1位数码管上显示,但不能移位显示,还望高手们帮忙看看。

现在遇到的问题是按键只在第一位显示,按什么显什么,但是不会到下一位显示,这不是我想要的,我想把按键都存到dispbuf[ i ]这个数组里面,然后把数组里面的数字显示出来。

“i++;”移位加在什么地方都没用。

附件里包括了proteus   跟   C

#include<reg51.h>
#include<absacc.h>
#include <string.h>
#include <intrins.h>
#define COM8155 XBYTE[0xff20] //8155控制口地址
#define PA XBYTE[0xff21] //8155A口地址
#define PB XBYTE[0xff22] //8155B口地址
#define uchar unsigned char
#define uint  unsigned int
#define SCANPORT P1

sbit P33=P3^3;
sbit P34=P3^4;
sbit P35=P3^5;

unsigned code seg[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //显示段位
unsigned dispbuf[8]={0}; //显示缓存
unsigned dispbit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //数位扫描
unsigned char uca_LineScan[4]={0xEF,0xDF,0xBF,0x7F};  //列线扫描电压,分为第1,2,3,4根列线
unsigned code pwd[8]={0};

uint key_code;
uchar i; //第几次按键
unsigned char key;

void change_pwd();
void check_pwd();
uchar keyscan();

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<防抖动标志>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
bit b_KeyShock=0;       //键盘防抖动标志位。
         //当按键中断产生时,首先判断此位。
         //0--执行键盘扫描及键码处理程序;1--不执行。
bit b_KillShock=0;     //防抖标志清除位:0--不清除;1--清除。


/**************************************************************************************/
void  delay(uint i)   
{
while(--i);
}
/**************************************************************************************/

/**************************************************************************************/
unsigned char keyscan(void)
{
unsigned char ucTemp=0;      //扫描状态暂存。
unsigned char ucRow=0,ucLine=0;     //行号,列号。
for(ucLine=0;ucLine<4;ucLine++)  //列扫描
  {
   SCANPORT=uca_LineScan[ucLine];     //输出扫描电位。
   ucTemp=SCANPORT&0x0F;       //输入扫描电位,并屏蔽高4位。
   if(ucTemp!=0x0F)   
    {           //判断该列是否有按键按下。
    switch(ucTemp)
     {
     case 0x0E: ucRow=10;break;    //如果有,则判断行号。
     case 0x0D: ucRow=20;break;
     case 0x0B: ucRow=30;break;
     case 0x07: ucRow=40;break;
     default:   ucRow=50;break;
     }
    break;
    }
  }
return ucRow+ucLine+1;   //返回按键编码。格式为2位数,高位为行号,低位为列号。
}
/***************************************************************************************/

/**************************************************************************************/
uint getkey(uint keycode)
{
switch(keycode)
{
case 11:key=7;break;
case 12:key=8;break;
case 13:key=9;break;
case 21:key=4;break;
case 22:key=5;break;
case 23:key=6;break;
case 31:key=1;break;
case 32:key=2;break;
case 33:key=3;break;
/* case 41:change_pwd();break;  */
case 42:key=0;break;
/* case 43:check_pwd();break;   */
default: break;
}
return(key);
}
/****************************************************************************************/


//*************************************************************************************************
//*                          *
//*  ***************************外部中断0,调用键盘扫描程序*************************     *
//*                          *
//*************************************************************************************************
void vINT0(void) interrupt 0
{
EX0=0;        //在键扫描处理时,关闭外部中断0,防抖动。
if(b_KeyShock==0)
  {
      //当判断有按键按下时,扫描键盘,并把扫描结果进行处理。
  key_code=keyscan();      //把按键存放
  b_KeyShock=1;    //设置防抖动标志。
  }
else b_KeyShock=0;    //如果有抖动则不执行键扫描,恢复防抖动标志。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<设置防抖动清除标志位 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
if(b_KeyShock==1)
  b_KillShock=1;    //如果防抖动标志位开启则开启防抖动标志清除位,
         //300ms后清除防抖动标志。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<恢复键扫描处理前初始状态 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
SCANPORT=0x0F;        //恢复P2口。
EX0=1;       //恢复按键中断。
i++;
}


/***************************************************************************************/
void display()
{
  uchar p;
  for(p=0;p<8;p++)
  {switch(p)
   {case 0:{P33=034=035=0;}break;
    case 1:{P33=134=035=0;}break;
case 2:{P33=034=135=0;}break;
case 3:{P33=134=135=0;}break;
case 4:{P33=034=035=1;}break;
case 5:{P33=134=035=1;}break;
case 6:{P33=034=135=1;}break;
case 7:{P33=134=135=1;}break;
default :  break;
   }
   P2=seg[dispbuf[p]];
   delay(20);
}
}
/***************************************************************************************/


void main()
{
SCANPORT=0x0F;               //初始化键盘接口。
EA=1;
EX0=1;
IT0=0;
while(1)
{
dispbuf=getkey(key_code);
display();
}

}


[ 本帖最后由 leolle 于 2008-7-24 10:15 编辑 ]

password2.rar
(2008-07-24 09:05:27, Size: 125 KB, Downloads: 17)


我也来说两句 查看全部回复

最新回复

  • vincent_tsai (2008-7-24 09:13:27)

    真是一篇好文章,頂一下..........樓主有空多多發表文章吧,造福廣大眾生.
  • panhearii (2008-7-24 09:21:01)

    budhy 真是辛苦了。。。
    楼主的中断函数太长了 按键的时候 DISPLAY得不到执行 是不是指这个??
  • leolle (2008-7-24 10:09:39)

    回飞弹舞:
        上次你们说我中断里面太复杂了,现在已经改过了,中断里面只调用了一道子函数,就是把键盘的行列码扫出来送给key_code,然后再在主程序里面去判断它真正的键值。

        现在遇到的问题是按键只在第一位显示,按什么显什么,但是不会到下一位显示,这不是我想要的,我想把按键都存到dispfuf这个数组里面,然后把数组里面的数字显示出来。

    [ 本帖最后由 leolle 于 2008-7-24 10:11 编辑 ]
  • panhearii (2008-7-24 10:51:01)

    你把上回我贴的程序 不经思考就全抄了。。。。。。。。。。
    b_KillShock=1;    //如果防抖动标志位开启则开启防抖动标志清除位,
             //300ms后清除防抖动标志。
    这都没改 300MS清抖动在哪呢???

    51是8位单片机 变量已CHAR为主 INT的处理时间要高出不少
    凌阳是16位的 也不宜用8位的变量

    是LOCK A那张图吧?
    你的附件中
    uchar i 从始至终都没变过 一直为0 所以被改变的自然也就只有第0位了

    你上面贴的程序里又出现了i++。。。。。。搞得都没耐心了
    楼主请更新附件

    正在继续看
  • leolle (2008-7-24 11:07:25)

    不好意思啊,那是我把i++删了以后保存的,你把i++加到哪里有效果吗?

    另外我问我们实验室一高手他说其实去抖可有可无的。

    再加上我自己把那几行删了也没什么关系。

    [ 本帖最后由 leolle 于 2008-7-24 11:09 编辑 ]
  • panhearii (2008-7-24 11:13:10)

    #include<reg51.h>
    #include<absacc.h>
    #include <string.h>
    #include <intrins.h>
    #define COM8155 XBYTE[0xff20] //8155控制口地址
    #define PA XBYTE[0xff21] //8155A口地址
    #define PB XBYTE[0xff22] //8155B口地址
    #define uchar unsigned char
    #define uint  unsigned int
    #define SCANPORT P1

    sbit P33=P3^3;
    sbit P34=P3^4;
    sbit P35=P3^5;

    unsigned code seg[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //显示段位
    unsigned dispbuf[8]={0}; //显示缓存
    unsigned dispbit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //数位扫描
    unsigned char uca_LineScan[4]={0xEF,0xDF,0xBF,0x7F};  //列线扫描电压,分为第1,2,3,4根列线
    unsigned code pwd[8]={0};

    uint key_code;
    uchar i; //第几次按键
    unsigned char key;

    void change_pwd();
    void check_pwd();
    uchar keyscan();

    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<防抖动标志>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    bit b_KeyShock=0;       //键盘防抖动标志位。
             //当按键中断产生时,首先判断此位。
             //0--执行键盘扫描及键码处理程序;1--不执行。
    bit b_KillShock=0;     //防抖标志清除位:0--不清除;1--清除。


    /**************************************************************************************/
    void  delay(uint i)   
    {
    while(--i);
    }
    /**************************************************************************************/

    /**************************************************************************************/
    unsigned char keyscan(void)
    {
    unsigned char ucTemp=0;      //扫描状态暂存。
    unsigned char ucRow=0,ucLine=0;     //行号,列号。
    for(ucLine=0;ucLine<4;ucLine++)  //列扫描
      {
       SCANPORT=uca_LineScan[ucLine];     //输出扫描电位。
       ucTemp=SCANPORT&0x0F;       //输入扫描电位,并屏蔽高4位。
       if(ucTemp!=0x0F)   
        {           //判断该列是否有按键按下。
        switch(ucTemp)
         {
         case 0x0E: ucRow=10;break;    //如果有,则判断行号。
         case 0x0D: ucRow=20;break;
         case 0x0B: ucRow=30;break;
         case 0x07: ucRow=40;break;
         default:   ucRow=50;break;
         }
        break;
        }
      }
    return ucRow+ucLine+1;   //返回按键编码。格式为2位数,高位为行号,低位为列号。
    }
    /***************************************************************************************/

    /**************************************************************************************/
    uint getkey(uint keycode)
    {
    switch(keycode)
    {
    case 11:key=7;break;
    case 12:key=8;break;
    case 13:key=9;break;
    case 21:key=4;break;
    case 22:key=5;break;
    case 23:key=6;break;
    case 31:key=1;break;
    case 32:key=2;break;
    case 33:key=3;break;
    /* case 41:change_pwd();break;  */
    case 42:key=0;break;
    /* case 43:check_pwd();break;   */
    default: break;
    }
    return(key);
    }
    /****************************************************************************************/


    //*************************************************************************************************
    //*                          *
    //*  ***************************外部中断0,调用键盘扫描程序*************************     *
    //*                          *
    //*************************************************************************************************
    void vINT0(void) interrupt 0
    {
    EX0=0;        //在键扫描处理时,关闭外部中断0,防抖动。
    if(b_KeyShock==0)
      {
          //当判断有按键按下时,扫描键盘,并把扫描结果进行处理。
      key_code=keyscan();      //把按键存放
      i++;if(i==8){i=0;}
      b_KeyShock=1;    //设置防抖动标志。
      }
    else b_KeyShock=0;    //如果有抖动则不执行键扫描,恢复防抖动标志。
    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<设置防抖动清除标志位 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    /*if(b_KeyShock==1)
      b_KillShock=1;    //如果防抖动标志位开启则开启防抖动标志清除位,
    */         //300ms后清除防抖动标志。
    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<恢复键扫描处理前初始状态 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    SCANPORT=0x0F;        //恢复P2口。
    EX0=1;       //恢复按键中断。

    }


    /***************************************************************************************/
    void display()
    {
      uchar p;
      for(p=0;p<8;p++)
      {switch(p)
       {case 0:{P33=034=035=0;}break;
        case 1:{P33=134=035=0;}break;
    case 2:{P33=034=135=0;}break;
    case 3:{P33=134=135=0;}break;
    case 4:{P33=034=035=1;}break;
    case 5:{P33=134=035=1;}break;
    case 6:{P33=034=135=1;}break;
    case 7:{P33=134=135=1;}break;
    default :  break;
       }
       P2=seg[dispbuf[p]];
       delay(20);
    }
    }
    /***************************************************************************************/


    void main()
    {

    SCANPORT=0x0F;               //初始化键盘接口。
    EA=1;
    EX0=1;
    IT0=0;

    while(1)
    {
    dispbuf=getkey(key_code);
    display();//
    }
    }

    这样就行了 你的键盘扫描还是有点问题 自己试了就知道
  • panhearii (2008-7-24 11:16:11)

    另外我问我们实验室一高手他说其实去抖可有可无的。
    这个仁者见仁 智者见智
    楼主看看你的程序 去抖没去好的 很惨~~~~

    那几行删不删都不影响程序运行 但是直接影响别人对你的看法
    你说我是觉得你懒呢 还是不懂呢 还是什么呢?

    我说话难听 请别见怪。。。。。。。。。。。。

    另:本人最近辞工回学校读书 为不增加父母负担 且保一日三餐 提供各种有偿服务
    邮箱 www.panheariii@hotmail.com

    [ 本帖最后由 panhearii 于 2008-7-24 11:19 编辑 ]
  • leolle (2008-7-24 11:24:38)

    还是不行啊

    现在虽然能移位,但好像按一次键能输入几次数,时序出了很大的问题。
  • leolle (2008-7-24 11:28:47)

    我在网上看到过一些例子,都是不断扫描键盘的,中断方式的没几个,有一个中断的但是也不能直接拿来用,所以我经过上次的经验再加上那个例子编出了这个。
  • leolle (2008-7-24 11:30:22)

    我下午再加个去抖上去试试。
  • panhearii (2008-7-24 11:31:33)

    所以说你的去抖有问题拉~~~我之前的那程序有
    300MS的延迟
    你补上试试

    由于我现在已经替换成STC的片子了 所以现在的按键全是用AD做的
    一个口接64个键 我是当3次扫描的键值都一致时 确认键值 然后3次扫描都为按键释放时 执行上一次的键值
    即松开按键才进行处理 没有标准的按键延迟去抖(不过我AD那做了软件滤波。。。还有一片104)

    另:本人最近辞工回学校读书 为不增加父母负担 且保一日三餐 提供各种有偿服务
    邮箱 www.panheariii@hotmail.com
  • leolle (2008-7-24 11:36:38)

    还记得我上次那个程序吗?
    上面加了按键释放以后你们说while那个地方是致命的问题。
  • panhearii (2008-7-24 11:43:45)

    因为上次你滥用WHILE(1)和BREAK
    这样做 领导是不会给你好脸色看的
    void delay(uint i)
    {
    while(i){i--;}
    }
    这样写 大家不至于鄙视你

    我再翻翻上次那程序
  • leolle (2008-7-24 15:03:35)

    你上午修改了以后用PROTEUS仿真能正确显示吗?
  • 绝处逢生 (2008-7-24 15:36:24)

    6#的程序无法编译通过啊。。。。。。。。。。。。。。。。。。。。。。。
  • 绝处逢生 (2008-7-24 15:41:56)

    我感觉难点在按键次数的获取,那个i值你能很好的获得吗?
  • panhearii (2008-7-24 15:55:04)

    P33=034=035=0;}break;
        case 1:{P33=134=035=0;}break
    复制过去时 笑脸被忽略了
    i值在取得键值后立即++
    键值能取 i就能变

    key_code=keyscan();      //把按键存放
      i++;if(i==8){i=0;}

    [ 本帖最后由 panhearii 于 2008-7-24 15:56 编辑 ]
  • leolle (2008-7-24 15:57:15)

    我试过了,在中断里面加
    delay(50);
    if(INT0==1)
            return;

    好像不行啊。扫出来的还是乱序的。
  • panhearii (2008-7-24 15:58:28)

    QUOTE:

    原帖由 leolle 于 2008-7-24 15:03 发表
    你上午修改了以后用PROTEUS仿真能正确显示吗?
    能正确显示 就是防抖动没做 i值乱加
  • leolle (2008-7-24 16:06:04)

    而且在中断里面加了延时以后只可以按一次键了