【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;
    }
}
相关推荐
StarsGreen3 分钟前
Android 启动流程详解
android·linux·单片机·嵌入式硬件
en.en..8 分钟前
AFE:模拟前端,模拟世界通往 MCU 的信号桥梁
单片机·嵌入式硬件
小鳄鱼电气1 小时前
感应电机直接转矩控制传动(AC4 200 HP)仿真说明书
单片机·嵌入式硬件
Dev_XH15 小时前
【成品设计】基于单片机的家用智能浇花系统的设计与实现
stm32·单片机·嵌入式硬件·物联网
意法半导体STM3216 小时前
【官方原创】LAT1717 STM32N6 如何使用单个XSPI驱动双片相同HyperRAM
stm32·单片机·嵌入式硬件·mcu·stm32n6·hyperram
木子单片机16 小时前
基于单片机的直流电机调速系统设计
单片机·嵌入式硬件·51单片机·nosql·keil
Zwawa18 小时前
两根线怎么挂住一堆设备:I2C 协议原理
c语言·单片机·嵌入式
倔强的胡萝卜20 小时前
基于STM32F103C8T6的温度报警器设计
stm32·单片机·嵌入式硬件
缘来是你远去是我20 小时前
ZYNQ 系列芯片中断机制详解:类型、处理过程与中断处理函数
单片机·嵌入式硬件
LCG米1 天前
STM32 定时器主从模式输出精确脉冲数实测:TRGO 触发链拆解、多发一脉冲根因与干净停止时序落地
stm32·单片机·嵌入式硬件·嵌入式