標題: 四位二進制如何取16個鍵值?附51單片機程序 [打印本頁]

作者: bd5fna    時間: 2024-5-2 10:01
標題: 四位二進制如何取16個鍵值?附51單片機程序
請教各位大佬,四位二進制如何取16個鍵值。用的是STC8H1K08的MCU,P1口設置為準雙向口。

單片機源程序如下:
sbit d0 = P1^2;
sbit d1 = P1^3;
sbit d2 = P1^4;
sbit d3 = P1^5;
unsigned char MatrixKey()

{        unsigned char k=0;

  if(d0==1 && d1==0 &&d2==0 && d3==0) k=1;

         else if(d0==0 && d1==1 && d2==0 && d3==0) k=2;

        else if(d0==1 && d1==1 && d2==0 && d3==0) k=3;

        else if(d0==0 && d1==0 && d2==0 && d3==1) k=4;

        else if(d0==1 && d1==0 && d2==1 && d3==0) k=5;

        else if(d0==0 && d1==1 && d2==1 && d3==0) k=6;

        else if(d0==1 && d1==1 && d2==1 && d3==0) k=7;

        else if(d0==0 && d1==0 && d2==0 && d3==1) k=8;

        else if(d0==1 && d1==0 && d2==0 && d3==1) k=9;

        else if(d0==0 && d1==1 && d2==0 && d3==1) k=0;

        else if(d0==1 && d1==1 && d2==0 && d3==1) k='*';

        else if(d0==0 && d1==0 && d2==1 && d3==1) k='#';

        else if(d0==1 && d1==0 && d2==1 && d3==1) k='A';

        else if(d0==0 && d1==1 && d2==1 && d3==1) k='B';

        else if(d0==1 && d1==1 && d2==1 && d3==1) k='C';

        else if(d0==0 && d1==0 && d2==0 && d3==0) k='D';
return k;
}

新手,請各位大佬多多指教!

作者: 624353765    時間: 2024-5-2 11:01
k=P1&0x3C
作者: csmyldl    時間: 2024-5-2 11:43
前面加一個16至4位二進制的編碼電路,不過這樣電路復雜了,不如用8個端口組成行列按鍵,或者用18個電阻串聯(lián)分壓電路構成16級電壓,用ADC識別作為16個按鍵
作者: lkc8210    時間: 2024-5-2 13:13
  1. unsigned char MatrixKey()
  2. {
  3.         unsigned char k=0;
  4.         unsigned char Temp = (P1>>2) & 0x0F;
  5.         switch(Temp)
  6.         {
  7.                 case 10:k=0;break;
  8.                 case 11:k='*';break;
  9.                 case 12:k='#';break;
  10.                 case 13:k='A';break;
  11.                 case 14:k='B';break;
  12.                 case 15:k='C';break;
  13.                 case 0:k='D';break;
  14.                 default:k=Temp;break;
  15.         }
  16.         return k;
  17. }
復制代碼

作者: 188610329    時間: 2024-5-2 13:16

unsigned char MatrixKey()
{
        unsigned char k=0;
        switch((P2>>2)&0x0f)
        {
                case        0x01:        k=1;        break;
                case        0x02:        k=2;        break;
                case        0x03:        k=3;        break;
                case        0x08:        k=4;        break;        //我也不知道為什么你會有兩個相同的按鍵狀態(tài)
                case        0x05:        k=5;        break;
                case        0x06:        k=6;        break;
                case        0x07:        k=7;        break;
                case        0x08:        k=8;        break;
                case        0x09:        k=9;        break;
                case        0x0A:        k=0;        break;
                case        0x0B:        k='*';        break;
                case        0x0C:        k='#';        break;
                case        0x0D:        k='A';        break;
                case        0x0E:        k='B';        break;
                case        0x0F:        k='C';        break;
                case        0x00:        k='D';        break;
                default:        k=0xff;        break;
        }
        return k;
}

作者: bd5fna    時間: 2024-5-2 14:47
csmyldl 發(fā)表于 2024-5-2 11:43
前面加一個16至4位二進制的編碼電路,不過這樣電路復雜了,不如用8個端口組成行列按鍵,或者用18個電阻串聯(lián) ...

