一、项目背景及功能需求
1.1项目背景
智能门锁是一种智能化、高效、安全的门锁,它可以实现密码识别开锁方式,极大地提高了门锁的安全性和便利性。随着人们对安全性的要求越来越高,智能门锁已经成为了现代家庭和企业的必备设备。因此,本项目旨在设计一款基于STC15单片机的智能门锁,以满足人们对安全性和便利性的需求。
1.2 功能需求
从功能上来看,主要分为四个部分:显示时间、密码门锁、修改密码和计算器。其中显示时间可以实时获取当前时间日期;密码门锁不仅可以防盗,还能防止用户忘记带钥匙;修改密码可以让用户在密码泄露时及时更改密码;计算器为创新功能,可以进行一些简单的算术运算。其具体的功能架构如下:
用到的文件模块如下:
(1)显示学号:开始会显示“WelcomeSmartLock”和自己的学号
(2)显示时间:可以实时获取当前日期,星期,时间
(3)密码门锁:输入正确密码即可进行开锁,密码错误3次就会发出警报
(4)修改密码:当门锁打开时才能进行修改密码,修改的密码还需要确认重新输入一次,防止用户输错,只有当两次输入一样,才能进行密码的修改;
(5)计算器:可以进行简单的算数运算
(6)结尾有一个动画页面
二、实训环境
单片机开发板套件、Keil C51、STC-ISP
三、项目硬件搭建
3.1硬件设备
硬件部分包括单片机最小系统、矩阵按键、LCD1602、RTC、步进电机等模块,系统框图如下图所示。
3.2硬件连接电路图
3.3硬件搭建实物图
四、具体任务及内容
完成一个智能门锁,包括以下内容:首先使用软件STC-ISP自动生成所需要延时的秒数,完成延时模块的设计,然后进行LCD1062模块的配置,写好显示函数,可以再液晶屏上显示自己想要的内容;然后用取模软件生成想要的图像,使得液晶屏上能显示开锁和关锁的图像;然后完成4x4矩阵键盘的配置,能够识别哪个键盘按下,并且读入相应的信息;然后完成电机驱动模块的配置,由于单片机电压不足,于是需要引入该模块来调动电机,能够进行门锁的开关。然后进行IIC模块的配置,使得单片机能进行简单的通信;随后进行PCF8263模块的配置,能够进行时间的发送与接收,实时获取当前时间。
五、项目运行说明及截图
通过三天的努力,我成功实现了并创新了这次的智能门锁。智慧门锁从功能上来看,主要分为四个部分:显示时间,密码门锁,修改密码,计算器。其中显示时间可以实时读取显示当前时间;密码门锁只有输入正确密码才会开门,输错3次后会报警;修改密码只有开门后才有权限进行修改,并且需要输入两次一样的要修改的密码才会修改成功;计算器是附加的创新功能,可以进行简单的算术运算。
具体功能体现如下:
进入界面
时间显示界面
门锁界面
修改密码
(没开锁)
(已开锁)
计算器界面
动画界面
七、附录:(其他相关技术文档或程序实现源码)
main.c文件
#include <stc15.h>
#include <string.h>
#include "LCD1602.h"
#include "delay.h"
#include "zimo.h"
#include "Key16.h"
#include "stepmotor.h"
#include "PCF8563.h"
#include "JiSuanQi.h"
#define uchar unsigned char
#define uint unsigned int
sbit beep=P3^7;
uint X=999;
uchar clear[]=" ";
uchar clearPwd[]=" ";
uchar show1[]="WelcomeSmartLock";
uchar show2[]="InputPassword";
uchar success_show[]="Success!";
uchar fail_show[]="Fail!";
uchar number[]="211071085";
extern unsigned char time_buf1[8];
extern unsigned char time_buf[8];
uchar PWD[]="888888";
uchar input_Pwd[8];
uchar oneInput[8];
uchar twoInput[8];
uchar JiSuan[10];
uint ans;
uchar clockFlag=0;
uint Motor_Num;
uchar my_input=0;
uchar index=0;
uchar pageFlag=0;
uchar Flag=0;//行
uchar FailNum=0;
void LCD_Show_closeClock();
void LCD_Show_openClock();
void LCD_Clear();
void openClock();
void close();
void LCD_Show_Time();
void Show_Xin();
void main()
{
P3M0=0x00;
P3M1=0x00;
LCD_Init();
// time_init();
LCD_Show_String(0,0,show1);
LCD_Show_String(3,1,number);
Delay1000ms();
LCD_Clear();
while(1)
{
my_input = KeyScan_4x4();
if(my_input=='/')
{
pageFlag=(pageFlag+1)%5;
LCD_Clear();
Delay200ms();
}
if(pageFlag==0)//页面1显示时间
{
LCD_Show_Time();
}
else if(pageFlag==1)//页面2显示门锁
{
if(clockFlag==0)
{
LCD_Show_closeClock();
LCD_Show_String(0,0,show2);
}
else if(clockFlag==1)
{
LCD_Show_openClock();
}
if('0'<=my_input && my_input<='9' && index<=7)
{
input_Pwd[index]=my_input;
LCD_Show_OneChar(index, 1, input_Pwd[index]);
Delay200ms();
LCD_Show_OneChar(index, 1, '*');
index++;
LCD_Show_OneChar(14, 1, index+'0');
}
if(my_input=='<' && index!=0)
{
index--;
input_Pwd[index]='0';
LCD_Show_OneChar(index, 1, ' ');
Delay200ms();
LCD_Show_OneChar(14, 1, index+'0');
}
if(my_input=='=')
{
LCD_Clear();
input_Pwd[index]='\0';
index=0;
if(strcmp(input_Pwd,PWD)==0 && clockFlag==0)
{
LCD_Show_String(0,0,success_show);
openClock();
Delay1000ms();
LCD_Clear();
clockFlag=1;
LCD_Show_openClock();
input_Pwd[0]='\0';
}
else
{
LCD_Show_String(0,0,fail_show);
FailNum++;
if(FailNum==3)
{X=999;
while(X--)
{
beep=0;
Delay500us();
beep=1;
Delay500us();
}
FailNum=0;
}
Delay1000ms();
LCD_Clear();
LCD_Show_closeClock();
LCD_Show_String(0,0,show2);
}
LCD_Show_OneChar(14, 1, index+'0');
}
if(my_input=='+' && clockFlag==1)
{
clockFlag=0;
LCD_Clear();
Delay200ms();
index=0;
close();
LCD_Show_String(0,0,show2);
input_Pwd[0]='\0';
LCD_Show_OneChar(14, 1, index+'0');
}
if(my_input=='C')
{
LCD_Show_String(0,1,clearPwd);
Delay200ms();
index=0;
LCD_Show_OneChar(14, 1, index+'0');
}
}
else if(pageFlag==2)//页面3显示修改密码
{
if(clockFlag==1)
{
// LCD_Show_String(0,0,"ChangePassword!");
// Delay1000ms();
LCD_Show_String(0,0,"ChangeP");
LCD_Show_String(0,1,"RepeatP");
LCD_Show_OneChar(7, Flag, ':');
if('0'<=my_input && my_input<='9' && index<=7)
{
oneInput[index]=my_input;
LCD_Show_OneChar(index+8, Flag, oneInput[index]);
Delay200ms();
LCD_Show_OneChar(index+8, Flag, '*');
index++;
}
if(my_input=='<' && index!=0)
{
index--;
oneInput[index]='0';
LCD_Show_OneChar(index+8, Flag, ' ');
Delay200ms();
}
if(my_input=='=')
{
Delay200ms();
Flag++;
oneInput[index]='\0';
if(Flag==2)
{
if(strcmp(oneInput,twoInput)==0)
{
strcpy(PWD,oneInput);
LCD_Clear();
LCD_Show_String(0,0,"ChangeSuccess!");
Delay1000ms();
LCD_Clear();
}
else
{
LCD_Clear();
LCD_Show_String(0,0,"DifferentResults!");
Delay1000ms();
LCD_Clear();
}
}
strcpy(twoInput, oneInput);
index=0;
}
}
else
{
LCD_Show_String(0,0," NoAuthority!");
}
}
else if(pageFlag==3)//页面4计算器
{
if(('0'<=my_input && my_input<='9')||(my_input=='+' || my_input=='-' || my_input=='x' || my_input=='='))
{
JiSuan[index]=my_input;
LCD_Show_OneChar(index, 0, JiSuan[index]);
index++;
JiSuan[index]='\0';
Delay200ms();
if(my_input=='=')
{
ans=Jfuntion(JiSuan);
LCD_Show_OneChar(0, 1, ans+'0');
}
}
if(my_input=='C')
{
LCD_Clear();
Delay200ms();
index=0;
}
if(my_input=='<' && index!=0)
{
index--;
JiSuan[index]='0';
LCD_Show_OneChar(index, 0, ' ');
Delay200ms();
}
}
else if(pageFlag==4)//页面5显示动画
{
Show_Xin();
}
}
}
void LCD_Clear()
{
LCD_Show_String(0,0,clear);
LCD_Show_String(0,1,clear);
}
void LCD_Show_closeClock()
{
LCD_Show_Customer(15,0,0,close_Clock);
LCD_Show_Customer(15,1,1,guan);
}
void LCD_Show_openClock()
{
LCD_Show_Customer(15,0,0,open_Clock);
LCD_Show_Customer(15,1,1,kai);
}
void close()
{
LCD_Show_closeClock();
Motor_Num=256;
while(Motor_Num--)
{
Motor_Drive41(0,5);
}
MotorStop();
}
void openClock()
{
Motor_Num=256;
LCD_Show_openClock();
while(Motor_Num--)
{
Motor_Drive41(1,5);
}
MotorStop();
}
void LCD_Show_Time()
{
//显示年份
uchar time_ge,time_shi;
get_time();
time_ge=time_buf1[1]%10;
time_shi=time_buf1[1]/10;
LCD_Show_OneChar(3,0,'2');
LCD_Show_OneChar(4,0,'0');
LCD_Show_OneChar(5,0,time_shi+'0');
LCD_Show_OneChar(6,0,time_ge+'0');
//显示月份
time_ge=time_buf1[2]%10;
time_shi=time_buf1[2]/10;
LCD_Show_OneChar(8,0,time_shi+'0');
LCD_Show_OneChar(9,0,time_ge+'0');
//显示日
time_ge=time_buf1[3]%10;
time_shi=time_buf1[3]/10;
LCD_Show_OneChar(11,0,time_shi+'0');
LCD_Show_OneChar(12,0,time_ge+'0');
//显示时
time_ge=time_buf1[4]%10;
time_shi=time_buf1[4]/10;
LCD_Show_OneChar(4,1,time_shi+'0');
LCD_Show_OneChar(5,1,time_ge+'0');
//显示分
time_ge=time_buf1[5]%10;
time_shi=time_buf1[5]/10;
LCD_Show_OneChar(7,1,time_shi+'0');
LCD_Show_OneChar(8,1,time_ge+'0');
//显示秒
time_ge=time_buf1[6]%10;
time_shi=time_buf1[6]/10;
LCD_Show_OneChar(10,1,time_shi+'0');
LCD_Show_OneChar(11,1,time_ge+'0');
//显示 : 和锁
LCD_Show_Customer(15,0,0,close_Clock);
LCD_Show_OneChar(6,1,':');
LCD_Show_OneChar(9,1,':');
//显示星期
time_ge=time_buf1[7];
time_ge+=(time_ge==0)?1:0;
LCD_Show_OneChar(14,0,time_ge+'0');
}
void Show_Xin()
{
uchar i;
for(i=0;i<15;i+=2)
{
LCD_Show_Customer(i,0,0,myZi);
LCD_Show_Customer(i+1,0,1,xin1_1);
LCD_Show_Customer(i,1,1,xin1_1);
LCD_Show_Customer(i+1,1,0,myZi);
}
Delay500ms();
for(i=0;i<15;i+=2)
{
LCD_Show_Customer(i,0,0,myZi2);
LCD_Show_Customer(i+1,0,1,xin1_2);
LCD_Show_Customer(i,1,1,xin1_2);
LCD_Show_Customer(i+1,1,0,myZi2);
}
Delay500ms();
}
LCD1602.c
#include "LCD1602.h"
void LCD_Write_Com(uchar LCD_Com)
{
LCD_RS=0;//写命令
LCD_RW=0;//写操作
LCD_DATA=LCD_Com;//把数据放到数据线上
Delay1ms(1);//延时,LCD1602准备接收数据
LCD_EN=1;//EN拉高
LCD_EN=0;//EN拉低
}
void LCD_Write_Data(uchar LCD_Data)
{
LCD_RS=1;//写数据
LCD_RW=0;//写操作
LCD_DATA=LCD_Data;//把数据放到数据线上
Delay1ms(1);//延时,LCD1602准备接收数据
LCD_EN=1;//EN拉高
LCD_EN=0;//EN拉低
}
void LCD_Init()
{
//GPIO初始化
P2M1&=0Xe5;P2M0&=0Xe5;//1110 0101设置为准双向口
P0M1=0X00;P0M0=0X00;//设置为准双向口
LCD_EN=0;
LCD_RS=0;
Delay5ms();
LCD_Write_Com(0X38);//显示模式设置
LCD_Write_Com(0X0C);//开关显示,光标设置0000 1100 D=1:开显示 C=0:不显示光标 B=0:光标不闪烁
LCD_Write_Com(0X06);//光标设置 0000 0110 N=1 光标自动加1 S=0 整屏不移动
LCD_Write_Com(0X01);//清屏
Delay1ms(5);
}
void LCD_Show_OneChar(uchar X,uchar Y,uchar LCD_char)
{
X&=0X0F;
Y&=0X01;//限制X不能大于15,Y不能大于1
if(Y)
{
X=X+0X40;//当要显示的位置在第二行时,算出地址
}
X=X+0X80;//计算地址指令码
LCD_Write_Com(X);//发送命令
LCD_Write_Data(LCD_char);//发送显示的数据
}
void LCD_Show_String(uchar X,uchar Y,uchar *LCD_String)
{
uchar i;
for(i=0;LCD_String[i]!='\0';i++)
{
LCD_Show_OneChar(X,Y,LCD_String[i]);
X++;
}
}
/*显示自定义字符:本函数实现在CGRAM的0X00的地址中写入自定义字符,然后显示在XY坐标位置
LCD1602可定义的字符可存在CGROM的0X00-0X07共8个位置
X:列地址(0-15)
Y:行地址(0-1)
Num:自定义字符在CGROM中存储的位置(0-7)
LCD_String:自定义字符的取模;若用取模软件(阴码/行列式/顺向)
*/
void LCD_Show_Customer(uchar X,uchar Y,uchar Num,uchar *LCD_Cust)//显示自定义字符
{
uchar i;
uchar Com=Num;//用于计算CGRAM地址指令
X&=0X0F;
Y&=0X01;//限制X不能大于15,Y不能大于1
if(Y)
{
X=X+0X40;//当要显示的位置在第二行时,算出地址
}
X=X+0X80;//计算地址指令码
Com=Com<<3;
Com=Com+0X40;//计算指令码
for(i=0;i<8;i++)
{
LCD_Write_Com(Com);//设置存入数据的地址
Com++;
LCD_Write_Data(LCD_Cust[i]);//逐行填充每行的内容
}
LCD_Write_Com(X);//发送命令
LCD_Write_Data(Num);//发送显示的数据
}
LCD1602.h
#ifndef _LCD1602_H
#define _LCD1602_H
#define uchar unsigned char
#define uint unsigned int
#include <stc15.h>
#include "delay.h"
sbit LCD_EN=P2^1;
sbit LCD_RS=P2^4;
sbit LCD_RW=P2^3;
#define LCD_DATA P0
void LCD_Init();
void LCD_Show_OneChar(uchar X,uchar Y,uchar LCD_char);
void LCD_Show_String(uchar X,uchar Y,uchar *LCD_String);
void LCD_Show_Customer(uchar X,uchar Y,uchar Num,uchar *LCD_Cust);
#endif
iic.c
#include "iic.h"
//起始信号
void IIC_Start (void)
{
SDA =1;
SCL = 1;
Delay1us();
SDA = 0;
}
//终止信号
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
Delay1us();
SDA = 1;
Delay1us();
}
//等待应答
bit IIC_WaitAck(void)
{
bit i;
SCL = 1;
Delay1us();
i = SDA;
SCL = 0;
return i;
}
//应答位控制
void IIC_SendAck(bit j)
{
SCL = 0;
Delay1us();
SCL = 1;
Delay1us();
SDA = j;
Delay1us();
SCL = 0;
SDA = 1;
Delay1us();
}
//I2C发送1个字节数据
void IIC_SendByte(unsigned char dite)
{
unsigned char i;
SDA = 0;
SCL =0;
Delay1us();
for(i=0;i<8;i++)
{
if(dite &0x80) SDA = 1;
else SDA =0;
Delay1us();
dite <<=1;
SCL = 1;
Delay1us();
SCL = 0;
Delay1us();
}
}
//I2C接收1个字节数据
unsigned char IIC_RecByte(void)
{
unsigned char i,tmpe;
SCL = 0;
Delay1us();
for(i=0;i<8;i++)
{
SCL = 1;
Delay1us();
tmpe = tmpe<<1;
if(SDA) tmpe |=1;
SCL =0;
Delay1us();
}
return tmpe;
}
iic.h
#ifndef _IIC_H
#define _IIC_H
#include <stc15.h>
#include "delay.h"
//总线引脚定义
sbit SDA = P5^3; /* 数据线 */
sbit SCL = P5^2; /* 时钟线 */
void IIC_Start (void);//起始信号
void IIC_Stop(void);//终止信号
bit IIC_WaitAck(void);//等待应答
void IIC_SendAck(bit j);//应答位控制
void IIC_SendByte(unsigned char dite);//I2C发送1个字节数据
unsigned char IIC_RecByte(void);//I2C接收1个字节数据
#endif
stempmotor.c
#include "stepmotor.h"
//步进电机初始化
void StepMotor_Init()
{
P1M1 &= 0xF0; P1M0 |= 0x0F; //设置P1.0~P1.3为推挽输出
// P1M1 &= 0xF0; P1M0 &= 0xF0; //设置P1.0~P1.3为准双向
}
//电机停止
void MotorStop(void)
{
DD=0;CC=0;BB=0;AA=0;
}
//步进电机转动:单四拍 其中X=1表示正转,X=0表示反转;Speed表示转速设置
void Motor_Drive41(uchar X,uint Speed)
{
if(X==1) //顺时针转动
{
DD=0;CC=0;BB=0;AA=1;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=1;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=1;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=1;CC=0;BB=0;AA=0;
Delay1ms(Speed); //转速调节
}
else //逆时针转动
{
DD=1;CC=0;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=1;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=1;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=0;AA=1;
Delay1ms(Speed); //转速调节
}
}
//步进电机转动:双四拍 其中X=1表示正转,X=0表示反转;Speed表示转速设置
void Motor_Drive42(uchar X,uint Speed)
{
if(X==1) //顺时针转动
{
DD=0;CC=0;BB=1;AA=1;
Delay1ms(Speed); //转速调节
DD=0;CC=1;BB=1;AA=0;
Delay1ms(Speed); //转速调节
DD=1;CC=1;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=1;CC=0;BB=0;AA=1;
Delay1ms(Speed); //转速调节
}
else //逆时针转动
{
DD=1;CC=0;BB=0;AA=1;
Delay1ms(Speed); //转速调节
DD=1;CC=1;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=1;BB=1;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=1;AA=1;
Delay1ms(Speed); //转速调节
}
}
//步进电机转动:八拍 其中X=1表示正转,X=0表示反转;Speed表示转速设置
void Motor_Drive8(uchar X,uint Speed)
{
if(X==1) //顺时针转动
{
DD=0;CC=0;BB=0;AA=1;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=1;AA=1;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=1;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=1;BB=1;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=1;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=1;CC=1;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=1;CC=0;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=1;CC=0;BB=0;AA=1;
Delay1ms(Speed); //转速调节
}
else //逆时针转动
{
DD=1;CC=0;BB=0;AA=1;
Delay1ms(Speed); //转速调节
DD=1;CC=0;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=1;CC=1;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=1;BB=0;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=1;BB=1;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=1;AA=0;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=1;AA=1;
Delay1ms(Speed); //转速调节
DD=0;CC=0;BB=0;AA=1;
Delay1ms(Speed); //转速调节
}
}
stempmotor.h
#ifndef _STEPMOTOR_H
#define _STEPMOTOR_H
#include <stc15.h>
#include "delay.h"
#define uchar unsigned char
#define uint unsigned int
sbit AA=P1^0; //电机控制口,连接电机驱动板IN1
sbit BB=P1^1; //电机控制口,连接电机驱动板IN2
sbit CC=P1^2; //电机控制口,连接电机驱动板IN3
sbit DD=P1^3; //电机控制口,连接电机驱动板IN4
void StepMotor_Init();//步进电机初始化
void MotorStop(void);//电机停止
void Motor_Drive41(uchar X,uint Speed);//步进电机转动:单四拍 其中X=1表示正转,X=0表示反转;Speed表示转速设置
void Motor_Drive42(uchar X,uint Speed);//步进电机转动:双四拍 其中X=1表示正转,X=0表示反转;Speed表示转速设置
void Motor_Drive8(uchar X,uint Speed);//步进电机转动:八拍 其中X=1表示正转,X=0表示反转;Speed表示转速设置
#endif
PCF8563.c
#include "PCF8563.h"
unsigned char time_buf1[8]={20,23,5,31,21,11,0,3};//空年月日时分秒星期(10进制)
unsigned char time_buf[8]; //空年月日时分秒星期 (16进制)
//使用封装好的I2C函数,进行函数PCF8563的写函数封装:向地址Adddrsend中写入数据Datasend
//函数编写流程为 :start->发送设备地址->等待ACK->发送需要被写的内存地址->等待ACK->发送数据写入E2PROM->等待ACK->STOP
void PCF8563_WriteOneByte(unsigned char Adddrsend, unsigned char Datasend)
{
IIC_Start();
IIC_SendByte(0xA2);//通过I2C总线发送数据(芯片指令)写操作
IIC_WaitAck();
IIC_SendByte(Adddrsend);
IIC_WaitAck();
IIC_SendByte(Datasend);
IIC_WaitAck();
IIC_Stop();
Delay1ms(10);
}
//使用封装好的I2C函数,进行函数PCF8563的读数据函数封装:从Adddrsend中读出数据,作为返回值
//读函数编写流程:start->发送设备地址->等待ACK->发送需要被读的内存地址->等待ACK->发送读指令(设备地址)->等待ACK-->读内存数据->等待no ACK->STOP
unsigned char PCF8563_ReadOneByte(unsigned char Adddrsend)
{
unsigned char Rec;
IIC_Start();
IIC_SendByte(0xA2);//通过I2C总线发送数据(芯片指令)写操作
IIC_WaitAck();
IIC_SendByte(Adddrsend);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xA3);
IIC_WaitAck();
Rec=IIC_RecByte();
IIC_Stop();
return Rec;
}
/******************BCD转十进制***************************/
unsigned char bcd_dec(unsigned char bat)
{
unsigned char temp1,temp2,tol;
temp1=bat&0x0f;
temp2=(bat&0xf0)>>4;
tol=temp2*10+temp1;
return tol;
}
/******************十进制转BCD***************************/
unsigned char dec_bcd(unsigned char bat)
{
return ((bat%10) & 0x0F) | (((bat/10) << 4) & 0xF0);;
}
//获取当前时间并转化
void get_time(void)
{
time_buf[6]=0x7f&PCF8563_ReadOneByte(0x02); //读取秒
time_buf[5]=0x7f&PCF8563_ReadOneByte(0x03); //读取分钟
time_buf[4]=0x3f&PCF8563_ReadOneByte(0x04); //读取小时
time_buf[3]=0x3f&PCF8563_ReadOneByte(0x05); //读取天数
time_buf[2]=0x1f&PCF8563_ReadOneByte(0x07); //读取月
time_buf[1]=0xff&PCF8563_ReadOneByte(0x08); //读取年
time_buf[7]=0x07&PCF8563_ReadOneByte(0x06); //读取星期
time_buf1[6]=bcd_dec(time_buf[6]); //将读取的BCD码转换成十进制以便运算,秒
time_buf1[5]=bcd_dec(time_buf[5]); //将读取的BCD码转换成十进制以便运算,分
time_buf1[4]=bcd_dec(time_buf[4]); //将读取的BCD码转换成十进制以便运算,小时
time_buf1[3]=bcd_dec(time_buf[3]); //将读取的BCD码转换成十进制以便运算,日
time_buf1[2]=bcd_dec(time_buf[2]); //将读取的BCD码转换成十进制以便运算,月
time_buf1[1]=bcd_dec(time_buf[1]); //将读取的BCD码转换成十进制以便运算,年
time_buf1[7]=bcd_dec(time_buf[7]); //将读取的BCD码转换成十进制以便运算,星期
//printf("20%d年%d月%d日%d时%d分%d秒\r\n",date.year1,date.moom1,date.dat1,date.hour1,date.min1,date.sec1);
}
//初始化当前时间
void time_init()
{
//将十进制数转化为BCD值,方便写入PCF8563
time_buf[1] = dec_bcd(time_buf1[1]);
time_buf[2] = dec_bcd(time_buf1[2]);
time_buf[3] = dec_bcd(time_buf1[3]);
time_buf[4] = dec_bcd(time_buf1[4]);
time_buf[5] = dec_bcd(time_buf1[5]);
time_buf[6] = dec_bcd(time_buf1[6]);
time_buf[7] = dec_bcd(time_buf1[7]);
PCF8563_WriteOneByte(0x02,time_buf[6]); //写入秒
PCF8563_WriteOneByte(0x03,time_buf[5]); //写入分
PCF8563_WriteOneByte(0x04,time_buf[4]); //写入小时
PCF8563_WriteOneByte(0x05,time_buf[3]); //写入日
PCF8563_WriteOneByte(0x07,time_buf[2]); //写入月
PCF8563_WriteOneByte(0x08,time_buf[1]); //写入年
PCF8563_WriteOneByte(0x06,time_buf[7]); //写入星期
}
PCF8563.h
#ifndef _PCF8563_H
#define _PCF8563_H
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int
//typedef struct {
// uint16_t year;
// uint8_t mon;
// uint8_t day;
// uint8_t hour;
// uint8_t min;
// uint8_t sec;
// uint8_t week;
//}sTime;
void PCF8563_WriteOneByte(unsigned char Adddrsend, unsigned char Datasend);
unsigned char PCF8563_ReadOneByte(unsigned char Adddrsend);
unsigned char bcd_dec(unsigned char bat);
unsigned char dec_bcd(unsigned char bat);
void time_init();//初始化当前时间
void get_time(void);//读取当前时间
#endif
Key16.c
#include "Key16.h"
uchar KeyScan_4x4(void)
{
uchar X_temp,Y_temp,temp;
X_temp=0XF0;//列值赋初值
Y_temp=0X0F;//行值赋初值
P2M1&=0X3F;P2M0|=0XC0;//设置P2.6-P2.7为强推挽输出 0011 1111;1100 0000
P4M1&=0X0F;P4M0|=0XF0;//设置P4.4-P4.7为强推挽输出 0000 1111;1111 0000
P5M1&=0XF3;P5M0|=0X0C;//设置P5.2-P5.3为强推挽输出 1111 0011;0000 1100
ROW1=1;ROW2=1;ROW3=1;ROW4=1;//行置高
COL1=0;COL2=0;COL3=0;COL4=0;//列置低
//所用到行IO口配置为输入,进行检测
Delay1ms(10);
P4M1&=0X0F;P4M0&=0X0F;//设置P4.4-P4.7为准双向口
Delay1ms(10);
if(ROW1==0)//检测行1电平是否为低电平
{
Delay1ms(10);
if(ROW1==0)
Y_temp&=0X0E;
}
if(ROW2==0)//检测行2电平是否为低电平
{
Delay1ms(10);
if(ROW2==0)
Y_temp&=0X0D;
}
if(ROW3==0)//检测行3电平是否为低电平
{
Delay1ms(10);
if(ROW3==0)
Y_temp&=0X0B;
}
if(ROW4==0)//检测行4电平是否为低电平
{
Delay1ms(10);
if(ROW4==0)
Y_temp&=0X07;
}
P2M1&=0X3F;P2M0|=0XC0;//设置P2.6-P2.7为强推挽输出 0011 1111;1100 0000
P4M1&=0X0F;P4M0|=0XF0;//设置P4.4-P4.7为强推挽输出 0000 1111;1111 0000
P5M1&=0XF3;P5M0|=0X0C;//设置P5.2-P5.3为强推挽输出 1111 0011;0000 1100
ROW1=0;ROW2=0;ROW3=0;ROW4=0;//行置低
COL1=1;COL2=1;COL3=1;COL4=1;//列置高
Delay1ms(10);
P2M1&=0X3F;P2M0&=0X3F;//设置P2.6-P2.7为准双向口
P5M1&=0XF3;P5M0&=0XF3;//设置P5.2-P5.3为准双向口
Delay1ms(10);
if(COL1==0)//检测列1电平是否为低电平
{
Delay1ms(10);
if(COL1==0)
X_temp&=0XE0;
}
if(COL2==0)//检测列2电平是否为低电平
{
Delay1ms(10);
if(COL2==0)
X_temp&=0XD0;
}
if(COL3==0)//检测列3电平是否为低电平
{
Delay1ms(10);
if(COL3==0)
X_temp&=0XB0;
}
if(COL4==0)//检测列4电平是否为低电平
{
Delay1ms(10);
if(COL4==0)
X_temp&=0X70;
}
//将行值和列值合并,得到按键对应的编码值,该值与16个按键一一对应
temp=X_temp|Y_temp;
temp=~temp;
//将按键检测的原始编码值解析对应按键值信息
switch(temp)//颠倒键值
{
case 0X11:return '/';//1
case 0X21:return 'x';//2
case 0X41:return '-';//3
case 0X81:return '+';//4
case 0X12:return '=';//5
case 0X22:return '9';//6
case 0X42:return '8';//7
case 0X82:return '7';//8
case 0X14:return 'C';//9
case 0X24:return '6';//0
case 0X44:return '5';//a
case 0X84:return '4';//b
case 0X18:return '<';//c
case 0X28:return '3';//d
case 0X48:return '2';//e
case 0X88:return '1';//f
default:return 0;
}
}
Key16.h
#ifndef _KEY_4X4_H
#define _KEY_4X4_H
#include <stc15.h>
#include "delay.h"
#define uchar unsigned char
#define uint unsigned int
/*
矩阵按键引脚定义*/
sbit COL4=P5^2; //4*4矩阵检测列检测端口
sbit COL3=P5^3; //4*4矩阵检测列检测端口
sbit COL2=P2^6; //4*4矩阵检测列检测端口
sbit COL1=P2^7; //4*4矩阵检测列检测端口
sbit ROW4=P4^4; //4*4矩阵检测行检测端口
sbit ROW3=P4^5; //4*4矩阵检测行检测端口
sbit ROW2=P4^6; //4*4矩阵检测行检测端口
sbit ROW1=P4^7; //4*4矩阵检测行检测端口
uchar KeyScan_4x4(void);
#endif
zimo.h
#ifndef _ZIMO_H
#define _ZIMO_H
#define uchar unsigned char
#define uint unsigned int
uchar code close_Clock[]={0x0E,0x0A,0x0A,0x0A,0x1F,0x11,0x11,0x1F};//??
uchar code guan[] = {0x11,0x0A,0x1F,0x0A,0x1F,0x0A,0x1B,0x00};
uchar code kai[] = {0x1F,0x0A,0x0A,0x1F,0x0A,0x0A,0x0A,0x00};
uchar code open_Clock[]={0x0E,0x02,0x02,0x02,0x1F,0x11,0x11,0x1F};//???
uchar code myZi[] = {0x00,0x00,0x0A,0x15,0x11,0x0A,0x04,0x00};
uchar code myZi2[] = {0x00,0x0A,0x15,0x15,0x11,0x0A,0x04,0x00};
uchar code xin1_2[] = {0x00,0x0A,0x1F,0x1F,0x1F,0x0E,0x04,0x00};
uchar code xin1_1[] = {0x00,0x00,0x0A,0x1F,0x1F,0x0E,0x04,0x00};
#endif