数字密码锁课程设计报告

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

嵌入式系统课程设计报告
数字密码锁
摘要
电子数字密码锁是一种通过密码输入来控制电路或是芯片工作,从而控制机械开关的闭合,我们采取的是单片机,它具有超大规模集成电路技术,有极强的数据处理功能,I/O口多。

以它为核心设计的密码锁,结构小,功能强,现在很多单位甚至家里的各个家用电器,还有保险箱都需要它。

目录
1设计内容及要求 (3)
2系统的设计 (3)
2.1系统设计结构图 (3)
2.2系统的工作原理说明 (4)
3系统硬件设计 (4)
3.1使用到的元器件列表 (5)
3.2系统各模块简介 (5)
4电路程序设计 (6)
4.1软件总设计流程图 (6)
4.2各模块具体实现 (7)
附录1设计总体电路图 (12)
附录2数字密码锁源程序 (13)
1设计内容及要求
1、任务
设计一多位电子密码锁
2、要求
1)设计一多位电子密码锁,输入密码用“F”表示,输入密码正确,绿灯亮(或显示其他标志、蜂鸣器替代),输入密码错误,红灯亮(或显示其他标志、蜂鸣器替代)
2)具有确定键和取消键,在未确定之前可以取消,重新输入
3)连续输入三次错误密码,红灯闪烁,报警电路动作,键盘锁定
4)具有密码重置功能
5)具有等待操作时间限制功能,超过限定时间报警
6)显示北京时间
2系统的设计
2.1系统设计结构图
如下图所示,本设计的真题原理框图如下所示:
图1 硬件系统的总体结构图
2.2系统的工作原理说明
本系统采用ADuc848单片机为核心的系统,加以4×4矩阵键盘、LED、蜂鸣器等。

矩阵键盘分别为0、1、2、3、4、5、6、7、8、9、Enter、Change、Conform、delete。

系统开始显示北京时间,按Enter后提示输入密码lcd显示“Enterplease”;输入密码过程中每输入一个密码屏幕上显示一个“*”,当密码输入完毕按下“confirm”键时,若输入密码与设定的密码相同,即密码正确,液晶屏显示为“OK!”提示锁打开,同时蜂鸣器响;若密码不正确,LED显示电路显示提示“wrong”,蜂鸣器响,若连续3次输入不正确,则发出警报声同时锁定键盘。

若在输入过程中发现输入错误的数字,可以通过“delete”键删除输入的数字后重新输入。

若需要修改预先设定的密码,可以先输入一次正确的密码,然后按下“change”键
Lcd显示“change number”,输入完新密码后,按确认键,密码修改完成。

为了防止恶意尝试,若连续输入3次密码输入错误则键盘被锁定不能再进行输入操作并发出报警声。

3系统硬件设计
如图1所示,本系统的硬件部分主要由单片机ADuc848、4×4矩阵键盘、LCD1602、报警电路和驱动电路组成;其中报警电路使用蜂鸣器。

总的来说,数字密码锁主要由微处理器模块、键盘模块、声光提示模块和显示模块构成。

3.1使用到的元器件列表
元器件规格/型号数量
单片机 ADuc848 1
三极管 8550 1
稳压管 7805 1
液晶显示器 LCD1602 1
晶振 12M 1
电阻 10K/1K/100 4/6/1
排阻 10K 1
电容 104/30Pf4.7uF 3/2/1
蜂鸣器 1
时钟芯片 1
表1 元器件列表
3.2 系统各模块简介
1.微处理器模块,也就是ADuc848单片机,因为本系统要实现密码检测、密码设定、声光提示等功能,要求微处理器必须能提供很多I/O口,而且由于系统体积限制,很难扩展I/O口和使用外部程序存储器,所以选用ADuc848单片机。

2.声光提示模块,由发光二极管LED和蜂鸣器组成,由单片机控制。

发光二极管LED有绿色和红色两种,绿色LED亮表示密码输入正确,驱动开锁电路;相反,红色LED亮就表示输入密码错误。

蜂鸣器采用5V驱动蜂鸣器,作为报警电路。

当输入密码错误次数超过3次后就发出声音警报。

