找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
12
返回列表 发新帖
楼主: bd5fna
打印 上一主题 下一主题
收起左侧

四位二进制如何取16个键值?附51单片机程序

  [复制链接]
41#
ID:69038 发表于 2024-5-7 09:40 | 只看该作者
如果DTMF解码正常,d0-d3有输出,那就要看看你的读数逻辑、数值处理是否有问题。
STD在解码成功后,会有一个上跳变的电平,并持续一段时间,然后再变为低电平。
“比如按下“1”键,显示的是一排16个“1”,不是单个。”这极有可能是你重复读数了。
你要做到:在STD从低到高再变为低之前的这段时间内,你去读并只能读一次。。。
回复

使用道具 举报

42#
ID:161164 发表于 2024-5-7 11:10 | 只看该作者
bd5fna 发表于 2024-5-6 21:02
目前的情况给各位大佬汇报一下:
void main()
{

代码要贴全部
你的k在哪更新?
回复

使用道具 举报

43#
ID:76027 发表于 2024-5-7 14:37 | 只看该作者
lkc8210 发表于 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};                      //初始密码

/***************************************************************************
函数: unsigned char MatrixKey()
描述: dtmf取值函数
参数: 将DTMF解码数据编码为数值
返回: 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)        //如果输入次数小于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);        //更新显示
                        }
                }
        
}
回复

使用道具 举报

44#
ID:76027 发表于 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};                      //初始密码

/***************************************************************************
函数: unsigned char MatrixKey()
描述: dtmf取值函数
参数: 将DTMF解码数据编码为数值
返回: 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)        //如果输入次数小于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);        //更新显示
                        }
               
        }
}


回复

使用道具 举报

45#
ID:69038 发表于 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;  //如果输入次数小于4,按序存入即可。
  
再看这个:
if(Password==initpassword[4])        //如果密码等于正确密码

这行代码你斟酌一下:Password是个4位10进制数,initpassword[4]是4成员数组的其中一个,能去比对匹配吗?
  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. }
复制代码



回复

使用道具 举报

46#
ID:161164 发表于 2024-5-8 09:58 | 只看该作者
bd5fna 发表于 2024-5-7 22:04
这是完整的代码,请各位大佬帮忙看看,哪里出错了。
#include //#include
//#include

还是不完整啊
你的k在MatrixKey()里更新
MatrixKey()在哪运行?
回复

使用道具 举报

47#
ID:76027 发表于 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 */
}
回复

使用道具 举报

48#
ID:69038 发表于 2024-5-8 16:26 | 只看该作者
“要别的网站下了一个,也不行,按键没反映。”,硬件电路一样吗?你是一字不改直接拿来用吗?
看代码D0-D3就与你的不一样了。STD信号线他接的是int0脚、下降沿触发,你的板也是这样接的吗?
回复

使用道具 举报

49#
ID:76027 发表于 2024-5-8 21:15 | 只看该作者
zhuls 发表于 2024-5-8 16:26
你是一字不改直接拿来用吗?
看代码D0-D ...

硬件改过了,写代码不行,这些简单的电路,还是可以搞定的。
回复

使用道具 举报

50#
ID:69038 发表于 2024-5-8 23:46 | 只看该作者
bd5fna 发表于 2024-5-8 21:15
硬件改过了,写代码不行,这些简单的电路,还是可以搞定的。

如上所述,你的K值在哪里更新了?
你一直贴代码,一直没看到K值有更新的代码。
你把电路也贴上来吧,或许有更多的的人来帮你。
回复

使用道具 举报

51#
ID:76027 发表于 2024-5-9 08:02 | 只看该作者
zhuls 发表于 2024-5-8 23:46
如上所述,你的K值在哪里更新了?
你一直贴代码,一直没看到K值有更新的代码。
你把电路也贴上来吧,或 ...


回复

使用道具 举报

52#
ID:76027 发表于 2024-5-9 08:23 | 只看该作者
这图上接的是P2口,我已接到P1口上了。
回复

