- 实验目的
使用单片机设计数字密码锁。
- 实验仪器
一套STC89C52RC开发板套件,包括STC89C52RC开发板,以及USB烧录线。
- 设计要求
1、有设置密码、开锁工作模式;
2、可以每次都设置密码,也可以设置一次密码多次使用。
- 实验原理
本实验所需要的主要硬件电路介绍
1)、矩阵按键
矩阵键盘扫描原理:
1、行线输出全为0;
2、读入列线值;
3、列线输出上次读入的值
4、读入行线值
5、组合2种读入值
优点:m*n个按键值需要一次反转(2次输入输出)就可以检测到结果,比行列扫面简单。
- 实验流程
- 根据教材进行学习数码管显示控制,本项目单片机为八段共阴数码管,段码为{ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f},分别表示0~9
- 根据教材进行学习矩形键盘、矩形键盘的反转扫描、矩形键盘密码锁的样例,根据矩形键盘密码锁样例改写代码。
- 将程序烧录进入单片机,并且把单片机中USB232连接OFF。
- 实验结果
输入密码“12345678”后,数码管显示open。
输入其他密码后,数码管显示Err。
- 代码
#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;
}
}