【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;
    }
}
相关推荐
智者知已应修善业42 分钟前
【51单片机用数码管显示流水灯的种类是按钮控制数码管加一和流水灯】2022-6-14
c语言·经验分享·笔记·单片机·嵌入式硬件·51单片机
智商偏低7 小时前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen8 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森10 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白10 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D11 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术14 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt14 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘15 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang15 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c