找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 977|回复: 4
打印 上一主题 下一主题
收起左侧

单片机DTMF密码锁程序问题请教大佬

[复制链接]
跳转到指定楼层
楼主
ID:76027 发表于 2024-8-31 07:55 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
前段时间根据论坛大佬们的帖子,改了一个无线的DTMF密码锁。在输入密码时要关闭语音转发,没有按键输入时打开语音转发。现在情况是输入密码大于4位正常,但小于4位,语音转发一直关闭。下面是代码,麻烦大佬们帮忙看看,如何改。

单片机源程序如下:
void main(void)
{
        unsigned char keynum,NUM;
        unsigned char i,j;
        
        P1M0 &= 0x00;
        P1M1 &= 0x00;

        P3M0 &= ~0x0c;                        //P3^2-3准双向
        P3M1 &= ~0x0c;
  P3M0 |= 0xf0;      //P3^4-7推挽输入
        P3M1 &= ~0xf0;
        P3=0x0f;                                        //初始化信道转换P3^4 5 6 7为低电平

        Delay_ms(400);                                                                                                                 //启动等待,等LCM讲入工作状态
         LCD_Init();                                                                                                                         //LCD初始化
        UART_InitConfig();
        Timer0_Init();
        LCD_WriteCommand(yi);                                                                                        //日历显示固定符号从第一行第0个位置之后开始显示
        for(i=0;i<16;i++)
        {
                LCD_WriteData(name[ i]);                                                           //向液晶屏写开机画面
        }
        LCD_WriteCommand(er);
        for(i=0;i<16;i++)
        {
                LCD_WriteData(start_line[ i]);                            //写输入密码等待界面
        }
        LCD_WriteCommand(er+9);                                                            //设置光标位置
        LCD_WriteCommand(0x0f);                                                     //设置光标为闪烁
        Delay_ms(5);                                                                                                   //延时片刻(可不要)
        N=0;                                                                                                                                    //初始化数据输入位数
        while(1)                                                                                                                   //进入循环
        {
                keynum= MatrixKey();                                 //读按键的位置码
                if(keynum)                                                    //当有按键按下时
                {
                  NUM=keynum;                                                                    //根据按键的位置将其编码,编码值赋值给NUM
                 {
                  switch(NUM)                                                           //判断按键值
                        {
                          case ('A'):      ;                      break;
                         case ('B'):      ;                   break;
                         case ('C'):      ;                           break;   //ABC是无意义按键
                         case ('D'):ResetPassword();          break;   //重新设置密码
                         case ('*'):Cancel();                 break;   //取消当前输入
                         case ('#'):Ensure();                 break;   //确认键
                         default:                                              //如果不是功能键按下时,就是数字键按下
                                {
                                 if(N<4)                                                   //当输入密码少于4位时,接受输入并保存,大于4位时则无效
                                 {
                                   AudioOff=0;                //在有按键输入时,关闭发射机音频输入                                                                                                                        
                                   LCD_WriteCommand(er);
                                                                for(i=0;i<16;i++)
                                                                {
                                                                        LCD_WriteData(Input[i ]);                                                           //显示输入画面
                                                                }
                                                                for(j=0;j<=N;j++)
                                                                {
                                                                        LCD_WriteCommand(er+4+j);                                                           //显示位数随输入增加而增加
                                                                        LCD_WriteData('*');                                                     //但不显示实际数字,用*代替
                                                                }
                                                                InputData[N]=NUM;                                   //将数字键的码赋值给InputData【】数组暂存
                                                                N++;                                                                                                                                                   //密码位数加
                                                               
                                                        }
                                                        else                                                   //输入数据位数大于4后,忽略输入
                                                        {
                                                               
                                                                AudioOff=1;                                //发射机音频输入打开
                                                                N=4;                                     //密码输入大于4位时,不接受输入
                                                                break;
                                                        }
                                                }
                                        }
                                }
                        }

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

5#
ID:277531 发表于 2024-9-3 10:33 | 只看该作者
你这是要求程序如何“强壮”。只有多加监测代码===回答的挺好!
回复

使用道具 举报

地板
ID:404160 发表于 2024-9-3 09:51 | 只看该作者
bd5fna 发表于 2024-9-3 08:05
感谢大佬的回复。我现在的代码也是按“#”号确认或大于4个数,语音转发开启。这个转发器是给很多人共用的 ...

你这是要求程序如何“强壮”。只有多加监测代码
回复

使用道具 举报

板凳
ID:76027 发表于 2024-9-3 08:05 | 只看该作者
飞云居士 发表于 2024-9-2 13:35
代码中的问题在于,当输入的密码少于4位时,AudioOff 被设置为 0(关闭语音转发),但是没有在输入结束后将 ...

感谢大佬的回复。我现在的代码也是按“#”号确认或大于4个数,语音转发开启。这个转发器是给很多人共用的,自己操作按现在的代码来说是没有问题的。但怕捣乱的人只按一个键后不再按了,语音关闭就无法恢复,如果一直按,那也是没有问题的。
回复

使用道具 举报

沙发
ID:404160 发表于 2024-9-2 13:35 | 只看该作者
代码中的问题在于,当输入的密码少于4位时,AudioOff 被设置为 0(关闭语音转发),但是没有在输入结束后将其重新设置为 1(打开语音转发)。这导致了当密码输入少于4位时,语音转发不会自动打开。

密码可以少于4位数,并且需要在输入结束后自动恢复语音转发。问题在于,当输入少于4位的密码时,语音转发没有被正确恢复。我们需要在每次输入结束后检查 N 的值,并在适当的时候将 AudioOff 设置回 1。

为了实现不定长密码输入,并且以时间或特定结束符表示输入完成,你可以修改代码以添加一个计时器或检测特定按键(例如长按某个键或输入特定字符)。这里,我将提供一个示例,使用特定按键(例如长按'#'键)作为结束输入的标志。

以下是修改后的代码:

```c
#include <reg52.h>
#include <intrins.h>

#define LCD_WriteCommand(x) LcdWrite(x, 0)
#define LCD_WriteData(x) LcdWrite(x, 1)

unsigned char InputData[10]; // 增加数组大小以存储更多密码
unsigned char N = 0; // 初始化数据输入位数
bit AudioOff = 1; // 初始化音频转发状态为打开

void Delay_ms(unsigned int ms);
void LCD_Init(void);
void LcdWrite(unsigned char cmd, bit data);
void UART_InitConfig(void);
void Timer0_Init(void);
unsigned char MatrixKey(void);

void main(void)
{
    unsigned char keynum, NUM;
    unsigned char i, j;

    P1M0 &= 0x00;
    P1M1 &= 0x00;

    P3M0 &= ~0x0c; // P3^2-3准双向
    P3M1 &= ~0x0c;
    P3M0 |= 0xf0; // P3^4-7推挽输入
    P3M1 &= ~0xf0;
    P3 = 0x0f; // 初始化信道转换P3^4 5 6 7为低电平

    Delay_ms(400); // 启动等待,等LCM讲入工作状态
    LCD_Init(); // LCD初始化
    UART_InitConfig();
    Timer0_Init();
    LCD_WriteCommand(0x80); // 设置光标位置
    LCD_WriteData('W'); // 写入开机画面
    LCD_WriteData('e');
    LCD_WriteData('l');
    LCD_WriteData('c');
    LCD_WriteData('o');
    LCD_WriteData('m');
    LCD_WriteData('e');
    LCD_WriteData('!');

    while (1) // 进入循环
    {
        keynum = MatrixKey(); // 读按键的位置码
        if (keynum) // 当有按键按下时
        {
            NUM = keynum; // 根据按键的位置将其编码,编码值赋值给NUM
            switch (NUM) // 判断按键值
            {
                case ('A'): ; break;
                case ('B'): ; break;
                case ('C'): ; break; // ABC是无意义按键
                case ('D'): ; break; // 可以添加重新设置密码的函数
                case ('*'): ; break; // 可以添加取消当前输入的函数
                case ('#'): // 长按'#'键结束输入
                    if (N > 0) // 确保有输入
                    {
                        AudioOff = 1; // 打开音频转发
                        LCD_WriteCommand(0x80 + 4 + N); // 移动光标到密码输入结束位置
                        LCD_WriteData('\n'); // 显示换行符表示输入结束
                        N = 0; // 重置密码位数
                    }
                    break;
                default: // 如果不是功能键按下时,就是数字键按下
                    {
                        if (N < 10) // 限制密码最大长度为10位
                        {
                            AudioOff = 0; // 在有按键输入时,关闭发射机音频输入
                            LCD_WriteCommand(0x80 + 4 + N); // 显示位数随输入增加而增加
                            LCD_WriteData('*'); // 但不显示实际数字,用*代替
                            InputData[N] = NUM; // 将数字键的码赋值给InputData[]数组暂存
                            N++; // 密码位数加
                        }
                    }
            }
        }
        else if (AudioOff == 1) // 当没有按键按下时,确保音频转发是打开的
        {
            Delay_ms(100); // 简单的防抖延时
            if (!AudioOff) AudioOff = 1; // 再次检查并确保音频转发是打开的
        }
    }
}

void Delay_ms(unsigned int ms)
{
    // 延时函数实现
}

void LCD_Init(void)
{
    // LCD初始化函数实现
}

void LcdWrite(unsigned char cmd, bit data)
{
    // LCD写入函数实现
}

void UART_InitConfig(void)
{
    // UART初始化配置函数实现
}

void Timer0_Init(void)
{
    // 定时器初始化函数实现
}

unsigned char MatrixKey(void)
{
    // 矩阵键盘扫描函数实现
    return 0; // 示例返回值
}
```

在这个修改中,我添加了一个长按'#'键作为结束输入的标志。当用户长按'#'键时,密码输入结束,音频转发自动打开,并在LCD上显示一个换行符表示输入结束。同时,我增加了一个简单的防抖延时,以确保在没有按键按下时,音频转发是打开的。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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