標(biāo)題: 求助單片機(jī)矩陣按鍵的問(wèn)題,已經(jīng)調(diào)試了好多天了,謝謝 [打印本頁(yè)]

作者: guanyi12340    時(shí)間: 2018-5-2 21:48
標(biāo)題: 求助單片機(jī)矩陣按鍵的問(wèn)題,已經(jīng)調(diào)試了好多天了,謝謝
我已經(jīng)調(diào)試了好多天了,因?yàn)榘滋焐习啵砩喜庞袝r(shí)間,但是連續(xù)4,5個(gè)晚上都發(fā)現(xiàn)不了原因,目前已經(jīng)可以做到加法了,但是我只要一按鍵,比如按1,按一下馬上彈起,就會(huì)有N個(gè)1出現(xiàn)在8位數(shù)碼管上,出現(xiàn)多少根據(jù)按的時(shí)間決定,求好心人幫幫我。。我仿佛是知道因?yàn)槌绦蛴涗浟宋叶啻芜M(jìn)行了按1的操作,可是我在按鍵檢測(cè)的時(shí)候用了if(keysta[j]==0),相當(dāng)于按鍵彈起的時(shí)候才顯示1。我用的兩個(gè)74HC573接的8位數(shù)碼管,DUAN WEI兩個(gè)IO扣控制鎖存器的,拜謝了。。拜謝了。。

