【AT89C52单片机项目】数字密码锁设计

  • 实验目的

使用单片机设计数字密码锁。

  • 实验仪器

一套STC89C52RC开发板套件,包括STC89C52RC开发板,以及USB烧录线。

  • 设计要求

1、有设置密码、开锁工作模式;

2、可以每次都设置密码,也可以设置一次密码多次使用。

  • 实验原理

本实验所需要的主要硬件电路介绍

1)、矩阵按键

矩阵键盘扫描原理:

1、行线输出全为0;

2、读入列线值;

3、列线输出上次读入的值

4、读入行线值

5、组合2种读入值

优点:m*n个按键值需要一次反转(2次输入输出)就可以检测到结果,比行列扫面简单。

  • 实验流程
  1. 根据教材进行学习数码管显示控制,本项目单片机为八段共阴数码管,段码为{ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f},分别表示0~9
  2. 根据教材进行学习矩形键盘、矩形键盘的反转扫描、矩形键盘密码锁的样例,根据矩形键盘密码锁样例改写代码。
  3. 将程序烧录进入单片机,并且把单片机中USB232连接OFF。
  • 实验结果

输入密码"12345678"后,数码管显示open。

|---------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| | |

输入其他密码后,数码管显示Err。

|---------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| | |

  • 代码
cpp 复制代码
#include <reg52.h>

#define DataPort P0   //定义数码管显示数据端口
#define KeyPort P3    //定义矩阵按键的数据端口
sbit LATCH1 = P2 ^ 6;  //定义锁存使能端口  段锁存
sbit LATCH2 = P2 ^ 7;  //定义锁存使能端口  位锁存

