- 实验目的
使用单片机设计数字密码锁。
- 实验仪器
一套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};//共阴极数码管段码表,包含字母abcdefunsigned 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; //先把比较位置1for (j = 0; j < 8; j++) //循环比较8个数值{ //如果有一个不等 则最终Flag值为0Flag = Flag && (Data[j] == DuanMa[password[j]]);} //比较输入值和已有密码for (j = 0; j < 8; j++) // 清屏{TempData[j] = 0xff;}if (Flag){TempData[0] = 0x3f;//OTempData[1] = 0x73;//PTempData[2] = 0x79;//ETempData[3] = 0x54;//nfor (j = 4; j < 8; j++){TempData[j] = 0x00; //除了open后面不显示}}else{TempData[0] = 0x79;//ETempData[1] = 0x50;//rTempData[2] = 0x50;//rfor (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;//1case 0x7b: return 2; break;//2case 0x77: return 3; break;//3case 0xbe: return 4; break;//4case 0xbd: return 5; break;//5case 0xbb: return 6; break;//6case 0xb7: return 7; break;//7case 0xde: return 8; break;//8case 0xdd: return 9; break;//9case 0xdb: return 10; break;//acase 0xd7: return 11; break;//bcase 0xee: return 12; break;//ccase 0xed: return 13; break;//dcase 0xeb: return 14; break;//ecase 0xe7: return 15; break;//fdefault: return 0xff; break;}
}