這是一個DTMF接收輸入的二進制碼。
作者: bd5fna    時間: 2024-5-2 14:49
188610329 發(fā)表于 2024-5-2 13:16
unsigned char MatrixKey()
{
        unsigned char k=0;

新手,沒注意,復制后沒改過來。
作者: Hephaestus    時間: 2024-5-2 15:01


但是你的數(shù)據(jù)跟DTMF矩陣完全對不上號。
作者: bd5fna    時間: 2024-5-2 15:17
Hephaestus 發(fā)表于 2024-5-2 15:01
但是你的數(shù)據(jù)跟DTMF矩陣完全對不上號。

我這是DTMF解碼芯片MT8870 D1-D3輸出的數(shù)據(jù)
作者: bd5fna    時間: 2024-5-2 15:21
這是DTMF的編解碼表
作者: xiaobendan001    時間: 2024-5-2 15:29
取鍵值的意義是?直接右移2位,不就得電這個4位的數(shù)據(jù)了嗎?然后該干啥干啥唄
作者: bd5fna    時間: 2024-5-2 15:35
unsigned char k=0;
        switch((P2>>2)&0x0f)     K=0,那0的鍵值是不是無法提取出來。
作者: xiaobendan001    時間: 2024-5-2 16:26
bd5fna 發(fā)表于 2024-5-2 15:35
unsigned char k=0;
        switch((P2>>2)&0x0f)     K=0,那0的鍵值是不是無法提取出來。

4位不就是最多16個啊,看樓上的真值表,0也是有用的,很明顯要有一個別的什么信號來確定是不是有按鍵按下去。
作者: qthomas1988    時間: 2024-5-2 16:37
是不是按鍵檢測識別有問題
作者: zhuls    時間: 2024-5-2 16:42
你這個是在同一個端口,要取數(shù)簡直沒有更方便了!你參考一下:
temp=P1; //讀P1口數(shù)據(jù)值
temp=temp>>2; //數(shù)據(jù)值移位,匹配硬件端口:P1^2345
temp=temp & 0x0f; //屏蔽高4位
temp=“0123456789ABCDEF”[temp];//查表
return (temp); //返回鍵名ASC碼

作者: bd5fna    時間: 2024-5-2 16:49
xiaobendan001 發(fā)表于 2024-5-2 16:26
4位不就是最多16個啊,看樓上的真值表,0也是有用的,很明顯要有一個別的什么信號來確定是不是有按鍵按下 ...

芯片上有一個STD信號在有按鍵按下時產生高電平。
作者: zhuls    時間: 2024-5-2 17:13
bd5fna 發(fā)表于 2024-5-2 16:49
芯片上有一個STD信號在有按鍵按下時產生高電平。

對啊,標準的DTMF鍵盤是16鍵的。
只有解碼成功,STD才有高電平輸出。
這個我以前用的很多,用在報警器上,一個發(fā),一個收:
HT-9200.pdf (284.66 KB, 下載次數(shù): 2) DTMF編碼器
HT9170.pdf (111.75 KB, 下載次數(shù): 1) DTMF解碼器



作者: xianfajushi    時間: 2024-5-2 17:53
按題主思路就是按16進制的組合按鍵,不用定義直接讀取組的值即可獲得,很簡單的,不用寫那么多代碼。8421即1=1按鍵2=2按鍵3=1+2按鍵0就是沒按鍵15就是所有按鍵。
作者: Hephaestus    時間: 2024-5-2 18:51
zhuls 發(fā)表于 2024-5-2 16:42
你這個是在同一個端口,要取數(shù)簡直沒懈獎懔耍∧悴慰家幌攏�
temp=P1; //讀P1口數(shù)據(jù)值
temp=temp>>2; / ...

return("1234567890.#ABCD"[(P1>>2)&0xf]);

就一句話的事情,寫那么多干什么。
作者: xiaobendan001    時間: 2024-5-2 19:06
Hephaestus 發(fā)表于 2024-5-2 18:51
return("1234567890.#ABCD"[(P1>>2)&0xf]);

就一句話的事情,寫那么多干什么。

精辟,總工就是總工
作者: zhuls    時間: 2024-5-2 20:57
Hephaestus 發(fā)表于 2024-5-2 18:51
return("1234567890.#ABCD"[(P1>>2)&0xf]);

就一句話的事情,寫那么多干什么。

你看的懂,不代表天下人都看的懂
作者: 188610329    時間: 2024-5-2 23:13
zhuls 發(fā)表于 2024-5-2 20:57
你看的懂,不代表天下人都看的懂

確實,就一句話都還能寫錯……,還不如人家寫復雜一點的…… 至少能保證對。
作者: lkc8210    時間: 2024-5-3 10:25
Hephaestus 發(fā)表于 2024-5-2 18:51
return("1234567890.#ABCD"[(P1>>2)&0xf]);

就一句話的事情,寫那么多干什么。

雖然精妙,可惜樓主的0到9不是ASCII
作者: bd5fna    時間: 2024-5-3 10:25
請各位大佬再幫忙看看,輸入密碼時任何鍵都不會顯示,只有按下確認鍵會顯示錯誤(任意鍵做確認鍵都會顯示錯誤),這可以確定按鍵解碼是成功的。#include <STC8.H>//#include <string.h>
//#include <EEPROM.h>
#include <LCD1602.h>
#define     MAIN_Fosc       24000000L   //定義主時鐘

sbit ALAM = P3^4;                //報警       
sbit KEY = P3^2;                //開鎖
//sbit dtmf_ok = P1^1; //雙音頻接收
sbit d0 = P1^2;
sbit d1 = P1^3;
sbit d2 = P1^4;
sbit d3 = P1^5;

unsigned char KeyNum,Count=0;
unsigned int Password=0;

unsigned char code initpassword[4]={5,6,7,8};                      //初始密碼

/***************************************************************************
函數(shù): unsigned char MatrixKey()
描述: dtmf取值函數(shù)
參數(shù): 將DTMF解碼數(shù)據(jù)編碼為數(shù)值
返回: K
版本: VER1.0
日期: 2024-4-23
備注:
***************************************************************************/

unsigned char MatrixKey()
{
          unsigned char k=0;
        switch((P1>>2)&0x0f)
        {
                case        0x01:        k=1;        break;
                case        0x02:        k=2;        break;
                case        0x03:        k=3;        break;
                case        0x04:        k=4;        break;        
                case        0x05:        k=5;        break;
                case        0x06:        k=6;        break;
                case        0x07:        k=7;        break;
                case        0x08:        k=8;        break;
                case        0x09:        k=9;        break;
                case        0x0A:        k=0;        break;
                case        0x0B:        k='*';        break;
                case        0x0C:        k='#';        break;
                case        0x0D:        k='A';        break;
                case        0x0E:        k='B';        break;
                case        0x0F:        k='C';        break;
                case        0x00:        k='D';        break;
                default:        k=0xff;        break;
        }
        return k;
       
}

void main()
{
        P1M0 &= ~0x3f;
        P1M1 &= ~0x3f;
        P3M0 &= ~0xfc;
        P3M1 &= ~0xfc;
  //P1=0xff;
        LCD_Init();
        LCD_ShowString(1,1,"Password:");
        while(1)
        {
                KeyNum=MatrixKey();
                if(KeyNum)
                {
                        if(KeyNum<=10)        //如果S1~S10按鍵按下,輸入密碼
                        {
                                if(Count<4)        //如果輸入次數(shù)小于4
                                {
                                        Password*=10;                                //密碼左移一位
                                        Password+=KeyNum%10;                //獲取一位密碼
                                        Count++;        //計次加一
                                }
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                        if(KeyNum=='#')        //如果#按鍵按下,確認   任意鍵都可以
                        {
                                if(Password==initpassword[4])        //如果密碼等于正確密碼
                                {
                                        LCD_ShowString(1,11,"PassOK ");        //顯示OK
                                         KEY=~KEY;                                                                                //打開繼電器
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                                else                                //否則
                                {
                                        LCD_ShowString(1,12,"error");        //顯示ERR
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                        }
                        if(KeyNum=='*')        //如果*按鍵按下,取消
                        {
                                Password=0;                //密碼清零
                                Count=0;                //計次清零
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                }
        }
}




作者: Hephaestus    時間: 2024-5-3 11:32
188610329 發(fā)表于 2024-5-2 23:13
確實,就一句話都還能寫錯……,還不如人家寫復雜一點的…… 至少能保證對。

是你寫錯了。
作者: lkc8210    時間: 2024-5-3 14:48
bd5fna 發(fā)表于 2024-5-3 10:25
請各位大佬再幫忙看看,輸入密碼時任何鍵都不會顯示,只有按下確認鍵會顯示錯誤(任意鍵做確認鍵都會顯示錯 ...

STD 信號呢?
作者: Hephaestus    時間: 2024-5-3 15:13
lkc8210 發(fā)表于 2024-5-3 10:25
雖然精妙,可惜樓主的0到9不是ASCII

我回復15樓,你的問題找15樓說去,別在我的帖子里面插嘴。
作者: bd5fna    時間: 2024-5-3 15:22
lkc8210 發(fā)表于 2024-5-3 14:48
STD 信號呢?

if(dtmf_ok==1)再檢測按鍵也一樣,不行。
作者: lkc8210    時間: 2024-5-3 15:53
Hephaestus 發(fā)表于 2024-5-3 15:13
我回復15樓,你的問題找15樓說去,別在我的帖子里面插嘴。

了解。。。。
作者: lkc8210    時間: 2024-5-3 15:53
bd5fna 發(fā)表于 2024-5-3 15:22
if(dtmf_ok==1)再檢測按鍵也一樣,不行。

咋加的?
作者: zhuls    時間: 2024-5-3 17:08
Hephaestus 發(fā)表于 2024-5-3 15:13
我回復15樓,你的問題找15樓說去,別在我的帖子里面插嘴。

我是15樓的。
你這是咋啦??
論壇本就是公開的,有事論事,有什么插不插嘴?看到有不同意見的都可以說的。不然要這論壇何用?
作者: bd5fna    時間: 2024-5-3 18:56
lkc8210 發(fā)表于 2024-5-3 15:53
咋加的?

while(1)
        {
                KeyNum=MatrixKey();
                if(dtmf_ok==1)
                {
                        if(KeyNum<=10)        //如果S1~S10按鍵按下,輸入密碼
                        {
                                if(Count<4)        //如果輸入次數(shù)小于4
                                {
                                        Password*=10;                                //密碼左移一位
                                        Password+=KeyNum%10;                //獲取一位密碼
                                        Count++;        //計次加一
                                }
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                        if(KeyNum=='#')        //如果#按鍵按下,確認
                        {
                                if(Password==initpassword[4])        //如果密碼等于正確密碼
                                {
                                        LCD_ShowString(1,11,"PassOK ");        //顯示OK
                                         KEY=~KEY;                                                                                //打開繼電器
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                                else                                //否則
                                {
                                        LCD_ShowString(1,12,"error");        //顯示ERR
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                        }
                        if(KeyNum=='*')        //如果*按鍵按下,取消
                        {
                                Password=0;                //密碼清零
                                Count=0;                //計次清零
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                }
        }
}


作者: 188610329    時間: 2024-5-3 22:31
Hephaestus 發(fā)表于 2024-5-3 11:32
是你寫錯了。

永遠自信滿滿的樣子,希望你能保持。自己看看你寫的什么東西,返回值是什么再說吧
作者: bd5fna    時間: 2024-5-4 09:59
向各位大佬匯報一下目前的情況:用下面的代碼,在不接入任何輸入的情況下,開機就顯示滿屏的“0”,按鍵按下,顯示一大串對應的鍵值而不是單個鍵值。注釋掉按鍵代碼,顯示一大串字符。請教一下各位大佬,這個如何解?
#include <STC8.H>
//#include <string.h>
//#include <EEPROM.h>
#include <LCD1602.h>
#define     MAIN_Fosc       24000000L   //定義主時鐘

sbit ALAM = P3^4;                //報警        
sbit KEY = P3^2;                //開鎖
sbit dtmf_ok = P1^1; //雙音頻接收
sbit d0 = P1^2;
sbit d1 = P1^3;
sbit d2 = P1^4;
sbit d3 = P1^5;

unsigned char KeyNum,Count=0;
unsigned int Password=0;

unsigned char code initpassword[4]={5,6,7,8};                      //初始密碼
unsigned char dat[]="0123456789*#ABCD";
/***************************************************************************
函數(shù): unsigned char MatrixKey()
描述: dtmf取值函數(shù)
參數(shù): 將DTMF解碼數(shù)據(jù)編碼為數(shù)值
返回: K
版本: VER1.0
日期: 2024-4-23
備注:
***************************************************************************/

unsigned char MatrixKey()
{
        unsigned char k=0;
  unsigned char Temp = (P1>>2) & 0x0F;
if(dtmf_ok==1)
{
   switch(Temp)
         
        {

                case        0x01:        k=1;        break;
                case        0x02:        k=2;        break;
                case        0x03:        k=3;        break;
                case        0x04:        k=4;        break;        
                case        0x05:        k=5;        break;
                case        0x06:        k=6;        break;
                case        0x07:        k=7;        break;
                case        0x08:        k=8;        break;
                case        0x09:        k=9;        break;
                case        0x0A:        k=0;        break;
                case        0x0B:        k='*';        break;
                case        0x0C:        k='#';        break;
                case        0x0D:        k='A';        break;
                case        0x0E:        k='B';        break;
                case        0x0F:        k='C';        break;
                                                                case        0x00:        k='D';        break;
               default:        k=0xff;        break;
        }
       }
                                return k;
                        
}

void main()
{
        P1M0 &= ~0x3f;
        P1M1 &= ~0x3f;
  P3M0 &= ~0xfc;
        P3M1 &= ~0xfc;
  //P1=0xff;
        LCD_Init();
        LCD_ShowString(1,1,"Password:");
        while(1)
        {
                KeyNum=MatrixKey();

                LCD_WriteData(dat[KeyNum]);
               
                /*if(KeyNum)
                {
                        if(KeyNum<=10)        //如果0-9按鍵按下,輸入密碼
                        {
                                if(Count<4)        //如果輸入次數(shù)小于4
                                {
                                        Password*=10;                                //密碼左移一位
                                        Password+=KeyNum%10;                //獲取一位密碼
                                        Count++;        //計次加一
                                }
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                        if(KeyNum=='#')        //如果#按鍵按下,確認
                        {
                                if(Password==initpassword[4])        //如果密碼等于正確密碼
                                {
                                        LCD_ShowString(1,11,"PassOK ");        //顯示OK
                                         KEY=~KEY;                                                                                //打開繼電器
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                                else                                //否則
                                {
                                        LCD_ShowString(1,12,"error");        //顯示ERR
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                        }
                        if(KeyNum=='*')        //如果*按鍵按下,取消
                        {
                                Password=0;                //密碼清零
                                Count=0;                //計次清零
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                }*/
        }
}



作者: bd5fna    時間: 2024-5-5 12:35
已經改用下降沿觸發(fā)檢測按鍵,但還是開機滿屏的‘0’。
作者: zhuls    時間: 2024-5-6 16:26
沒有原理圖,我就腦補且認為你這個是DTMF解碼、從8870的D0-D3口接P1^2-P1^5,獲取數(shù)據(jù)的吧。如果不是,那我這個回復貼就是廢話,無視之!unsigned char MatrixKey()
{
  unsigned char k=0;
  unsigned char Temp = (P1>>2) & 0x0F; //你在這邊已賦值給temp了!不管有沒有STD來,都是一個值。!  //改成unsigned char Temp;
if(dtmf_ok==1) //因為前邊的問題,這個判斷已無意義
{
   //如果8870/9170DTMF解碼,OE腳要置高,D0-D3腳才有電平出來,你可以在硬件上把OE與STD直連,并下拉一個幾十K。
   //此處插入 讀值D0-D3:(P1>>2) & 0x0F
   switch(Temp)
        {
                case        0x01:        k=1;        break;   //此分支返回,就是0x01, 直接ASC改成'1'
                case        0x02:        k=2;        break;  //0x02,
                case        0x03:        k=3;        break;//.
                case        0x04:        k=4;        break;    //    .
                case        0x05:        k=5;        break;//.
                case        0x06:        k=6;        break;//.
                case        0x07:        k=7;        break;//.
                case        0x08:        k=8;        break;//.
                case        0x09:        k=9;        break;//.
                case        0x0A:        k=0;        break;//此分支返回,就是0x00
                case        0x0B:        k='*';        break;//此分支返回,0x2A, 而你接下要用到的dat[]成員數(shù)才16個!
                case        0x0C:        k='#';        break;//此分支返回,0x23!!!
                case        0x0D:        k='A';        break;//此分支返回,0x41!!!
                case        0x0E:        k='B';        break;//此分支返回,0x42!!!
                case        0x0F:        k='C';        break;//此分支返回,0x43!!!
                case        0x00:        k='D';        break;//此分支返回,0x44!!!
               default:        k=0xff;        break;           
        }
       }
  return k;
}


你這段代碼switch(Temp)是分支篩選,與接下來的LCD_WriteData(dat[KeyNum]);這行也是分支篩選,功能重復了,為什么要2次?
直接把 case        0x01:        k=1;        break;  改成 case        0x01:        k=‘1’;        break;  一直改到‘0’這行。直接調用顯示就OK了:
LCD_WriteData(k);
總之:數(shù)值套娃,還是套到錯的數(shù)值。






作者: 55556hm    時間: 2024-5-6 16:38

unsigned char MatrixKey()
{
        unsigned char k=0;
        switch((P2>>2)&0x0f)
        {
                case        0x01:        k=1;        break;
                case        0x02:        k=2;        break;
                case        0x03:        k=3;        break;
                case        0x08:        k=4;        break;        //我也不知道為什么你會有兩個相同的按鍵狀態(tài)
                case        0x05:        k=5;        break;
                case        0x06:        k=6;        break;
                case        0x07:        k=7;        break;
                case        0x08:        k=8;        break;
                case        0x09:        k=9;        break;
                case        0x0A:        k=0;        break;
                case        0x0B:        k='*';        break;
                case        0x0C:        k='#';        break;
                case        0x0D:        k='A';        break;
                case        0x0E:        k='B';        break;
                case        0x0F:        k='C';        break;
                case        0x00:        k='D';        break;
                default:        k=0xff;        break;
        }
        return k;
}
作者: zhuls    時間: 2024-5-6 16:44
bd5fna 發(fā)表于 2024-5-5 12:35
已經改用下降沿觸發(fā)檢測按鍵,但還是開機滿屏的‘0’。

你要確認,DTMF解碼是否正常!d0-d3是否有輸出!
把STD接個電阻串個LED,再把OE接到STD,看看每按一次鍵,led是否會閃亮一下。
作者: bd5fna    時間: 2024-5-6 19:52
zhuls 發(fā)表于 2024-5-6 16:44
你要確認,DTMF解碼是否正常!d0-d3是否有輸出!
把STD接個電阻串個LED,再把OE接到STD,看看每按一次鍵 ...

DTMF解碼正常!d0-d3有輸出!每按一次鍵,led會閃,STD輸出高電平。用的是這種模塊
作者: bd5fna    時間: 2024-5-6 21:02
本帖最后由 bd5fna 于 2024-5-7 09:37 編輯

目前的情況給各位大佬匯報一下:
void main()
{
        P1M0 &= ~0x3f;
        P1M1 &= ~0x3f;
  P3M0 &= ~0xfc;
        P3M1 &= ~0xfc;
  //P1=0xff;
        Timer0_Init();
        LCD_Init();
        UART_InitConfig();
        LCD_ShowString(1,1,"Password:");
        TI = 1;                                                                                                         //使用printf()函數(shù)時,TI必須為1
        while(1)
        {
                printf("%d ",k);
                LCD_WriteData(k);   這里可顯示解碼出來的鍵值,有一個現(xiàn)象,比如按下“1”鍵,顯示的是一排16個“1”,不是單個。
               
                        if(k<=9)        //如果0-9按鍵按下,輸入密碼
                        {
                                if(Count<4)        //如果輸入次數(shù)小于4
                                {
                                        Password*=10;                                //密碼左移一位
                                        Password+=k%10;                //獲取一位密碼
                                        Count++;        //計次加一
                                }
                                LCD_ShowNum(2,1,Password,4);        //更新顯示    注釋掉   LCD_WriteData(k); 這里顯示不了輸入的鍵值。
                        
                                printf("%d ",Password);
                        }
                        if(k=='#')        //如果#按鍵按下,確認         按下“#”鍵后,顯示“error”
                        {
                                if(Password==initpassword[4])        //如果密碼等于正確密碼
                                {
                                        LCD_ShowString(1,11,"PassOK ");        //顯示OK
                                         jdq=~jdq;                                                                                //打開繼電器
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                                else                                //否則
                                {
                                        LCD_ShowString(1,12,"error");        //顯示ERR
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                        }
                        if(k=='*')        //如果*按鍵按下,取消   按“*”返回沒有效果
                        {
                                Password=0;                //密碼清零
                                Count=0;                //計次清零
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
        }
}


作者: zhuls    時間: 2024-5-7 09:40
如果DTMF解碼正常,d0-d3有輸出,那就要看看你的讀數(shù)邏輯、數(shù)值處理是否有問題。
STD在解碼成功后,會有一個上跳變的電平,并持續(xù)一段時間,然后再變?yōu)榈碗娖健?br /> “比如按下“1”鍵,顯示的是一排16個“1”,不是單個!边@極有可能是你重復讀數(shù)了。
你要做到:在STD從低到高再變?yōu)榈椭暗倪@段時間內,你去讀并只能讀一次。。。

作者: lkc8210    時間: 2024-5-7 11:10
bd5fna 發(fā)表于 2024-5-6 21:02
目前的情況給各位大佬匯報一下:
void main()
{

代碼要貼全部
你的k在哪更新?
作者: bd5fna    時間: 2024-5-7 14:37
lkc8210 發(fā)表于 2024-5-7 11:10
代碼要貼全部
你的k在哪更新?

#include <STC8.H>//#include <string.h>
//#include <EEPROM.h>
#include <LCD1602.h>
#define     MAIN_Fosc       24000000L   //定義主時鐘

sbit ALAM = P3^4;                //報警      
sbit KEY = P3^2;                //開鎖
//sbit dtmf_ok = P1^1; //雙音頻接收
sbit d0 = P1^2;
sbit d1 = P1^3;
sbit d2 = P1^4;
sbit d3 = P1^5;

unsigned char k,KeyNum,Count=0;
unsigned int Password=0;

unsigned char code initpassword[4]={5,6,7,8};                      //初始密碼

/***************************************************************************
函數(shù): unsigned char MatrixKey()
描述: dtmf取值函數(shù)
參數(shù): 將DTMF解碼數(shù)據(jù)編碼為數(shù)值
返回: K
版本: VER1.0
日期: 2024-4-23
備注:
***************************************************************************/

unsigned char MatrixKey()
{
      
        switch((P1>>2)&0x0f)
        {
                case        0x01:        k='1';        break;
                case        0x02:        k='2';        break;
                case        0x03:        k='3';        break;
                case        0x04:        k='4';        break;        
                case        0x05:        k='5';        break;
                case        0x06:        k='6';        break;
                case        0x07:        k='7';        break;
                case        0x08:        k='8';        break;
                case        0x09:        k='9';        break;
                case        0x0A:        k='0';        break;
                case        0x0B:        k='*';        break;
                case        0x0C:        k='#';        break;
                case        0x0D:        k='A';        break;
                case        0x0E:        k='B';        break;
                case        0x0F:        k='C';        break;
                case        0x00:        k='D';        break;
                default:        k=0xff;        break;
        }
        return k;
      
}

void main()
{
        P1M0 &= ~0x3f;
        P1M1 &= ~0x3f;
        P3M0 &= ~0xfc;
        P3M1 &= ~0xfc;
  //P1=0xff;
        LCD_Init();
        LCD_ShowString(1,1,"Password:");
        while(1)
        {
            
                        if(K<=9)        //如果S1~S10按鍵按下,輸入密碼
                        {
                                if(Count<4)        //如果輸入次數(shù)小于4
                                {
                                        Password*=10;                                //密碼左移一位
                                        Password+=K%10;                //獲取一位密碼
                                        Count++;        //計次加一
                                }
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                        if(K=='#')        //如果#按鍵按下,確認   
                        {
                                if(Password==initpassword[4])        //如果密碼等于正確密碼
                                {
                                        LCD_ShowString(1,11,"PassOK ");        //顯示OK
                                         KEY=~KEY;                                                                                //打開繼電器
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                                else                                //否則
                                {
                                        LCD_ShowString(1,12,"error");        //顯示ERR
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                        }
                        if(k=='*')        //如果*按鍵按下,取消
                        {
                                Password=0;                //密碼清零
                                Count=0;                //計次清零
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                }
        
}

作者: bd5fna    時間: 2024-5-7 22:04
這是完整的代碼,請各位大佬幫忙看看,哪里出錯了。
#include <STC8.H>//#include <string.h>
//#include <EEPROM.h>
#include <LCD1602.h>
#define     MAIN_Fosc       24000000L   //定義主時鐘

sbit ALAM = P3^4;                //報警      
sbit KEY = P3^2;                //開鎖
sbit d0 = P1^2;
sbit d1 = P1^3;
sbit d2 = P1^4;
sbit d3 = P1^5;

unsigned char k=0,Count=0;
unsigned int Password=0;

unsigned char code initpassword[4]={5,6,7,8};                      //初始密碼

/***************************************************************************
函數(shù): unsigned char MatrixKey()
描述: dtmf取值函數(shù)
參數(shù): 將DTMF解碼數(shù)據(jù)編碼為數(shù)值
返回: K
版本: VER1.0
日期: 2024-4-23
備注:
***************************************************************************/

unsigned char MatrixKey()
{
        switch((P1>>2)&0x0f)
        {
                case        0x01:        k='1';        break;
                case        0x02:        k='2';        break;
                case        0x03:        k='3';        break;
                case        0x04:        k='4';        break;        
                case        0x05:        k='5';        break;
                case        0x06:        k='6';        break;
                case        0x07:        k='7';        break;
                case        0x08:        k='8';        break;
                case        0x09:        k='9';        break;
                case        0x0A:        k='0';        break;
                case        0x0B:        k='*';        break;
                case        0x0C:        k='#';        break;
                case        0x0D:        k='A';        break;
                case        0x0E:        k='B';        break;
                case        0x0F:        k='C';        break;
                case        0x00:        k='D';        break;
                default:        k=0xff;        break;
        }
        return k;
      
}

void main()
{
        P1M0 &= ~0x3f;
        P1M1 &= ~0x3f;
        P3M0 &= ~0xfc;
        P3M1 &= ~0xfc;
  //P1=0xff;
        LCD_Init();
        LCD_ShowString(1,1,"Password:");
        while(1)
        {
              
                        if(k<=10)        //如果S1~S10按鍵按下,輸入密碼
                        {
                                if(Count<4)        //如果輸入次數(shù)小于4
                                {
                                        Password*=10;                                //密碼左移一位
                                        Password+=k%10;                //獲取一位密碼
                                        Count++;        //計次加一
                                }
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
                        if(k=='#')        //如果#按鍵按下,確認   
                        {
                                if(Password==initpassword[4])        //如果密碼等于正確密碼
                                {
                                        LCD_ShowString(1,11,"PassOK ");        //顯示OK
                                         KEY=~KEY;                                                                                //打開繼電器
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                                else                                //否則
                                {
                                        LCD_ShowString(1,12,"error");        //顯示ERR
                                        Password=0;                //密碼清零
                                        Count=0;                //計次清零
                                        LCD_ShowNum(2,1,Password,4);        //更新顯示
                                }
                        }
                        if(k=='*')        //如果*按鍵按下,取消
                        {
                                Password=0;                //密碼清零
                                Count=0;                //計次清零
                                LCD_ShowNum(2,1,Password,4);        //更新顯示
                        }
               
        }
}



作者: zhuls    時間: 2024-5-8 06:35
本帖最后由 zhuls 于 2024-5-8 09:44 編輯

沒看錯的話,你的K值沒更新。〖 MatrixKey()沒有被調用到。
是不是要有一段比如這樣的代碼:

if (STD==1 && getval==0)//STD是8870 的腳 ,getval是取值標志,確保在STD=1時,只取一次值。
{
   k=MatrixKey();
   getval=1;
}
if (STD==0 )   getval=0;

還有這個:
  if(k<=10)        //因為你的K已轉成ASC碼,所以永遠不會<=10 了,改成if((k>=0x30)&&(k<=0x39))
   
密碼做為字符,不建議以10進制方式存取,直接字符串即可。
先定義unsigned int Password[4];
然后:

if(Count<4)    Password[ =k;  //如果輸入次數(shù)小于4,按序存入即可。
  
再看這個:
if(Password==initpassword[4])        //如果密碼等于正確密碼

這行代碼你斟酌一下:Password是個4位10進制數(shù),initpassword[4]是4成員數(shù)組的其中一個,能去比對匹配嗎?
  1. char cmp_password()
  2. {
  3.    for(i=0;i<4;i++)
  4.   {
  5.     if(Password[i]!=initpassword[i])
  6.      {
  7.       return(0);//匹配失敗
  8.     }
  9.   }
  10. return (0xff);//匹配成功
  11. }
復制代碼




作者: lkc8210    時間: 2024-5-8 09:58
bd5fna 發(fā)表于 2024-5-7 22:04
這是完整的代碼,請各位大佬幫忙看看,哪里出錯了。
#include //#include
//#include

還是不完整啊
你的k在MatrixKey()里更新
MatrixKey()在哪運行?
作者: bd5fna    時間: 2024-5-8 11:18
要別的下了一個,也不行,按鍵沒反映。
#include<stdio.h>
#include<STC8h.h>
#include<LCD_16x2_8-bit_Header_File.h>

#define DTMF_Input_Read P1

void External_Interrupt_Init();

volatile char Key_detect;           /* flag to check Tone is received or not */
void main()
{   
    unsigned char DTMF_Key;         /* variable to store detected key */         
  
                P1M0 &= ~0x3f;
                P1M1 &= ~0x3f;
                P3M0 &= ~0xfc;
                P3M1 &= ~0xfc;

    LCD_Init();
                LCD_Clear();
                DTMF_Input_Read = 0xff;         /* set port as input */
    LCD_String_xy(0,0,"DTMF Key:");
                External_Interrupt_Init();
          Key_detect = 0;
    while(1)
    {   
                                MSdelay(1);
        if(Key_detect)              /* Key_detect = 1 indicates Tone Received*/
        {   
          Key_detect = 0;
                                        LCD_Command(0xc0);
                                        DTMF_Key = 0;
          DTMF_Key = (DTMF_Input_Read & 0x0f);
                                       
        
                                        switch(DTMF_Key)          /* detect received key*/
                                        {
                                                        case 0x01: LCD_Char('1');
                                                                                                 break;
                                                        case 0x02: LCD_Char('2');
                                                                                                 break;
                                                        case 0x03: LCD_Char('3');
                                                                                                 break;
                                                        case 0x04: LCD_Char('4');
                                                                                                 break;
                                                        case 0x05: LCD_Char('5');
                                                                                                 break;
                                                        case 0x06: LCD_Char('6');
                                                                                                 break;
                                                        case 0x07: LCD_Char('7');
                                                                                                 break;
                                                        case 0x08: LCD_Char('8');
                                                                                                 break;
                                                        case 0x09: LCD_Char('9');
                                                                                                 break;
                                                        case 0x0A: LCD_Char('0');
                                                                                                 break;
                                                        case 0x0B: LCD_Char('*');
                                                                                                 break;
                                                        case 0x0C: LCD_Char('#');
                                                                                                 break;
                                        }
        }
    }   
}


void External_Interrupt_Init()                                
{
        EA  = 1;                                        /* Enable global interrupt */
        EX0 = 1;                      /* Enable Ext. interrupt0 */                        
        IT0 = 1;                      /* Select Ext. interrupt0 on falling edge */         
}
/* ISR is used to check tone is received or not */
                                                                                       
void External0_ISR() interrupt 0   
{
        Key_detect = 1;                        /* Toggle pin on falling edge on INT0 pin */
}
作者: zhuls    時間: 2024-5-8 16:26
“要別的網站下了一個,也不行,按鍵沒反映。”,硬件電路一樣嗎?你是一字不改直接拿來用嗎?
看代碼D0-D3就與你的不一樣了。STD信號線他接的是int0腳、下降沿觸發(fā),你的板也是這樣接的嗎?
作者: bd5fna    時間: 2024-5-8 21:15
zhuls 發(fā)表于 2024-5-8 16:26
你是一字不改直接拿來用嗎?
看代碼D0-D ...

硬件改過了,寫代碼不行,這些簡單的電路,還是可以搞定的。
作者: zhuls    時間: 2024-5-8 23:46
bd5fna 發(fā)表于 2024-5-8 21:15
硬件改過了,寫代碼不行,這些簡單的電路,還是可以搞定的。

如上所述,你的K值在哪里更新了?
你一直貼代碼,一直沒看到K值有更新的代碼。
你把電路也貼上來吧,或許有更多的的人來幫你。
作者: bd5fna    時間: 2024-5-9 08:02
zhuls 發(fā)表于 2024-5-8 23:46
如上所述,你的K值在哪里更新了?
你一直貼代碼,一直沒看到K值有更新的代碼。
你把電路也貼上來吧,或 ...



作者: bd5fna    時間: 2024-5-9 08:23
這圖上接的是P2口,我已接到P1口上了。
作者: zhuls    時間: 2024-5-9 09:26
void External_Interrupt_Init()                                
{
        EA  = 1;                       /* Enable global interrupt */
        EX0 = 1;                      /* Enable Ext. interrupt0 */                        
        IT0 = 1;                      //下跳變觸發(fā),與STD的上升沿或高電平不相符,如果你STD直接到EXINT0,用這段代碼貌似是有問題的。
}
作者: bd5fna    時間: 2024-5-9 10:05
zhuls 發(fā)表于 2024-5-9 09:26
void External_Interrupt_Init()                                
{
        EA  = 1;                  ...

這個應該沒有問題,在STD高電平消失的一瞬間讀數(shù)據(jù),因為D0-D3的數(shù)據(jù)是在鎖存狀態(tài),TOE接的是高電平,按鍵放開后,會鎖存數(shù)據(jù)。我也試過低電平讀。⊿TQ就是低電平),二者是一樣的。附上DTMF解碼板的原理圖。
作者: lkc8210    時間: 2024-5-9 11:10
bd5fna 發(fā)表于 2024-5-9 08:23
這圖上接的是P2口,我已接到P1口上了。

LCD的端口改了嗎?
作者: zhuls    時間: 2024-5-9 11:10
bd5fna 發(fā)表于 2024-5-9 10:05
這個應該沒有問題,在STD高電平消失的一瞬間讀數(shù)據(jù),因為D0-D3的數(shù)據(jù)是在鎖存狀態(tài),TOE接的是高電平,按 ...

是的Q1做了倒相。。
作者: bd5fna    時間: 2024-5-9 11:50
lkc8210 發(fā)表于 2024-5-9 11:10
LCD的端口改了嗎?

LCD能正常顯示"DTMF Key"
作者: bd5fna    時間: 2024-5-9 18:37
各位大佬幫忙看看是不是1602驅動的問題,造成下一行無法顯示而覺得代碼有問題。
#include “LCD_16x2_8-bit_Header_File.h”
#define MAIN_Fosc 24000000L //定義主時鐘
void Send_595(unsigned char dat);
void Send_byte_over(無符號字符 SDA);
/****************************函數(shù)********************************/
void LCD_Init()
{
MSdelay(30);
LCD_Command(0x38);/*使用2行,初始化LCD的5*7矩陣*/ 現(xiàn)已確定這個有問題,多加一行再加延時就行
LCD_Command(0x0c);/*光標關閉時顯示*/
LCD_Command(0x06);/*遞增光標(將光標向右移動)*/
LCD_Command(0x01);/*清除顯示屏*/
MSdelay(3);
}

void LCD_Clear()
{
LCD_Command(0x01); /*清除顯示屏*/
MSdelay(3);
}

void LCD_Command(char cmd )
{
Send_byte_over(cmd);
//ldata= cmd; /*將數(shù)據(jù)作為 LCD 的命令發(fā)送到 PORT*/
RS = 0; /*選擇命令寄存器*/
//RW = 0;
EN = 1;/*使能引腳到鎖存數(shù)據(jù)上的高低脈沖*/
_nop_();
EN = 0;
MS延遲(3);
}

void LCD_Char(char dat)
{
Send_byte_over(dat);
//ldata= dat; /*將數(shù)據(jù)發(fā)送到LCD*/
RS = 1; /*選擇數(shù)據(jù)寄存器*/
//RW = 0;
EN=1;/*使能引腳到鎖存數(shù)據(jù)上的高低脈沖*/
_nop_();
EN=0;
MS延遲(3);
}


void LCD_String(const char *msg)
{
while((*msg)!=0)
{
LCD_Char(*msg);
msg++;

}
}

void LCD_String_xy(char row,char pos,const char *msg)
{
char location=0;
if(row<1)
{
location=(0x80) |((pos) & 0x0f);/*在第一行和所需位置打印消息*/
LCD_Command(位置);
}
else
{
location=(0xC0) |((pos) & 0x0f);/*在第二行和所需位置打印消息*/
LCD_Command(位置);

} LCD_String(味精);
}


void MSdelay(unsigned int ms)
{
unsigned int i;
do{
i = MAIN_Fosc / 10000;
while(--i); //每個循環(huán) 10T
}while(--ms);
}



/*************從3個IO口控制8位數(shù)據(jù)進入595,595在輸出8位到LCD******************************/
void Send_595(unsigned char dat) //發(fā)送一個字節(jié)
{
unsigned char i;
for(i=0; i<8; i++)
{
if(dat & 0x80) P_HC595_SER = 1;
else P_HC595_SER = 0;
P_HC595_SRCLK = 1;
P_HC595_SRCLK = 0;
dat = dat << 1;
}
}
/*************發(fā)送8位完整數(shù)據(jù)到LCD******************************/
void Send_byte_over(unsigned char sda)
{
Send_595(sda);
P_HC595_RCLK = 1;
P_HC595_RCLK = 0;
}



作者: zhuls    時間: 2024-5-10 10:58
bd5fna 發(fā)表于 2024-5-9 18:37
各位大佬幫忙看看是不是1602驅動的問題,造成下一行無法顯示而覺得代碼有問題。
#include “LCD_16x2_8-bi ...

關于595時序,595本質是D觸發(fā)器,“在Clk的上升沿,把Dat的狀態(tài)傳到Q”。
看你的代碼卻更像是“在CLK的下降沿,把Dat的狀態(tài)傳到Q”
所以你在調用LCD_Command()、Send_byte_over(unsigned char sda)之前先把SRCLK、RCLK置為“0”會更穩(wěn)妥。。。
但你之前又說能正常顯示字符,應該問題也不大。
作者: bd5fna    時間: 2024-5-10 19:08
感謝各位大佬的幫助,現(xiàn)在基本解決問題了。還有一個小問題就是按鍵“0”按下沒有反映,不知代碼哪兒還有問題。




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