unsigned char code DuanMa[] = { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//共阴极数码管段码表,包含字母abcdef

unsigned char code WeiMa[] = { 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};  //位码表

unsigned char TempData[8];   //用来存放数码管数据
unsigned char Data[8];
unsigned char password[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };  //设置密码
void DelayUs2x(unsigned char t);  //延迟函数
void DelayMs(unsigned char t);  //毫秒延迟函数
void Display(unsigned char FirstBit, unsigned char Num);  //数码管显示函数
unsigned char KeyScan(void);  //键盘扫描函数,使用行列逐级扫描法
unsigned char KeyPro(void);  //把键盘扫描结果转换为数字的函数
main()
{
    unsigned char num = 0, i = 0, j; //定义并初始化变量
    unsigned char Flag = 0;
    while (1)
    {
        num = KeyPro();  //获取按键数字
        if (num != 0xff) //如果按键状态发生变化
        {
            if (i == 0)
            {
                for (j = 0; j < 8; j++) //初始化数码管数据,清屏
                {
                    TempData[j] = 0xff; 
                }
            }

            if (i < 8)
            {
                Data[i] = DuanMa[num]; //把按键值输入到临时数组中
                for (j = 0; j <= i; j++)   //通过一定顺序把临时数组中
                {                       //的值赋值到显示缓冲区,从右往左输入
                    TempData[7 - i + j] = Data[j]; //数字从数码管右侧逐渐出现
                }
            }

            i++;   //输入数值累加
            if (i == 9) //如果密码输入完毕
            {
                i = 0; //初始化变量i,以便之后可以重新输入密码
                Flag = 1;  //先把比较位置1
                for (j = 0; j < 8; j++)  //循环比较8个数值
                {                       //如果有一个不等 则最终Flag值为0
                    Flag = Flag && (Data[j] == DuanMa[password[j]]);
                }    //比较输入值和已有密码

                for (j = 0; j < 8; j++) // 清屏
                {
                    TempData[j] = 0xff;
                }

                if (Flag)
                {
                    TempData[0] = 0x3f;//O
                    TempData[1] = 0x73;//P
                    TempData[2] = 0x79;//E
                    TempData[3] = 0x54;//n
                    for (j = 4; j < 8; j++)
                    {
                        TempData[j] = 0x00; //除了open后面不显示
                    }
                }

                else
                {
                    TempData[0] = 0x79;//E
                    TempData[1] = 0x50;//r
                    TempData[2] = 0x50;//r
                    for (j = 3; j < 8; j++)
                    {
                        TempData[j] = 0x00;
                    }
                }
            }
        }

        Display(0, 8);
        //DelayMs(1000);
    }
}

void DelayUs2x(unsigned char t)
{
    while (--t)
    {

    }
}
void DelayMs(unsigned char t)
{
    while (--t)
    {
        DelayUs2x(245);
        DelayUs2x(245);
    }
}
void Display(unsigned char FirstBit, unsigned char Num)
{
    unsigned char i;
    for (i = 0; i < Num; i++)
    {
        DataPort = 0;  //清空数据,防止有交替重影
        LATCH1 = 1;
        LATCH1 = 0;

        DataPort = WeiMa[i + FirstBit]; //取位码
        LATCH2 = 1;  //位锁存
        LATCH2 = 0;

        DataPort = TempData[i];  //取显示数据,段码
        LATCH1 = 1;  //段锁存
        LATCH1 = 0;

        DelayUs2x(200);  //扫描间隙延时,时间太长会闪烁
    }                   //太短会造成重影
}

unsigned char KeyScan(void)  //键盘扫描函数,使用行列逐级扫描法
{
    unsigned char Val;
    KeyPort = 0xf0;  //高四位 置高电平,低四位 置低电平
    if (KeyPort != 0xf0)  //如果有按键按下
    {
        DelayMs(10);  //去抖

        if (KeyPort != 0xf0)
        {  //如果有按键按下
            KeyPort = 0xfe; //检测第一行
            if (KeyPort != 0xfe)
            {
                Val = KeyPort & 0xf0;
                Val += 0x0e;
                while (KeyPort != 0xfe) ;
                DelayMs(10); //去抖
                while (KeyPort != 0xfe) ;
                return Val;
            }

            KeyPort = 0xfd; //检测第二行
            if (KeyPort != 0xfd)
            {
                Val = KeyPort & 0xf0;
                Val += 0x0d;
                while (KeyPort != 0xfd) ;
                DelayMs(10);  //去抖
                while (KeyPort != 0xfd) ;
                return Val;
            }

            KeyPort = 0xfb;  //检测第三行
            if (KeyPort != 0xfb)
            {
                Val = KeyPort & 0xf0;
                Val += 0x0b;
                while (KeyPort != 0xfb) ;
                DelayMs(10); //去抖
                while (KeyPort != 0xfb) ;
                return Val;
            }

            KeyPort = 0xf7; //检测第四行
            if (KeyPort != 0xf7)
            {
                Val = KeyPort & 0xf0;
                Val += 0x07;
                while (KeyPort != 0xf7) ;
                DelayMs(10); //去抖
                while (KeyPort != 0xf7) ;
                return Val;
            }
        }
    }
    return 0xff;
}

unsigned char KeyPro(void)
{
    switch (KeyScan())
    {
        case 0x7e: return 0; break;//0 按下相应的键显示相对应的码值
        case 0x7d: return 1; break;//1
        case 0x7b: return 2; break;//2
        case 0x77: return 3; break;//3
        case 0xbe: return 4; break;//4
        case 0xbd: return 5; break;//5
        case 0xbb: return 6; break;//6
        case 0xb7: return 7; break;//7
        case 0xde: return 8; break;//8
        case 0xdd: return 9; break;//9
        case 0xdb: return 10; break;//a
        case 0xd7: return 11; break;//b
        case 0xee: return 12; break;//c
        case 0xed: return 13; break;//d
        case 0xeb: return 14; break;//e
        case 0xe7: return 15; break;//f
        default: return 0xff; break;
    }
}
相关推荐
yutian06067 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
析木不会编程10 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉14 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名67714 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式大圣14 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室15 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费15 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_3975623117 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
liyinuo201717 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范
艺术家天选17 小时前
STM32点亮LED灯
stm32·单片机·嵌入式硬件