使用道具 举报

53#
ID:69038 发表于 2024-5-9 09:26 | 只看该作者
void External_Interrupt_Init()                                
{
        EA  = 1;                       /* Enable global interrupt */
        EX0 = 1;                      /* Enable Ext. interrupt0 */                        
        IT0 = 1;                      //下跳变触发,与STD的上升沿或高电平不相符,如果你STD直接到EXINT0,用这段代码貌似是有问题的。
}
回复

使用道具 举报

54#
ID:76027 发表于 2024-5-9 10:05 | 只看该作者
zhuls 发表于 2024-5-9 09:26
void External_Interrupt_Init()                                
{
        EA  = 1;                  ...

这个应该没有问题,在STD高电平消失的一瞬间读数据,因为D0-D3的数据是在锁存状态,TOE接的是高电平,按键放开后,会锁存数据。我也试过低电平读取(STQ就是低电平),二者是一样的。附上DTMF解码板的原理图。
回复

使用道具 举报

55#
ID:161164 发表于 2024-5-9 11:10 | 只看该作者
bd5fna 发表于 2024-5-9 08:23
这图上接的是P2口,我已接到P1口上了。

LCD的端口改了吗?
回复

使用道具 举报

56#
ID:69038 发表于 2024-5-9 11:10 | 只看该作者
bd5fna 发表于 2024-5-9 10:05
这个应该没有问题,在STD高电平消失的一瞬间读数据,因为D0-D3的数据是在锁存状态,TOE接的是高电平,按 ...

是的Q1做了倒相。。
回复

使用道具 举报

57#
ID:76027 发表于 2024-5-9 11:50 | 只看该作者
lkc8210 发表于 2024-5-9 11:10
LCD的端口改了吗?

LCD能正常显示"DTMF Key"
回复

使用道具 举报

58#
ID:76027 发表于 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);
/****************************函数********************************/
void LCD_Init()
{
MSdelay(30);
LCD_Command(0x38);/*使用2行,初始化LCD的5*7矩阵*/ 现已确定这个有问题,多加一行再加延时就行
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; /*将数据作为 LCD 的命令发送到 PORT*/
RS = 0; /*选择命令寄存器*/
//RW = 0;
EN = 1;/*使能引脚到锁存数据上的高低脉冲*/
_nop_();
EN = 0;
MS延迟(3);
}

void LCD_Char(char dat)
{
Send_byte_over(dat);
//ldata= dat; /*将数据发送到LCD*/
RS = 1; /*选择数据寄存器*/
//RW = 0;
EN=1;/*使能引脚到锁存数据上的高低脉冲*/
_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); //每个循环 10T
}while(--ms);
}



/*************从3个IO口控制8位数据进入595,595在输出8位到LCD******************************/
void Send_595(unsigned char dat) //发送一个字节
{
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;
}
}
/*************发送8位完整数据到LCD******************************/
void Send_byte_over(unsigned char sda)
{
Send_595(sda);
P_HC595_RCLK = 1;
P_HC595_RCLK = 0;
}


回复

使用道具 举报

59#
ID:69038 发表于 2024-5-10 10:58 | 只看该作者
bd5fna 发表于 2024-5-9 18:37
各位大佬帮忙看看是不是1602驱动的问题,造成下一行无法显示而觉得代码有问题。
#include “LCD_16x2_8-bi ...

关于595时序,595本质是D触发器,“在Clk的上升沿,把Dat的状态传到Q”。
看你的代码却更像是“在CLK的下降沿,把Dat的状态传到Q”
所以你在调用LCD_Command()、Send_byte_over(unsigned char sda)之前先把SRCLK、RCLK置为“0”会更稳妥。。。
但你之前又说能正常显示字符,应该问题也不大。
回复

使用道具 举报

60#
ID:76027 发表于 2024-5-10 19:08 | 只看该作者
感谢各位大佬的帮助,现在基本解决问题了。还有一个小问题就是按键“0”按下没有反映,不知代码哪儿还有问题。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表