3.显示模块,考虑到友好的人机界面,采用LCD1602液晶显示。

显示模块的作用主要是显示提示信息和输入的密码,以方便用户使用。

4.键盘模块,键盘模块的作用是让用户输入密码和修改密码。

考虑到本系统
需要用到大量的按键,键盘模块采用4×4的16矩阵键盘模式。

4软件程序设计
4.1软件总设计流程图
软件总设计流程图如图12所示。

图12 软件设计流程图
4.2 具体功能软件实现
4.2.1 4×4矩阵键盘扫描程序
当键盘中按键数量较多时,为了减少对I/O口的占用,通常将按键排列成矩阵形式,也称为行列键盘,这是一种常见的连接方式。

矩阵式键盘接口见图13所示,它由行线和列线组成,按键位于行、列的交叉点上。

当键被按下时,其交点的行线和列线接通,相应的行线或列线上的电平发生变化,MCU通过检测行或列线上的电平变化可以确定哪个按键被按下。

图13 4×4矩阵键盘
图13为一个4×4行列结构,可以构成16个键的键盘。

很明显,在按键数量多的场合,矩阵键盘与独立式按键键盘相比可以节省很多的I/O口线。

矩阵键盘不仅在连接上比单独式按键复杂,它的按键识别方法也比单独式按键复杂。

在矩阵键盘的软件接口程序中,常使用的按键识别方法有行扫描法和线反转法。

这两种方法的基本思路是采用循环查循的方法,反复查询按键的状态,因此会大量占用MCU的时间,所以较好的方式是采用状态机的方法来设计,尽量减少键盘查询过程对MCU的占用时间。

图13中,lie0、lie1、lie2、lie3、为4根列线工作于输入方式hang0、hang1、hang2、hang3为4根行线,工作于输出方式,由MCU(扫描)控制其输出的电平值。

行扫描法也称为逐行扫描查询法,其按键识别的过程如下:
(1)将全部行线lie0-lie3置低电平输出,然后读hang0-hang3四根输入列线中有无低电平出现。

只要有低电平出现,则说明有键按下(实际编程时,还要考虑按键的消抖)。

如读到的都是高电平,则表示无键按下。

(2)在确认有键按下后,需要进入确定具体哪一个键闭合的过程。

其思路是:依次将行线置为低电平,并检测列线的输入(扫描),进而确认具体的按键位置。

如当hang0输出低电平时,测到lie2的输入为低电平,则可确认按键S3处于闭合状态。

通过以上分析可以看出,MCU对矩阵键盘的按键识别,是采用扫描方式控制行线的输出和检测列线输入的信号相配合实现的。

(3)矩阵按键的识别仅仅是确认和定位了行和列的交叉点上的按键,接下来还要考虑键盘的编码,即对各个按键进行编号。

在软件中常通过计算的方法或查表的方法对按键进行具体的定义和编号
4x4矩阵键盘扫描函数见附件源程序
4.2.2 显示程序
本系统使用LCD1602实现显示,只要参照LCD1602的使用手册进行初始化和程序编写就可以显示,即在程序编写中添加LCD1602的驱动程序。

这里的驱动程序主要包括:初始化函数、设置显示坐标、写字符函数及写字符串函数。

在时钟界面时显示时间的运行,在密码锁界面时主要显示提示信息和输入的密码,当然,当输入密码数字时,输出不是显示数字,而是用“*”显示代替。

LCD1602的部分读写控制时序程序如下所示:
当系统开始后,LCD1602初始化,然后显示时钟界面,程序在T0中断,进入时钟运行子程序,其流程图如图14所示。

图14 时钟运行流程图
当输入密码后,调用AT24C02中的密码进行比较,若密码一致,就驱动开锁电路,即绿色发光二极管LED亮,若不一致,红色发光二极管LED亮,如果超过3次输入的密码不正确,此时报警电路就会响应,蜂鸣器响,以及锁住系统。

其程序流程图如图18所示。

图18 密码比较流程图
4.2.5 密码修改子程序
修改密码时,先输入旧密码,如果输入的密码正确,再输入新密码,否则返回;输入新密码后要求再次输入新密码,当两次输入的新密码一致时,然后存储到AT24C02中,否则重新输入新密码。