單片機(jī)源程序:
  1. #include<reg52.h>

  2. sbit L0=P1^0;                   //定義L0-L7小燈IO口
  3. sbit L1=P1^1;
  4. sbit L2=P1^2;
  5. sbit L3=P1^3;
  6. sbit L4=P1^4;
  7. sbit L5=P1^5;
  8. sbit L6=P1^6;
  9. sbit L7=P1^7;

  10. sbit o4=P3^0;                    //定義矩陣鍵盤IO口
  11. sbit o1=P3^1;
  12. sbit o2=P3^2;
  13. sbit o3=P3^3;
  14. sbit i1=P3^4;
  15. sbit i2=P3^5;
  16. sbit i3=P3^6;
  17. sbit i4=P3^7;

  18. sbit DUAN=P2^0;                                 //定義段選開(kāi)關(guān)
  19. sbit WEI=P2^1;                                 //定義位選開(kāi)關(guān)


  20. unsigned char ledbuff[8]={                       //數(shù)碼管顯示緩沖區(qū)
  21.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  22. };

  23. unsigned char duanma[]={                                                           //定義單個(gè)數(shù)碼管段位,顯示0-F
  24.         0x3f,0x06,0x5b,0x4f,
  25.         0x66,0x6d,0x7d,0x07,
  26.         0x7f,0x6f,0x77,0x7c,
  27.         0x39,0x5e,0x79,0x71
  28.         };
  29. unsigned char weima[]={                                                                   //定義單個(gè)數(shù)碼管位,顯示第幾個(gè)數(shù)碼管
  30.         0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe
  31.         };        

  32. unsigned char keysta[4][4]={                                                 //定義矩陣按鍵的當(dāng)前狀態(tài)
  33.         {1,1,1,1},
  34.         {1,1,1,1},
  35.         {1,1,1,1},
  36.         {1,1,1,1}
  37.         };
  38. unsigned char code keycodemap[4][4]={                                        //矩陣鍵盤標(biāo)準(zhǔn)鍵碼映射表
  39.         {0x31,0x32,0x33,0x26},                                                        //數(shù)字鍵1、數(shù)字鍵2、數(shù)字鍵3、加號(hào)
  40.         {0x34,0x35,0x36,0x25},                                                        //數(shù)字鍵4、數(shù)字鍵5、數(shù)字鍵6、減號(hào)
  41.         {0x37,0x38,0x39,0x28},                                                        //數(shù)字鍵7、數(shù)字鍵8、數(shù)字鍵9、乘號(hào)
  42.         {0x30,0x1b,0x0d,0x27}                                                        //數(shù)字鍵0、ESC鍵、  等號(hào)、   除號(hào)
  43. };

  44. void keydriver();

  45. unsigned char o=0;
  46. unsigned char cnt=0;

  47. void main()
  48. {

  49.         TMOD=0x01;          //計(jì)時(shí)器模式選擇為01,16位計(jì)時(shí)器
  50.         TH0=0xfc;          //為T0賦初值0xFC67,定時(shí)1ms
  51.         TL0=0x67;
  52.         TR0=1;                  //打開(kāi)計(jì)時(shí)器
  53.         EA=1;                  //打開(kāi)中斷總開(kāi)關(guān)
  54.         ET0=1;                  //打開(kāi)中斷T0
  55.         ledbuff[0]=duanma[0];

  56.         while(1)
  57.         {
  58.                 keydriver();                   //調(diào)用按鍵驅(qū)動(dòng)函數(shù)
  59.         }
  60. }



  61. void shownumber(unsigned long num)                           /* 將一個(gè)無(wú)符號(hào)長(zhǎng)整型的數(shù)字顯示到數(shù)碼管上,num-待顯示數(shù)字 */
  62. {

  63.         signed char i;
  64.         unsigned char buf[8];
  65.         for(i=0;i<8;i++)
  66.         {
  67.                 buf[i]=num%10;
  68.                 num=num/10;
  69.         }
  70.         L1=1;
  71.         for(i=7;i>=1;i--)                                                   //從最高位起,遇到0轉(zhuǎn)換為空格,遇到非0則退出循環(huán)
  72.         {
  73.                 if(buf[i]==0x00)
  74.                 {
  75.                         ledbuff[i]=0x00;
  76.                 }
  77.                 else
  78.                         break;
  79.         }
  80.         for(;i>=0;i--)                                                                 //剩余低位都如實(shí)轉(zhuǎn)換為數(shù)碼管顯示字符
  81.         {
  82.                 ledbuff[i]=duanma[buf[i]];
  83.         }
  84. }

  85. void keyaction(unsigned char keycode)
  86. {
  87.         static unsigned long result=0;                           //用于保存運(yùn)算結(jié)果
  88.         static unsigned long addend=0;                           //用于保存輸入的加數(shù)
  89.         if((keycode>=0x30)&&(keycode<=0x39))                //輸入0-9的數(shù)字
  90.         {
  91.                 addend=(addend*10)+(keycode-0x30);           //整體十進(jìn)制左移,新數(shù)字進(jìn)入個(gè)位
  92.                 shownumber(addend);                                                //運(yùn)算結(jié)果顯示到數(shù)碼管
  93.         }
  94.         else if(keycode==0x26)                   //按下加號(hào)
  95.         {
  96.                 result+=addend;
  97.                 addend=0;
  98.                 shownumber(result);
  99.         }
  100.         else if(keycode==0x0d)                        //按下等號(hào)
  101.         {
  102.                 result+=addend;
  103.                 addend=0;
  104.                 shownumber(result);
  105.         }
  106.         else if(keycode==0x1b)                         //按下ESC
  107.         {
  108.                 addend=0;
  109.                 result=0;
  110.                 shownumber(addend);
  111.         }
  112. }


  113. void keydriver()
  114. {
  115.         unsigned char i,j;
  116.         unsigned char backup[4][4]={                   //按鍵值備份,保存前一次的值
  117.         {1,1,1,1},
  118.         {1,1,1,1},
  119.         {1,1,1,1},
  120.         {1,1,1,1}
  121.         };
  122.         
  123.         for(i=0;i<4;i++)                                //循環(huán)檢測(cè)4*4的矩陣按鍵
  124.                 {
  125.                         for(j=0;j<4;j++)
  126.                         {
  127.                                 if(keysta[i][j]!=backup[i][j])                                //檢測(cè)按鍵動(dòng)作
  128.                                 {                                                                                    //按鍵按下時(shí)執(zhí)行動(dòng)作
  129.                                         if(keysta[i][j]==0)
  130.                                         {
  131.                                                 keyaction(keycodemap[i][j]);               //調(diào)用按鍵動(dòng)作函數(shù)
  132.                                         }
  133.                                 backup[i][j]=keysta[i][j];                                //刷新前一次的備份值
  134.                                 }

  135.                         }
  136.                 }
  137. }

  138. void keyscan()                                                                         //鍵盤消抖,檢測(cè)鍵盤是否按下
  139. {
  140.     static        unsigned char keyout=0;
  141.         unsigned char j;
  142.         static unsigned char keybuf[4][4]={
  143.         {0xff,0xff,0xff,0xff},
  144.         {0xff,0xff,0xff,0xff},
  145.         {0xff,0xff,0xff,0xff},
  146.         {0xff,0xff,0xff,0xff}
  147.         };
  148.         keybuf[keyout][0]=(keybuf[keyout][0]<<1)|i1;                        //消抖功能,對(duì)第一列鍵盤將keybuf[][]賦值為1111 1111或者0000 0000
  149.         keybuf[keyout][1]=(keybuf[keyout][1]<<1)|i2;
  150.         keybuf[keyout][2]=(keybuf[keyout][2]<<1)|i3;
  151.         keybuf[keyout][3]=(keybuf[keyout][3]<<1)|i4;

  152.         for(j=0;j<4;j++)
  153.         {
  154.                 if((keybuf[keyout][j])==0x00)                                //如果keybuf為0000 0000 則視為按下按鍵
  155.                 {
  156.                         keysta[keyout][j]=0;
  157.                 }
  158.                 else if((keybuf[keyout][j])==0xff)                         //如果keybuf為1111 1111 則視為彈起按鍵
  159.                 {
  160.                         keysta[keyout][j]=1;

  161.                 }
  162.         }



  163.         switch(keyout)                                                                         //對(duì)鍵盤進(jìn)行行掃描
  164.         {
  165.                 case 0:o4=1;o1=0;break;
  166.                 case 1:o1=1;o2=0;break;
  167.                 case 2:o2=1;o3=0;break;
  168.                 case 3:o3=1;o4=0;break;
  169.                 default:break;
  170.         }

  171.          keyout++;
  172.          keyout=keyout&0x03;                                                                  //keyout到4清0


  173.                
  174. }

  175. void ledscan()                                                                                        //鍵盤顯示函數(shù)
  176. {

  177.     static unsigned char i = 0;  //動(dòng)態(tài)掃描的索引
  178.         P0 = 0xFF;   //顯示消隱
  179.         switch(i)
  180.         {
  181.         case 0:
  182.                 WEI=1;P0=weima[0];WEI=0;DUAN=1;P0=ledbuff[0];i++;DUAN=0;break;                 //顯示個(gè)位
  183.         case 1:
  184.                 WEI=1;P0=weima[1];WEI=0;DUAN=1;P0=ledbuff[1];i++;DUAN=0;break;                 //顯示十位
  185.         case 2:
  186.                 WEI=1;P0=weima[2];WEI=0;DUAN=1;P0=ledbuff[2];i++;DUAN=0;break;                 //顯示百位
  187.         case 3:                        
  188.                 WEI=1;P0=weima[3];WEI=0;DUAN=1;P0=ledbuff[3];i++;DUAN=0;break;
  189.         case 4:                        
  190.                 WEI=1;P0=weima[4];WEI=0;DUAN=1;P0=ledbuff[4];i++;DUAN=0;break;
  191.         case 5:                        
  192.                 WEI=1;P0=weima[5];WEI=0;DUAN=1;P0=ledbuff[5];i++;DUAN=0;break;
  193.         case 6:                        
  194.                 WEI=1;P0=weima[6];WEI=0;DUAN=1;P0=ledbuff[6];i++;DUAN=0;break;
  195.         case 7:
  196.                 WEI=1;P0=weima[7];WEI=0;DUAN=1;P0=ledbuff[7];i++;DUAN=0;break;
  197.         default:i=0;break;
  198.         }
  199. }

  200. void interrupttimer0() interrupt 1                        //定時(shí)中斷檢測(cè)鍵盤,刷新數(shù)碼管
  201. {



  202.         TH0=0xfc;
  203.         TL0=0x67;
  204.         keyscan();   //調(diào)用按鍵掃描函數(shù)
  205.         ledscan();   //調(diào)用數(shù)碼管顯示掃描函數(shù)






  206. }
