第十一届蓝桥杯单片机组省赛模拟试题——智能门锁
作者:互联网
试题可以直接在官网下载(试题链接),十分神奇地考了矩阵键盘。
-
按键功能:
矩阵键盘扫描方法很多,这里采用逐行扫描的方法:每次将某一行(R1、R2、R3、R4)置低电平,然后去读每一列(C1、C2、C3、C4)的电平。如果读出某一列为低电平,则表示该行该列所对应的按键被按下,按键注意去抖动。(可能实现起来比较暴力,图是白嫖的)
-
源码:
(1)IIC驱动:
//IIC.h
#include<reg52.h>
sbit SDA = P2^1; //数据线
sbit SCL = P2^0; //时钟线
void Delay_IIC(unsigned char t); //延时函数
void IIC_Start(void); //起始信号
void IIC_Stop(void); //停止信号
void IIC_Ack(unsigned char ackbit); //产生应答
bit IIC_WaitAck(void); //等待应答
void IIC_SendByte(unsigned char byte); //发送数据
unsigned char IIC_RecByte(void); //接收数据
//IIC.c
#include<IIC.h>
void Delay_IIC(unsigned char time)
{
while(time--);
}
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
Delay_IIC(5);
SDA = 0; //在SCL高电平期间,SDA由高变低
Delay_IIC(5);
SCL = 0;
}
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
Delay_IIC(5);
SDA = 1; //在SCL高电平期间,SDA由高变低
Delay_IIC(5);
}
void IIC_Ack(unsigned char ackbit)
{
if(ackbit)
SDA = 0; //产生应答信号
else
SDA = 1; //产生非应答信号
Delay_IIC(5);
SCL = 1;
Delay_IIC(5); //第9个时钟周期
SCL = 0;
SDA = 1; //释放SDA线
Delay_IIC(5);
}
bit IIC_WaitAck(void)
{
SDA = 1;
Delay_IIC(5);
SCL = 1;
Delay_IIC(5);
if(SDA) //在SCL高电平期间,SDA为高电平,从机非应答。
{
SCL = 0;
IIC_Stop();
return 0;
}
else //在SCL高电平期间,SDA为低电平,从机有应答。
{
SCL = 0;
return 1;
}
}
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++) //循环发送8位数据
{
if(byt & 0x80) //数据位是高电平
{
SDA = 1;
}
else //数据位是低电平
{
SDA = 0;
}
Delay_IIC(5);
SCL = 1; //SCL高电平期间,SDA的数据要保持稳定
byt <<= 1; //发送的数据左移,准备发送下一位
Delay_IIC(5); //等待SDA的数据被读取
SCL = 0;
}
}
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
Delay_IIC(5); //在SCL高电平期间,读取SDA的数据
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
Delay_IIC(5);
}
return da;
}
(2)主程序:
#include<reg52.h>
#include"IIC.h"
sfr P4 = 0xC0; //定义P4口
sbit R1 = P3^0; //定义矩阵键盘的行
sbit R2 = P3^1;
sbit R3 = P3^2;
sbit R4 = P3^3;
sbit C1 = P4^4; //定义矩阵键盘的列
sbit C2 = P4^2;
sbit C3 = P3^5;
sbit C4 = P3^4;
sbit L1 = P0^0; //定义LED
sbit L7 = P0^6;
sbit L8 = P0^7;
sbit relay = P0^4; //定义继电器
bit led = 0; //LED状态位
bit over = 0; //密码修改完成标志位(0表示未修改完成,1表示修改完成)
unsigned char seg = 15; //数码管显示第1位
unsigned char stat = 15; //密码操作状态位(14表示输入密码,10表示修改密码)
unsigned char status = 0; //密码输入正确状态下有无操作标志位(0表示有操作,1表示无操作);密码错误状态下初始化标志位
unsigned char count = 0; //定时器计数(50ms计时)
unsigned long pass = 0; //输入密码(定义为32bit)
unsigned long cipher = 0; //存放密码
unsigned char num = 0; //记录存放密码的个数
unsigned char code SEG_code[16] =
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0xc6,0x86,0x8c,0xC8,0xbf,0xff};
//定义共阳数码管段码内容:0~9,C,E,P,N,—,
/*========================================端口选择========================================*/
//端口选择
void Select_HC138(unsigned char n)
{
switch(n)
{
case 0:
P2 = (P2 & 0x1f) | 0x00;
break;
case 4:
P2 = (P2 & 0x1f) | 0x80;
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0;
break;
}
}
/*========================================================================================*/
/*======================================密码存取操作======================================*/
//24C02字节写操作
void Write_24C02(unsigned char addr,unsigned char dat)
{
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0xa0); //写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(addr); //写内存字节地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(dat); //写目标数据
IIC_WaitAck(); //等待从机应答
IIC_Stop(); //IIC总线停止信号
}
//24C02读字节操作
unsigned char Read_24C02(unsigned char addr)
{
unsigned char temp;
//进行一个伪写操作
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0xa0); //写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(addr); //写内存字节地址
IIC_WaitAck(); //等待从机应答
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0xa1); //读设备地址
IIC_WaitAck(); //等待从机应答
temp = IIC_RecByte(); //读取目标数据
IIC_Ack(0); //产生一个非应答信号
IIC_Stop(); //IIC总线停止信号
return temp;
}
//24C02写字节延时函数
void Delay_24C02(unsigned int time)
{
while(time--);
}
/*========================================================================================*/
/*=======================================系统初始化=======================================*/
//初始化
void Init_system()
{
Select_HC138(5);
P0 = 0x00; //关闭蜂鸣器和继电器
Select_HC138(4);
P0 = 0xff; //关闭LED
Select_HC138(6);
P0 = 0x00; //熄灭数码管
Select_HC138(0);
led = 0; //LED状态位
over = 0; //密码修改完成标志位(0表示未修改完成,1表示修改完成)
seg = 15; //数码管显示第1位
stat = 15; //密码操作状态位(14表示输入密码,10表示修改密码)
status = 0; //密码输入正确状态下有无操作标志位(0表示有操作,1表示无操作);密码错误状态下初始化标志位
count = 0; //定时器计数(50ms计时)
pass = 0; //输入密码(定义为32bit)
cipher = 0; //存放密码
num = 0; //记录存放密码的个数
}
//初始化密码
void Init_pass()
{
Write_24C02(0x01,0x88); //保存密码低8位
Delay_24C02(1000);
Write_24C02(0x02,0x88); //保存密码中8位
Delay_24C02(1000);
Write_24C02(0x03,0x88); //保存密码高8位
Delay_24C02(1000); //初始密码为0x888888
}
/*========================================================================================*/
/*=======================================数码管显示=======================================*/
//数码管延时函数
void Delay_tube(unsigned char t)
{
while(t--);
}
//数码管显示
void Show_tube(unsigned char position,unsigned char value)
{
Select_HC138(7);
P0 = 0xff; //熄灭
Select_HC138(6);
P0 = 0x01 << position;
Select_HC138(7);
P0 = value;
}
void Show_all()
{
Select_HC138(7);
P0 = 0xff;
Select_HC138(6);
P0 = 0xff;
}
//数码管动态显示
void Display_cypher() //密码操作
{
Show_tube(0,SEG_code[seg]); //14显示—,10显示C
Delay_tube(100);
if(num >= 6)
{
Show_tube(2,SEG_code[(pass>>24)%16]); //取pass十万位(6)
Delay_tube(100);
}
if(num >= 5)
{
Show_tube(3,SEG_code[(pass>>20)%16]); //取pass万位(5)
Delay_tube(100);
}
if(num >= 4)
{
Show_tube(4,SEG_code[(pass>>16)%16]); //取pass千位(4)
Delay_tube(100);
}
if(num >= 3)
{
Show_tube(5,SEG_code[(pass>>12)%16]); //取pass百位(3)
Delay_tube(100);
}
if(num >= 2)
{
Show_tube(6,SEG_code[(pass>>8)%16]); //取pass十位(2)
Delay_tube(100);
}
if(num >= 1)
{
Show_tube(7,SEG_code[(pass>>4)%16]); //取pass个位(1)
Delay_tube(100);
}
Show_all();
}
void Display_open() //密码输入正确
{
Show_tube(0,SEG_code[0]);
Delay_tube(100);
Show_tube(4,SEG_code[0]); //显示open
Delay_tube(100);
Show_tube(5,SEG_code[12]);
Delay_tube(100);
Show_tube(6,SEG_code[11]);
Delay_tube(100);
Show_tube(7,SEG_code[13]);
Delay_tube(100);
Show_all();
}
/*========================================================================================*/
/*======================================密码检验操作======================================*/
//检验密码是否正确
void Check_pass()
{
if(num == 6 && stat == 15 && seg == 14)
{
unsigned char c;
c = Read_24C02(0x03); //读高8位
cipher |= c;
cipher <<= 8;
c = Read_24C02(0x02); //读中8位
cipher |= c;
cipher <<= 8;
c = Read_24C02(0x01); //读低8位
cipher |= c;
if(cipher == (pass>>4)) //密码正确,显示open
{
stat = 0;
seg = 0;
TR0 = 1; //开定时器中断
num = 0;
pass = 0;
Select_HC138(5);
P0 = 0x00;
relay = 1; //继电器吸合
Select_HC138(0);
}
else if(cipher != (pass>>4)) //密码错误
{
TR0 = 1; //开定时器中断
Select_HC138(4);
L1 = led; //点亮L1(5秒)
Select_HC138(0);
if(status == 1)
{
Init_system(); //初始化
TR0 = 0; //关定时器中断
}
}
}
}
//修改密码
void Reset_pass()
{
if(status == 1 && stat == 0) //5秒内无操作
{
Init_system(); //初始化
TR0 = 0; //关定时器中断
}
else if(status == 0 && stat == 10) //5秒内有操作
{
TR0 = 0; //关定时器中断
pass = 0;
num = 0;
stat = 14; //重新输入密码
}
}
//密码修改完成
void Reset_over()
{
if(over == 1) //再次按下S12,密码修改完成
{
cipher = (pass>>4);
Write_24C02(0x01,cipher%256); //保存密码低8位
Delay_24C02(1000);
Write_24C02(0x02,(cipher>>8)%256); //保存密码中8位
Delay_24C02(1000);
Write_24C02(0x03,(cipher>>16)%256); //保存密码高8位
Delay_24C02(1000);
Init_system();
}
}
/*========================================================================================*/
/*=========================================定时器=========================================*/
//定时器0中断初始化
void Init_timer0()
{
TMOD = 0x01;
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256; //50ms定时
EA = 1; //打开总中断
ET0 = 1; //打开定时器0的中断
TR0 = 0; //关闭定时器0
}
//定时器0中断服务函数
void Service_timer0() interrupt 1
{
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
count++;
if(count == 100) //计时满5S
{
count = 0;
led = 1;
status = 1;
}
}
/*========================================================================================*/
/*========================================按键处理========================================*/
//按键延时函数
void Delay_keys()
{
unsigned char i,j;
i = 108;
j = 145;
do
{
while(--j);
}while(--i);
}
//矩阵键盘
void Press_keys()
{
//==============================扫描第一行================================
R1 = 0;
R2 = R3 = R4 = 1;
C1 = C2 = C3 = C4 = 1;
if(C1 == 0 && stat == 14)
{
Delay_keys();
if(C1 == 0)
{
pass |= 0x00;
pass <<= 4;
num++;
}
while(C1 == 0);
}
else if(C2 == 0 && stat == 14)
{
Delay_keys();
if(C2 == 0)
{
pass |= 0x01;
pass <<= 4;
num++;
}
while(C2 == 0);
}
else if(C3 == 0 && stat == 14)
{
Delay_keys();
if(C3 == 0)
{
pass |= 0x02;
pass <<= 4;
num++;
}
while(C3 == 0);
}
else if(C4 == 0 && stat == 14)
{
Delay_keys();
if(C4 == 0)
{
pass |= 0x03;
pass <<= 4;
num++;
}
while(C4 == 0);
}
if(num >= 6)
{
stat = 15;
Select_HC138(4);
P0 = 0xff;
Select_HC138(0);
if(seg == 10) //在修改密码状态下,将stat置0
{
stat = 0;
over = 1; //输入完成
}
}
//========================================================================
//==============================扫描第二行================================
R2 = 0;
R1 = R3 = R4 = 1;
C1 = C2 = C3 = C4 = 1;
if(C1 == 0 && stat == 14)
{
Delay_keys();
if(C1 == 0)
{
pass |= 0x04;
pass <<= 4;
num++;
}
while(C4 == 0);
}
else if(C2 == 0 && stat == 14)
{
Delay_keys();
if(C2 == 0)
{
pass |= 0x05;
pass <<= 4;
num++;
}
while(C2 == 0);
}
else if(C3 == 0 && stat == 14)
{
Delay_keys();
if(C3 == 0)
{
pass |= 0x06;
pass <<= 4;
num++;
}
while(C3 == 0);
}
else if(C4 == 0 && stat == 14)
{
Delay_keys();
if(C4 == 0)
{
pass |= 0x07;
pass <<= 4;
num++;
}
while(C4 == 0);
}
if(num >= 6)
{
stat = 15;
Select_HC138(4);
P0 = 0xff;
Select_HC138(0);
if(seg == 10) //在修改密码状态下,将stat置0
{
stat = 0;
over = 1;
}
}
//========================================================================
//==============================扫描第三行================================
R3 = 0;
R1 = R2 = R4 = 1;
C1 = C2 = C3 = C4 = 1;
if(C1 == 0 && stat == 14)
{
Delay_keys();
if(C1 == 0)
{
pass |= 0x08;
pass <<= 4;
num++;
}
while(C1 == 0);
}
else if(C2 == 0 && stat == 14)
{
Delay_keys();
if(C2 == 0)
{
pass |= 0x09;
pass <<= 4;
num++;
}
while(C2 == 0);
}
if(num >= 6)
{
stat = 15;
Select_HC138(4);
P0 = 0xff;
Select_HC138(0);
if(seg == 10) //在修改密码状态下,将stat置0
{
stat = 0;
over = 1;
}
}
//========================================================================
//==============================扫描第四行================================
R4 = 0;
R1 = R2 = R3 = 1;
C1 = C2 = C3 = C4 = 1;
if(C2 == 0 && stat == 14) //清除全部数字
{
Delay_keys();
if(C2 == 0)
{
if(num < 6)
{
pass = 0;
num = 0;
}
}
while(C2 == 0);
}
else if(C3 == 0 && stat == 0) //修改密码
{
Delay_keys();
if(C3 == 0)
{
stat = 10;
seg = 10;
Select_HC138(4);
P0 = 0xff;
L8 = 0; //点亮L8
Select_HC138(0);
Reset_over(); //再次按下,修改完成
}
while(C3 == 0);
}
else if(C4 == 0 && stat == 15 && seg != 10) //开始输入密码
{
Delay_keys();
if(C4 == 0)
{
stat = 14;
seg = 14;
Select_HC138(4);
P0 = 0xff;
L7 = 0; //点亮L7
Select_HC138(0);
}
while(C4 == 0);
}
}
/*========================================================================================*/
/*=========================================主函数=========================================*/
//主函数
void main()
{
Init_timer0();
Init_system();
Init_pass();
while(1)
{
switch(seg)
{
case 14:
case 10:
Display_cypher();
break;
case 0:
Display_open();
break;
}
Press_keys();
Check_pass();
Reset_pass();
}
}
/*========================================================================================*/
标签:Delay,密码,void,unsigned,蓝桥,单片机,IIC,pass,组省赛 来源: https://blog.csdn.net/qq_41412394/article/details/105266987