直接看题目先。
全部程序:提取码:azxy
#include "STC15F2K60S2.h"
#include "intrins.h"
#include "ds1302.h"
#include "iic.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit TX=P1^0;//超声波发射引脚
sbit RX=P1^1;//超声波接收引脚
sbit H1=P3^0;
sbit H2=P3^1;
sbit H3=P3^2;
sbit H4=P3^3;
//矩阵键盘引脚定义
sbit L1=P4^4;
sbit L2=P4^2;
sbit L3=P3^5;
sbit L4=P3^4;
u8 code duan[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};//0~9
u8 mima[6]={6,5,4,3,2,1};//正确密码存储数组
u8 mima1[6]={10,10,10,10,10,10};//输入时显示的密码数组
u8 store_addr[6]={0x00,0x01,0x02,0x03,0x04,0x05};//密码存储在EEPROM的地址
extern unsigned char Time[3];//DS1302时分秒数组
u16 dat=0;//超声波测得的距离
u8 flag=0;//矩阵键盘按键按标志
u8 key_num=0;//按键键值
u8 model=0;//数码管显示的界面0~3 0:时间界面 1:密码待输入界面 2:修改密码界面 3:输入要修改的密码界面
u8 num=0;//记录密码长度
u8 relay=0;//继电器标志
u8 been=0;//蜂鸣器标志
u16 count=0;//继电器响应时间标志
u16 count1=0;//蜂鸣器响应时间标志
u8 error_flag=0;//密码错误次数记录
u8 aa;//保证第一次上电密码是654321
void delay(u16 i)//延迟函数
{
while(i--);
}
void Delay5ms()//延迟5MS,方便EEPROM连续写
{
unsigned char i, j;
i = 59;
j = 90;
do
{
while (--j);
} while (--i);
}
void Chan_hc573(u8 chose)//锁存器选择
{
switch(chose)
{
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;
}
P2 = (P2 & 0x1f) | 0x00;
}
void Init_system()//初始化开发板,关闭LED灯,蜂鸣器,继电器
{
P0=0x00;
Chan_hc573(5);
P0=0xff;
Chan_hc573(4);
}
void Smg_display(u8 com,u8 dat)//控制数码管的位选和段选
{
P0=0xff;
Chan_hc573(7);
P0=0x01<<com;
Chan_hc573(6);
P0=dat;
Chan_hc573(7);
delay(1000);
}
void Close_smg()//数码管消隐
{
P0=0x00;
Chan_hc573(6);
P0=0xff;
Chan_hc573(7);
}
void Wire_mima()//密码复位和保证第一次上电密码是654321
{
Wire_dat(store_addr[0],6);Delay5ms();
Wire_dat(store_addr[1],5);Delay5ms();
Wire_dat(store_addr[2],4);Delay5ms();
Wire_dat(store_addr[3],3);Delay5ms();
Wire_dat(store_addr[4],2);Delay5ms();
Wire_dat(store_addr[5],1);Delay5ms();
}
void Read_mima()//读取EEPROM里面的密码
{
u8 i=0;
for(i=0;i<6;i++) {mima[i]=Read_dat(store_addr[i]);}
}
//========================================//
//================自动门状态==============//
//========================================//
void Delay12us()//延迟12US,用于超声波发射
{
unsigned char i;
_nop_();
_nop_();
i = 36;
while (--i);
}
void scan_csp()//超声波发射40Khz的频率
{
u8 i=0;
for(i=0;i<8;i++)
{
TX=1;
Delay12us();
TX=0;
Delay12us();
}
}
void Try_cj()//超声波所测得的距离
{
TMOD &= 0x0F;
EA=1;
ET0=1;
TH0=0;
TL0=0;
TF0=0;
scan_csp();
TR0=1;
while((TF0==0)&(RX==1));
TR0=0;
if(TF0==1)
{
TF0=0;
dat=999;
}
else
{
dat=(TH0<<8)|TL0;
dat=dat*0.017+3;//测得的距离
}
if(dat<30) {relay=1;TR1=1;}//小于30cm继电器打开,定时器1打开
}
void Display_time()//显示从DS1302中所读取到的时间
{
Smg_display(0,duan[Time[0]/16]); //时
Smg_display(1,duan[Time[0]%16]);
Smg_display(2,duan[11]);
Smg_display(3,duan[Time[1]/16]); //分
Smg_display(4,duan[Time[1]%16]);
Smg_display(5,duan[11]);
Smg_display(6,duan[Time[2]/16]); //秒
Smg_display(7,duan[Time[2]%16]);
Close_smg(); //数码管消隐
}
//========================================//
//================密码门状态==============//
//========================================//
void Display_mima()//密码门状态时所显示的界面
{
if(model==1)
{
Smg_display(0,duan[11]); //显示 —
Smg_display(1,duan[11]); //显示 —
}
else if(model==2)
{
Smg_display(0,duan[10]); //数码管熄灭
Smg_display(1,duan[11]); //显示 —
}
else if(model==3)
{
Smg_display(0,duan[11]);//显示 —
Smg_display(1,duan[10]); //数码管熄灭
}
Smg_display(2,duan[mima1[0]]);
Smg_display(3,duan[mima1[1]]);
Smg_display(4,duan[mima1[2]]);
Smg_display(5,duan[mima1[3]]); //显示所输入的密码
Smg_display(6,duan[mima1[4]]);
Smg_display(7,duan[mima1[5]]);
Close_smg();
}
void Clear_mima()//用于密码输入正确或错误时清除已输入的密码,回到待输入状态
{
u8 i;
for(i=0;i<6;i++) {mima1[i]=10;}
}
void Key_down()//矩阵键盘的程序,通过按下的按键获取键值
{
H1=0;
H2=H3=H4=L1=L2=L3=L4=1;
if(L1==0) //键值0
{
delay(1000);
if(L1==0)
{
flag=1;
while(L1==0) {}
key_num=0;
}
}
else if(L2==0) //键值1
{
delay(1000);
if(L2==0)
{
flag=1;
while(L2==0) {}
key_num=1;
}
}
else if(L3==0) //键值2
{
delay(1000);
if(L3==0)
{
flag=1;
while(L3==0) {}
key_num=2;
}
}
else if(L4==0) //键值3
{
delay(1000);
if(L4==0)
{
flag=1;
while(L4==0) {}
key_num=3;
}
}
H2=0;
H1=H3=H4=L1=L2=L3=L4=1;
if(L1==0) //键值4
{
delay(1000);
if(L1==0)
{
flag=1;
while(L1==0) {}
key_num=4;
}
}
else if(L2==0) //键值5
{
delay(1000);
if(L2==0)
{
flag=1;
while(L2==0) {}
key_num=5;
}
}
else if(L3==0) //键值6
{
delay(1000);
if(L3==0)
{
flag=1;
while(L3==0) {}
key_num=6;
}
}
else if(L4==0) //键值7
{
delay(1000);
if(L4==0)
{
flag=1;
while(L4==0) {}
key_num=7;
}
}
H3=0;
H2=H1=H4=L1=L2=L3=L4=1;
if(L1==0) //键值8
{
delay(1000);
if(L1==0)
{
flag=1;
while(L1==0) {}
key_num=8;
}
}
else if(L2==0) //键值9
{
delay(1000);
if(L2==0)
{
flag=1;
while(L2==0) {}
key_num=9;
}
}
else if(L3==0) //设置键
{
delay(1000);
if(L3==0)
{
while(L3==0) {}
if(model==0) {model=2;}
}
}
else if(L4==0) //复位键
{
delay(1000);
if(L4==0)
{
while(L4==0) {}
mima[0]=6;mima[1]=5;mima[2]=4;
mima[3]=3;mima[4]=2;mima[5]=1;
Wire_mima();
}
}
H4=0;
H2=H3=H1=L1=L2=L3=L4=1;
if(L3==0)
{
delay(1000);
if(L3==0) //确认键
{
count=0;count1=0;
while(L3==0) {}
key_num=14;
}
}
else if(L4==0) //返回键
{
delay(1000);
if(L4==0)
{
while(L4==0) {}
if((model==2)||(model==3)) {model=0;}
num=0;
Clear_mima();
}
}
}
void Mima_scan()//输入密码时每次按下所读取到的键值
{
u8 dat=0;
Key_down();
if(flag==1)//按键按下标志
{
if(model==0) {model=1;}//初始化时显示的是时间界面,按下键盘就到待输入密码界面
switch(key_num)//通过键值读取所按下的数字
{
case 0: dat=0; break;
case 1: dat=1; break;
case 2: dat=2; break;
case 3: dat=3; break;
case 4: dat=4; break;
case 5: dat=5; break;
case 6: dat=6; break;
case 7: dat=7; break;
case 8: dat=8; break;
case 9: dat=9; break;
}
mima1[num]=dat;//把读取到的数字存储到输入时显示的密码数组里
num++;//每按下一次,存储位置加一
if(num==6) {num=6;}//密码输入完成
flag=0;//返回0,防止程序一直运行
}
}
void Right_mima()//输入密码与正确密码进行比对
{
u8 i=0;
if(key_num==14)//代表确认键按下
{
if(num==6)//代表密码输入完成
{
if(model==1)//待输入密码界面
{
if((mima1[0]==mima[0])&&(mima1[1]==mima[1])&&(mima1[2]==mima[2])&&(mima1[3]==mima[3])&&(mima1[4]==mima[4])&&(mima1[5]==mima[5]))
{ //如果密码正确
relay=1; //继电器打开
TR1=1; //定时器打开
num=0; //清零,等待下一次输入
error_flag=0; //错误次数清零
}
else //密码错误
{
num=0; //清零,等待下一次输入
error_flag++; //错误次数加一
model=1; //返回等待输入界面
Clear_mima(); //清除刚才输入错误的密码
if(error_flag==3) //如果错误了三次
{
TR1=1; //定时器打开
been=1; //蜂鸣器打开
model=0; //返回时间显示界面
}
}
}
else if(model==2) //修改密码界面
{
if((mima1[0]==mima[0])&&(mima1[1]==mima[1])&&(mima1[2]==mima[2])&&(mima1[3]==mima[3])&&(mima1[4]==mima[4])&&(mima1[5]==mima[5]))
{ //如果密码正确
model=3; //跳转到输入要修改密码的界面
if(num==6) //要修改的密码输入完成
{
if(model==3) {Clear_mima();}//清除刚才输入正确的密码
num=0; //清零,等待下一次输入
}
error_flag=0; //错误次数清零
}
else //密码错误
{
num=0; //清零,等待下一次输入
Clear_mima(); //清除刚才输入错误的密码
error_flag++; //错误次数加一
model=2; //返回到修改密码界面
if(error_flag==3) //如果错误了三次
{
TR1=1; //定时器打开
been=1; //蜂鸣器打开
model=0; //返回时间显示界面
}
}
}
else if(model==3) //输入要修改密码的界面
{
for(i=0;i<6;i++) {mima[i]=mima1[i];}//把输入的密码存储到真正的密码数组里面
for(i=0;i<6;i++) {Wire_dat(store_addr[i],mima1[i]);Delay5ms();}//把输入的密码存储到EEPORM里面
model=0; //返回时间显示界面
num=0; //清零,等待下一次输入
Clear_mima(); //清除刚才输入修改后的密码
}
}
}
}
void Been_stat()//蜂鸣器打开与关闭
{
if(been==1)//打开蜂鸣器
{
P06=1;P04=0;
Chan_hc573(5);
}
else //关闭蜂鸣器
{
if(relay==0)//继电器关闭状态,如果不加这个判断,TR1会马上关闭,到时候继电器不能正常运行
{
TR1=0;//关闭定时器1
P06=0;P04=0;
Chan_hc573(5);
}
}
}
void Mima_stat()//区分两种门所要显示的界面
{
if(model==0) {Display_time();}//公共界面,时间显示界面
else {Display_mima();}//密码门状态显示界面
}
//========================================//
//================全部程序整合============//
//========================================//
void all_stat()//公共继电器的处理
{
if((Time[0]>0x06)&&(Time[0]<0x22))//自动门状态
{
if(TR1==0) {Try_cj();} //继电器关闭状态下才发射超声波
Display_time(); //显示时间
if(relay==1) //如果继电器打开
{
P04=1;P06=0;
Chan_hc573(5);
}
else //继电器关闭状态
{
TR1=0; //定时器1也关闭
count=0; //时间清零
P04=0;P06=0;
Chan_hc573(5);
}
}
else //密码门状态
{
Mima_stat(); //区分两种门所要显示的界面
Mima_scan(); //输入密码时每次按下所读取到的键值
Right_mima(); //输入密码与正确密码进行比对
Been_stat(); //蜂鸣器打开与关闭
if(relay==1) //如果继电器打开
{
P04=1;P06=0;
Chan_hc573(5);
}
else //继电器关闭状态
{
if(been==0) //蜂鸣器关闭状态,如果不加这个判断,TR1会马上关闭,到时候蜂鸣器不能正常运行
{
TR1=0; //关闭定时器1
P04=0;P06=0;
Chan_hc573(5);
}
}
}
}
void Timer1Init(void) //定时器1 定时1ms 12.000MHz
{
AUXR |= 0x40;
TMOD &= 0x0F;
TL1 = 0x20;
TH1 = 0xD1;
TF1 = 0;
ET1 = 1;
EA = 1;
}
void Service_T1() interrupt 3 //定时器中断服务函数
{
count++; //继电器时间自加
count1++; //蜂鸣器时间自加
if(count==5000) //继电器时间达到5S
{
count=0; //继电器时间清零
relay=0; //关闭继电器
model=0; //返回时间显示界面
Clear_mima(); //清除刚才输入的密码
}
if(count1==3000) //蜂鸣器时间达到3S
{
error_flag=0; //输入错误次数清零
count1=0; //蜂鸣器时间清零
been=0; //关闭蜂鸣器
if(relay==0) {Clear_mima();} 清除刚才输入的密码
}
}
void First_mima()//保证第一次开发板上电密码是654321
{
aa=Read_dat(0x55);//随便从EEPROM中选择一个地址读取它的值
if(aa!=99) //正常读取到的值为255,所以几率很小是99,如果怕是99的话可以多读取几个地址,这样几率会小更多
{
Wire_mima();//读取到不是99,就把密码654321写进去
Wire_dat(0x55,99);//然后把刚才读取的地址写入99,下次就不会运行这一段程序了
}
Read_mima();//读取EEPROM里面的密码,并赋值给密码存储数组,用于密码对比
}
void main()//主函数
{
Init_system();//初始化开发板,关闭LED灯,蜂鸣器,继电器
Timer1Init();//定时器1 定时1ms 12.000MHz
wire_ds1302();//写入初始化时间
Read_mima();//读取EEPROM里面的密码
First_mima();//保证第一次开发板上电密码是654321
while(1)
{
all_stat();//公共继电器的处理
Key_down();//矩阵键盘的程序,通过按下的按键获取键值
read_ds1302();//读取DS1302里面的时间
}
}