復(fù)制代碼

作者: HC6800-ES-V2.0    時(shí)間: 2018-5-3 08:25
根據(jù)你所說(shuō)的:可是我在按鍵檢測(cè)的時(shí)候用了if(keysta[j]==0),相當(dāng)于按鍵彈起的時(shí)候才顯示1。

這個(gè)是沒(méi)有用的。
試想:在按鍵的抖動(dòng)時(shí),是不是會(huì)有很多次的等于零,而你的程序卻判斷有零就顯示,這與沒(méi)有消抖是一回事嘛。

所以,我的建議是:先消抖,就是延時(shí)啊,按下看時(shí)10ms左右,松開(kāi)也延時(shí)10ms左右。要先消抖,穩(wěn)定后才用你的判斷是否顯示。

這個(gè)應(yīng)該是很基礎(chǔ)的了,你不會(huì)沒(méi)有例子吧?!
給你一個(gè):
/*******************************************************************************
* 函 數(shù) 名         : KeyDown
* 函數(shù)功能                   : 檢測(cè)有按鍵按下并讀取鍵值
* 輸    入         : 無(wú)
* 輸    出         : 無(wú)
*******************************************************************************/
void KeyDown(void)
{
        char a=0;
        GPIO_KEY=0x0f;
        if(GPIO_KEY!=0x0f)//讀取按鍵是否按下
        {
                Delay10ms();//延時(shí)10ms進(jìn)行消抖
                if(GPIO_KEY!=0x0f)//再次檢測(cè)鍵盤是否按下
                {
                       
                        //測(cè)試列
                        GPIO_KEY=0X0F;
                        switch(GPIO_KEY)
                        {
                                case(0X07):        KeyValue=0;break;
                                case(0X0b):        KeyValue=1;break;
                                case(0X0d): KeyValue=2;break;
                                case(0X0e):        KeyValue=3;break;
                        }
                        //測(cè)試行
                        GPIO_KEY=0XF0;
                        switch(GPIO_KEY)
                        {
                                case(0X70):        KeyValue=KeyValue;break;
                                case(0Xb0):        KeyValue=KeyValue+4;break;
                                case(0Xd0): KeyValue=KeyValue+8;break;
                                case(0Xe0):        KeyValue=KeyValue+12;break;
                        }
                        while((a<50)&&(GPIO_KEY!=0xf0))         //檢測(cè)按鍵松手檢測(cè)
                        {
                                Delay10ms();
                                a++;
                        }
                }
        }
}