修改密码时,如果连续三次输入的旧密码都不正确,报警电路响应。

其程序流程图如图19所示。

图19 密码修改流程图
附录1 设计总体电路图
附录2数字密码锁源程序
#include<aduc848.h>
#include<time.h>
#define uint unsigned int
#define uchar unsigned char
#define No_key 20 //无按键时的返回值
#define lcddata P0 //lcd1602的数据输入端口sbit lcden= P3^3;
sbit lcdrs= P3^6;
sbit lcdrw= P3^5;
sbit light= P3^0;
sbit light1= P3^2;
uchar i;//用来统计输入密码错误次数
uchar j ; //用来统计输入个数的全局变量uchar k;//用来统计改密码时输入的个数
uchar aa; //用来在定时器中计数的全局变量uchar code table1[]=" OK!" ;
uchar code table2[]="Enter please:" ; uchar code table3[]="wrong!";
uchar code table4[]="Newpassword:";
uchar code key_table[16] =
{
0,1,2,3,
4,5,6,7,
8,9,10,11,
12,13,14,15
};
uchar password[]={1,2,3,4,5,6} ; //设定初始密码
uchar CurrentTime[7]={40,40,21,6,23,4,11};//初始时间
uchar save[6]; //保存输入的数据
uchar conflag ; //确认标志
uchar lockflag; //锁键盘标志
uchar startflag; //开始标志
uchar changeflag;//改键标志位
uchar timeflag;//时钟标志
void delay(uint z); //延时子函数
void wright_com(uchar com); //写指令函数
void wright_data(uchar date) ; //写数据函数
void init(); //初始化
void display_OK(); // 显示OK
void delete(); //删除输入的最后一个数
void display_wrong();//显示wrong;
uchar keyscan() ; //带返回值的键盘扫描程序
void enter_code(uchar t); //输入密码函数,把输入的数据存入数组中并在屏幕上显示相应的东西
void change_code(uchar t); // 改变密码的函数,把输入的数据存到password中
void confirm(); //确认密码对不对,把输入的数据与密码逐一对比,完全一样刚正确
void succeed_an(); //输入密码成功时的响应
void fail_an(); //输入密码失败时的响应
void lockkey(); //锁键盘三秒
void reset(); //复位函数
void display_enter(); //显示输入
void alarm() ;//密码成功声音
void xianshi();//显示时间
void xiemaohao();//显示时间中的斜杠
void main(void)
{
uchar temp;
init();
PLLCON&=0xf8;//设置频率为12.58MHz
I2CCON=0xE8;//配置IIC为软件主发送模式必须
SetTime(CurrentTime);
SwitchRTC(1);
while(1)
{
if(lockflag)
{
temp=keyscan(); // 锁键期间也要进行键盘扫描
if(temp!=No_key) //重新记时三秒
{
aa=0; //重新在定时器中计数
}
}
else
{
temp=keyscan(); //反复扫描输入,等待随时输入
if(temp!=No_key) //有按键按下才进行下面的操作
{
if(changeflag&&k<6)
change_code(temp);
else
{
if(temp==10)
{
wright_com(0x01);
startflag=~startflag; //开始标志置位
if(startflag)
reset();
}
if(startflag)
{
enter_code(temp); //每扫描一次键盘就要进行一次处理,保存输入的数值
if(temp==13) //按下确认键盘就要进行密码确认
{
confirm(); //进行确认判断
if(conflag) //密码确认为正确
{
succeed_an(); //密码正确,作出相应的反应
}
else
{
fail_an(); //密码错误,作相应反应 }
}
if(temp==12&&conflag==1)
{ alarm();
changeflag=1;
k=0;
}
if(temp==14)
{
delete(); //作删除操作
}
}
else
{ //wright_com(0x01) ;
ReadTime(CurrentTime) ;
xianshi();
xiemaohao(); //写冒号
}
}
}
}
}
}
/****** 显示enter********/
void display_enter()
{
uchar num;
//wright_com(0x01);
wright_com(0x80+0x40);
for(num=0;num<16;num++)
wright_data(' ');
wright_com(0x80);
for(num=0;num<13;num++)
{
wright_data(table2[num]);
}
}
/****** 显示OK********/
void display_OK()
{
uchar num;
wright_com(0x01);
wright_com(0x80);
for(num=0;num<16;num++)
wright_data(' ');
//wright_com(0x80+0x40);
//for(num=0;num<16;num++)
//wright_data(' ');
//wright_com(0x80);
wright_com(0x80);
for(num=0;num<4;num++)
{
wright_data(table1[num]);
}
}
/****** 显示wrong********/
void display_wrong()
{ uchar num;
wright_com(0x01);
wright_com(0x80+0x40);
for(num=0;num<15;num++)
wright_data(' ');
wright_com(0x80);
for(num=0;num<6;num++)
{
wright_data(table3[num]);
}
wright_com(0x80+15) ;
wright_data(i+49);
}
/****** 删除最后一个********/
void delete()
{
wright_com(0x80+0x40+j-1); //确定删除对象
wright_data(' '); //显示空格即为删除
save[--j]=0; //删除后数据清零
wright_com(0x80+0x40+j); //为下次输入数据时写好位置,必须是在最后一个后面
}
/****** 对各种变量进行复位********/
void reset()
{
uchar num;
display_enter();
wright_com(0x80+0x40); //擦除屏幕上的显示
for(num=0;num<6;num++)
{
save[num]=0; //对输入的数值进行清零
wright_data(' '); //显示的是空格
}
wright_com(0x80+0x40); //下次再输入时可以又从起始位置输入conflag=0;
j=0;
}
/****** 输入密码正确进行响应********/
void succeed_an()
{
display_OK(); //显示成功
alarm();
}
/****** 输入密码错误进行响应********/
void fail_an()
{ if(i>=2)
{ lockkey();
display_wrong();
alarm();
}
else
{
wright_com(0x80+15) ;
wright_data(i+48);
display_wrong();
alarm();
i++ ;
}
}
/******锁键盘三秒************/
void lockkey()
{
lockflag=1;
}
/******改变密码并在屏幕上显示出来******/
void change_code(uchar t)
{ uchar num;
if(t>=0&&t<10)
{
password[k]=t; //保存输入的数据
if(k==0)
{
for(num=0;num<12;num++)
{wright_com(0x80+num);
wright_data(table4[num]);
}
wright_com(0x80+0x40) ; //第一输入时要先写入地址指令,否则无法显示
wright_data(password[k]+48) ;
}
else
{
wright_data(password[k]+48);//不是第一个输入则不用再写地址
}
k++;
}
}
/******输入密码并在屏幕上显示星号******/
void enter_code(uchar t)
{
if(t>=0&&t<10)
{
if(j==0)
{
wright_com(0x80+0x40) ; //第一输入时要先写入地址指令,否则无法显示
wright_data('*') ;
}
else
{
wright_data('*') ;//不是第一个输入则不用再写地址
}
save[j++]=t; //保存输入的数据
}
}
/******校对密码以确定是不是正确的**********/
void confirm()
{
uchar k;
for(k=0;k<6;k++)
{
if(password[k]!=save[k]) //对数组中的内容进行逐一比较,一旦有数据不对马上退出循环
{
break;
}
}
if(k==6) //要是条件退出的话说明六个数全对密码
{
conflag=1; // 进行标志密码正确
}
}
/******中断服务程序**********/
void timer0(void) interrupt 1
{
TR0=0;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256; //重装初值
if(lockflag)
{
aa++;
if(aa>=100) //三秒到了
{
aa=0; //清零可以方便下次再使用
lockflag=0; //标志清零解除键锁,方便下次使用
}
}
TR0=1;
}
/******初始化***********/
void init()
{
/*****定时器初始化****/
TMOD=1;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
ET0=1;
EA=1; //开启总中断
TR0=1;//把定时器关闭
/****1602初始化******/
lcdrw=0; //这个必须要置零,否则无法正常显示
lcden=0;
wright_com(0x38) ; //初始化
wright_com(0x0c) ; //打开光标 0x0c不显示光标 0x0e光标不闪,0x0f 光标闪
wright_com(0x01) ; //清显示
wright_com(0x80) ;
}
/******1602写入指令************/
void wright_com(uchar com)
{
lcdrs=0;
lcddata=com;
delay(1);
lcden=1;
delay(1);
lcden=0;
}
/******1602写入数据***********/
void wright_data(uchar date)
{
lcdrs=1;
lcddata=date;
delay(1);
lcden=1;
delay(1);
lcden=0;
}
/******延时函数************/
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--) ;
}
/**********4x4矩阵键盘扫描函数*********/
uchar keyscan()
{
static bit keyflag=0; //keyflag定义为静态变量这样的话main中的每个while循环就不会让keyflag重新赋0.
unsigned char temp,jianzhi=0xff;
P1&=0xf0;
P2&=0xf0;
temp=P1&0x0f;
if(keyflag==0)
{
if(temp!=0x0f)
{
delay(10);
if(temp==(P1&0x0f))
{
P2|=0x0e;
switch(P1&0x0f)
{
case 0x0e:jianzhi=3;break;
case 0x0d:jianzhi=7;break;
case 0x0b:jianzhi=11;break;
case 0x07:jianzhi=15;break;
case 0x0f:break;
default:jianzhi= 0x20;break;
}
P2&=0xf0;
P2|=0x0d;
switch(P1&0x0f)
{
case 0x0e:jianzhi= 2;break;
case 0x0d:jianzhi= 6;break;
case 0x0b:jianzhi= 10;break;
case 0x07:jianzhi= 14;break;
case 0x0f:break;
default:jianzhi= 0x20;break;
}
P2&=0xf0;
P2|=0x0b;
switch(P1&0x0f)
{
case 0x0e:jianzhi= 1;break;
case 0x0d:jianzhi= 5;break;
case 0x0b:jianzhi= 9;break;
case 0x07:jianzhi= 13;break;
case 0x0f:break;
default:jianzhi= 0x20;break;
}
P2&=0xf0;
P2|=0x07;
switch(P1&0x0f)
{
case 0x0e:jianzhi= 0;break;
case 0x0d:jianzhi= 4;break;
case 0x0b:jianzhi= 8;break;
case 0x07:jianzhi= 12;break;
case 0x0f:break;
default:jianzhi= 0x20;break;
}
keyflag=1;
}
}
}
if(keyflag==1)
{
if(temp==0x0f) //只有在按键松开的时间足够长的时候才会从新开始读键值,即让keyflag为0。

{
delay(1000);
if(temp==0x0f)
keyflag=0;
}
}
return jianzhi;
}
/*******密码正确的声音********/
void alarm()
{ unsigned int b;
PWM0H=33;PWM1L=66;PWMCON=0x21; //配置pwm模块工作在方式2,选择频率为32.768khz
for(b=0;b<=30000;b++) ; //响声延时
PWM0H=12;PWM1L=70;PWMCON=0x21; //配置pwm模块工作在方式2,选择频率为32.768khz
for(b=0;b<=30000;b++) ;
PWMCON=0x01; //关响声
}
/*******写冒号********/
void xiemaohao() //写冒号
{
wright_com(0x82); //冒号
wright_data(0x3a);
wright_com(0x85); //冒号
wright_data(0x3a);
wright_com(0xc4); //写/线
wright_data(0x2f);
wright_com(0xc7); //写/线
wright_data(0x2f);
wright_com(0xca); //写,线
wright_data(0x2f);
}
/*******显示时间********/
void xianshi()
{ wright_com(0x80); //写时
wright_data(CurrentTime[2]/10+48);
wright_data(CurrentTime[2]%10+48);
wright_com(0x83); //写分
wright_data(CurrentTime[1]/10+48);
wright_data(CurrentTime[1]%10+48);
wright_com(0x86); //写秒
wright_data(CurrentTime[0]/10+48);
wright_data(CurrentTime[0]%10+48);
wright_com(0xc0); //写年高
wright_data(0x32);
wright_data(0x30);
wright_data(CurrentTime[6]/10+48);
wright_data(CurrentTime[6]%10+48);
wright_com(0xc5); //写月
wright_data(CurrentTime[5]/10+48);
wright_data(CurrentTime[5]%10+48);
wright_com(0xc8); //写日
wright_data(CurrentTime[4]/10+48);
wright_data(CurrentTime[4]%10+48);
wright_com(0xcb); //周几
wright_data(CurrentTime[3]%10+48);
}
时钟函数程序
void iic_start(void);
void iic_stop(void);
void iic_ack(void);
bit read_ack(void);
void iic_nack();
unsigned char get_byte(void);
void out_byte(unsigned char dd);
void IIC_Delay_us(unsigned int times);
void ReadTime(unsigned char TIME[7]); //读时间值
void SetTime(unsigned char TIME[7]); //设置时间初值
void SwitchRTC(unsigned char SWITCH); //时间开始走动
void ReadTime(unsigned char TIME[7]) //返回的是十进制的数值时间{
bit EATemp;
unsigned char temp;
EATemp=EA;
iic_start(); //开总线
out_byte(0xd0); //发地址
read_ack();
out_byte(0x00); //发秒地址
read_ack();
iic_stop(); //停总线
IIC_Delay_us(1);
iic_start();
out_byte(0xd1);
read_ack();
TIME[0]=get_byte();
iic_ack();
TIME[1]=get_byte();
iic_ack();
TIME[2]=get_byte();
iic_ack();
TIME[3]=get_byte();
iic_ack();
TIME[4]=get_byte();
iic_ack();
TIME[5]=get_byte();
iic_ack();
TIME[6]=get_byte();
iic_nack();
iic_stop();
IIC_Delay_us(1);
TIME[0]=((TIME[0]&0x7f)>>4)*10+(TIME[0]&0x0f); //second
TIME[1]=((TIME[1]&0x7f)>>4)*10+(TIME[1]&0x0f); //minute
//******************************************************************* *
if(TIME[2]&0x40) //12小时还是24小时制,d6=1表示12小时制
{
if(TIME[2]&0x20)temp=0x80;else temp=0x40; //12小时制
TIME[2]=((TIME[2]&0x1f)>>4)*10+(TIME[2]&0x0f); //hour
TIME[2]|=temp;
}
else
{
TIME[2]=((TIME[2]&0x3f)>>4)*10+(TIME[2]&0x0f); //24小时制 }
//******************************************************************* **
TIME[3]=TIME[3]&0x07; //week
TIME[4]=((TIME[4]&0x3f)>>4)*10+(TIME[4]&0x0f); //date
TIME[5]=((TIME[5]&0x1f)>>4)*10+(TIME[5]&0x0f); //month
TIME[6]=(TIME[6]>>4)*10+(TIME[6]&0x0f); //year
EA=EATemp;
}
//**************************************************放置时间初值
void SetTime(unsigned char TIME[7])
{
bit EATemp;
unsigned char temp=0;
unsigned char TimeTemp[7];
EATemp=EA;
for(temp=0;temp<7;temp++)TimeTemp[temp]=TIME[temp];
temp=0;
TimeTemp[6]=((TimeTemp[6]/10)<<4)+(TimeTemp[6]%10);
TimeTemp[5]=((TimeTemp[5]/10)<<4)+(TimeTemp[5]%10);
TimeTemp[4]=((TimeTemp[4]/10)<<4)+(TimeTemp[4]%10);
TimeTemp[3]=((TimeTemp[3]/10)<<4)+(TimeTemp[3]%10);
if((TimeTemp[2]&0xc0)==0x00)
{
TimeTemp[2]=((TimeTemp[2]/10)<<4)+(TimeTemp[2]%10); }
else
{
if((TimeTemp[2]&0xc0)==0x01)temp=0x40;else temp=0x60; TimeTemp[2]&=0x3f;
TimeTemp[2]=((TimeTemp[2]/10)<<4)+(TimeTemp[2]%10); TimeTemp[2]|=temp;
}
TimeTemp[1]=((TimeTemp[1]/10)<<4)+(TimeTemp[1]%10); TimeTemp[0]=((TimeTemp[0]/10)<<4)+(TimeTemp[0]%10);
TimeTemp[0]&=0x7f;
iic_start();
out_byte(0xd0);
read_ack();
out_byte(0x00);
read_ack();
out_byte(TimeTemp[0]);
read_ack();
out_byte(TimeTemp[1]);
read_ack();
out_byte(TimeTemp[2]);
read_ack();
out_byte(TimeTemp[3]);
read_ack();
out_byte(TimeTemp[4]);
read_ack();
out_byte(TimeTemp[5]);
read_ack();
out_byte(TimeTemp[6]);
read_ack();
iic_stop();
IIC_Delay_us(1);
EA=EATemp;
}
void SwitchRTC(unsigned char SWITCH)
{
unsigned char temp;
bit EATemp;
EATemp=EA;
iic_start();
out_byte(0xd0);
read_ack();
out_byte(0x00);
read_ack();
iic_stop();
//IIC_Delay_us(1);
iic_start();
out_byte(0xd1);
read_ack();
temp=get_byte();
iic_nack();
iic_stop();
//IIC_Delay_us(1);
if(SWITCH)temp&=0x7f;
else temp|=0x80;
iic_start();
out_byte(0xd0);
read_ack();
out_byte(0x00);
read_ack();
out_byte(temp);
read_ack();
iic_stop();
//IIC_Delay_us(1);
EA=EATemp;
}
void iic_start(void) {
MDE=1;
MDO=1;
//IIC_Delay_us(2);
MCO=1;
//IIC_Delay_us(2);
MDO=0;
//IIC_Delay_us(2);
}
void iic_stop(void) {
MDE=1;
MDO=0;
//IIC_Delay_us(2);
MCO=1;
//IIC_Delay_us(2);
MDO=1;
}
void iic_ack(void) {
MDE=1;
MCO = 0;
MDO = 0;
//IIC_Delay_us(2);
MCO = 1;
//IIC_Delay_us(2);
MCO = 0;
//IIC_Delay_us(1);
MDO = 1;
}
bit read_ack(void) {
bit flag;
MCO = 0;
//IIC_Delay_us(2);
MDE=1;
MDO = 1;
MCO = 1;
//IIC_Delay_us(2);
MDE=0;
flag = MDI;
MCO = 0;
return flag;
}
void iic_nack() {
MDE=1;
MDO = 1;
//IIC_Delay_us(2);
MCO = 1;
//IIC_Delay_us(2);
MCO = 0;
}
/******************************************************************** ***************
* 函数名: get_byte;
* 描述: 从IIC总线获取一个字节;
* 输入: none;
* 返回值: 一字节数据;
* 注释: none;
********************************************************************* ***************/
unsigned char get_byte(void) //输入一个字节{
unsigned char dd;
int i;
dd=0;
MDE=1;
MDO = 1;
MDE=0;
for (i=0;i<8;i++)
{
MCO = 0;
IIC_Delay_us(1);
MCO = 1;
//IIC_Delay_us(1);
dd<<=1;
if (MDI)dd|=0x01;
}
MCO = 0;
return(dd);
}
/******************************************************************** ***************
* 函数名: out_byte;
* 描述: 向IIC总线输出一个字节;
* 输入: 一字节数据
* 返回值: none;
* 注释: none;
********************************************************************* ***************/
void out_byte(unsigned char dd) //输出一个字节{
unsigned char i;
MDE=1;
for(i=0;i<8;i++)
{
MCO = 0;
//IIC_Delay_us(0);
MDO = (dd & 0x80)>>7;
IIC_Delay_us(1);
MCO = 1;
//IIC_Delay_us(3);
dd <<= 1;
}
MCO = 0;
}
/******************************************************************** ***************
* 函数名: IIC_Delay_us;
* 描述: IIC总线延时函数;
* 输入: 延时参数
* 返回值: none;
* 注释: none;
********************************************************************* ***************/
void IIC_Delay_us(unsigned int times)
{
unsigned int i;
unsigned char DelayJs;
for (i=0; i<times; i++)DelayJs++;
}。

相关文档
最新文档