這個(gè)例子程序,會(huì)返回按下鍵的值——從而可以判斷按下的是哪個(gè)鍵,你可以再根據(jù)返回的鍵值進(jìn)行你程序需要的操作,比你的程序好多了,特別是消抖。
作者: wulin    時(shí)間: 2018-5-3 09:12
樓主的按鍵掃描程序缺少自鎖語(yǔ)句,導(dǎo)致長(zhǎng)按時(shí)重復(fù)響應(yīng),推薦一款精簡(jiǎn)的4*4按鍵掃描程序和按鍵服務(wù)程序參考。
#define value 10                                //中斷周期1ms  消抖延時(shí) 10
unsigned char KeySec=0;                        //定義鍵值全局變量
/***********************************************************/
void keyscan()                                        //按鍵掃描程序(放在1ms中斷中)
{
        static bit sign=0;                        //按鍵自鎖標(biāo)志
        static unsigned char count=0;//消抖計(jì)數(shù)變量                       
        unsigned char num=0;                //臨時(shí)變量
        P3=0xf0;                                        //賦值P3 1111 0000
        if(P3!=0xf0)                                //檢測(cè)有按鍵按下
        {
                count++;                                //消抖計(jì)數(shù)
                if((count>=value)&&(sign==0))
                {                       
                        sign=1;                                //按鍵自鎖標(biāo)志置1,防止長(zhǎng)按重復(fù)響應(yīng)
                        num=P3;                                //保存P3值xxxx 0000,x為0或1
                        num|=0x0f;                        //保存num按位或0x0f值xxxx 1111
                        P3=num;                                //賦值P3 xxxx 1111
                        num=P3;                                //保存P3值xxxx xxxx
                        switch(num)
                        {
                                case 0xee: KeySec= 1; break;
                                case 0xde: KeySec= 2; break;
                                case 0xbe: KeySec= 3; break;
                                case 0x7e: KeySec= 4; break;
                                case 0xed: KeySec= 5; break;
                                case 0xdd: KeySec= 6; break;
                                case 0xbd: KeySec= 7; break;
                                case 0x7d: KeySec= 8; break;
                                case 0xeb: KeySec= 9; break;
                                case 0xdb: KeySec=10; break;
                                case 0xbb: KeySec=11; break;
                                case 0x7b: KeySec=12; break;
                                case 0xe7: KeySec=13; break;
                                case 0xd7: KeySec=14; break;
                                case 0xb7: KeySec=15; break;
                                case 0x77: KeySec=16; break;
                        }
                }
        }
        else                                                //按鍵抬起
        {
                sign=0;                                        //按鍵自鎖標(biāo)志清0
                count=0;                                //消抖計(jì)數(shù)清0
        }
}
void key_service()                      //按鍵服務(wù)程序,放在主循環(huán)中
{
        switch(KeySec)
        {
                case 1:                                //事例1號(hào)鍵觸發(fā)
                //任務(wù)1
                KeySec=0;                          //鍵值清零,避免重復(fù)觸發(fā)
                break;                        //跳出當(dāng)前程序

                case 2:                                //事例2號(hào)鍵觸發(fā)
                        //任務(wù)2
                KeySec=0;                          //鍵值清零,避免重復(fù)觸發(fā)
                break;                        //跳出當(dāng)前程序
               
                //......
                //......

                case 16:                        //事例16號(hào)鍵觸發(fā)
                //任務(wù)16
                KeySec=0;                          //鍵值清零,避免重復(fù)觸發(fā)
                break;                         //跳出當(dāng)前程序
        }                  
}
作者: wulin    時(shí)間: 2018-5-3 10:16
我用的兩個(gè)74HC573接的8位數(shù)碼管,DUAN WEI兩個(gè)IO扣控制鎖存器的
這是用兩個(gè)74HC573接的8位共陰數(shù)碼管動(dòng)態(tài)顯示程序
void ledscan()//鍵盤顯示函數(shù)
{
        static unsigned char i=0;//靜態(tài)變量
        P0=0x00;                                //消隱
        DUAN=1;
        DUAN=0;
        P0=weima;                //位碼
        WEI=1;
        WEI=0;
        P0=ledbuff;                //段碼
        DUAN=1;
        DUAN=0;
        i++;
        if(i>=8)
                i=0;
}

作者: wen-zi    時(shí)間: 2018-5-3 12:00
彈起判斷應(yīng)該放在按鍵執(zhí)行后
作者: guanyi12340    時(shí)間: 2018-5-3 22:14
謝謝各位大佬了,今天翹班研究這個(gè)程序,發(fā)現(xiàn)132.void keydriver()函數(shù)里面backup[4][4]沒(méi)有定義靜態(tài),前面加個(gè)static一下就好了~唉~~~思維啊,思維啊~~板凳哥這個(gè)程序我仔細(xì)研究了下,確實(shí)比我的好多了~~拜謝
作者: xiaoyu.    時(shí)間: 2018-5-18 15:19
51單片機(jī)獨(dú)立按鍵
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit dula=P2^6;
sbit wela=P2^7;
sbit K1=P3^4;
sbit K2=P3^5;
sbit K3=P3^6;
sbit K4=P3^7;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
uint aa;
uchar num1,num2,shi1,ge1,shi2,ge2;

void delay(uint z)
{
        uint x,y;
        for(x=z;x>0;x--)
                for(y=110;y>0;y--);
}

void display(uchar num1,uchar num2)
{
        shi1=num1/10;
        ge1=num1%10;
        shi2=num2/10;
        ge2=num2%10;
       
        dula=1;
        P0=table[shi1];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xfe;
        wela=0;
        delay(1);

        dula=1;
        P0=table[ge1];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xfd;
        wela=0;
        delay(1);

        dula=1;
        P0=table[shi2];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xfb;
        wela=0;
        delay(1);

        dula=1;
        P0=table[ge2];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xf7;
        wela=0;
        delay(1);
}

void key()
{
        if(K1==0)
        {
                delay(5);
                if(K1==0)
                {
                        TR0=0;
                        while(!K1);
                }
        }

        if(K2==0)
        {
                delay(5);
                if(K2==0)
                {
                        if(num1==0)
                        {
                                num1=60;
                        }
                        num1--;
                        while(!K2);
                }
        }

        if(K3==0)
        {
                delay(5);
                if(K3==0)
                {
                        num1++;
                        if(num1>=60)
                        {
                                num1=num1-60;
                        }
                        while(!K3);
                }
        }

        if(K4==0)
        {
                delay(5);
                if(K4==0)
                {
                        TR0=1;
                        while(!K4);
                }
        }
}

void inint()
{
        TMOD=0x01;
        TH0=(65536-50000)/256;
        TL0=(65536-50000)%256;
        EA=1;
        ET0=1;
        TR0=1;
}

void main()
{
        inint();
        while(1)
        {
                key();
                display(num1,num2);
        }
}

void zhongduan()interrupt 1
{
        TH0=(65536-50000)/256;
        TL0=(65536-50000)%256;
        aa++;
        if(aa==20)
        {
                aa=0;
                num2++;
                if(num2==60)
                {
                        num2=0;
                        num1++;
                        if(num1==60)
                                num1=0;
                }
        }
}




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1