万年历程序 C语言

 

万年历数字钟及可调时钟系统

一、引言

万年历数字钟是一种用万年历时钟芯片实现年、月、日、时、分、秒计时,并通过单片机处理后送给显示芯片显示的装置,与机械式时钟相比具有更高的准确性和直观性,且具有更长的使用寿命。本系统还可以扩展为可调的自动开关,对家电对用电设备进行控制,笔者在随后改制成为可调时的自动断电的供电系统.

二、原理图设计

1.单片机及其外围电路设计

复位采用X25045芯片,复位电路如图1

万年历程序 C语言

所示。

图1复位电路设计

单片机采用贴片封装的AT89S51,晶振为11.0592MHz。其中P1.5~P1.7为下载程序使用,电路如图2所示。

万年历程序 C语言

图2单片机89S51外围电路设计

2.时钟芯片电路设计

时钟芯片采用PCF8563,晶振采用32.768K,电容使用15pf。PCF8563是PHILIPS公司推出的一款工业级内含I2C总线接口功能的具有极低功耗的多功能时钟/日历芯片。内部时钟电路、内部振荡电路、内部低电压检测电路(1.0V)以及两线制I2C总线通讯方式,不但使外围电路及其简洁,而且也增加了芯片的可靠性。同时每次读写数据后,内嵌的字地址寄存器会自动产生增量。电路如图3所示。

万年历程序 C语言

图3时钟芯片电路设计

3.显示芯片电路设计

显示芯片采用ZLG7289,晶振为12MHz。ZLG7289A是广州周立功单片机发展有限公司自行设计的,具有SPI串行接口功能的可同时驱动8位共阴式数码管(或64只独立LED)的智能显示驱动芯片,该芯片同时还可连接多达64键的键盘矩阵,单片即可完成LED显示﹑键盘接口的全部功能。电路如图4

万年历程序 C语言

所示。

图4

4.双电源电路设计显示芯片电路设计

系统采用双电源,平时使用V1=10V的外接电源,停电时使用电池,由V2输入。电池有6节,其电压为9V。当电池电压低于6V时,LED亮,说明电池电量不足。电路如图5所示。

万年历程序 C语言

图5双电源电路设计

万年历程序 C语言.doc下载

三、程序设计

程序开始时先对系统初始化,并设置好各种中断。下步操作主要是对时钟芯片进行操作,首先要给时钟芯片设置初值,时钟芯片便自行计数。此时检测是否有按键按下,按键是为了调整时钟。有按键按下则执行按键中断程序,没有按键按下则执行下一步的操作,即取时钟芯片中的时钟值,然后送显示。程序流程图

万年历程序 C语言

如下。

图6总体流程图

四、源程序

<reg51.h>

<intrins.h>

<math.h>#include#include#include

#defineucharunsignedchar/*宏定义*/

#defineuintunsignedint

ucharclose_date,open_date;

voidRESWDI(void);

voidWREN(void);

voidWRDI(void);

voidWRSR(void);

unsignedcharRSDR(void);

voidWIPCHK(void);

voidOUTByte(unsignedcharByte);

unsignedcharINPUTByte(void);

unsignedcharReadByte(unsignedcharADD);

voidWriteByte(unsignedcharByte,ADD);

#define_Nop()_nop_()/*定义空指令*/sbit

sbit

sbit

sbit

sbit

sbit

sbit

sbit

sbit

sbit

sbit

sbit

sbitzlg7289_cs=P1^1;zlg7289_clk=P2^6;zlg7289_dio=P2^7;zlg7289_key=P3^2;p07=P0^7;p06=P0^6;CS=P2^4;SCK=P2^2;SO=P2^5;SI=P2^3;p10=P1^0;SDA=P1^2;SCL=P1^3;/*模拟I2C数据传送位*//*模拟I2C时钟控制位*/uchar

uchar

uchar

ucharbuf[9]={0x00,0x00,0x30,0x23,0x15,0x1,0x05,0x04,0x05};bufdata,bb,date;SLA=0xA2,SUBA=0x00;*p;/*接收指针*/

ucharkeychange=0;

ucharkey=0;/*键盘值*/

bitkeyint=0;/*按键中断标志*/

bitkeyok=1;/*数据是否修改好*/

ucharnum=0;/*移位键移到哪个LED*/

/****延时函数****************************************/voiddelay(uchari)

{

while(i--);

}

//********************TIMER1interrupt***************************//

timer0(void)interrupt1using1{

TH0=0x3c;

TL0=0xb0;

RESWDI();

}process

voidRESWDI(void)////复位看门狗(喂狗){

zlg7289_cs=1;

CS=1;

CS=0;

CS=1;

zlg7289_cs=1;

}

voidWREN(void)//写使能复位使用)?{

zlg7289_cs=1;

SCK=0;

CS=0;

OUTByte(0x06);//发送06H写使能命令字SCK=0;

CS=1;

zlg7289_cs=1;

}

voidWRDI(void)//写使能复位(禁止写{{

zlg7289_cs=1;

SCK=0;

CS=0;

OUTByte(0x04);//发送04H写禁止命令字SCK=0;CS=1;

zlg7289_cs=1;

}

voidWRSR(void)//写状态寄存器

{

WREN();

zlg7289_cs=1;

SCK=0;

CS=0;

OUTByte(0x01);//发送01H写寄存器命令字

OUTByte(0x00);//发送寄存器值BL0,BL1为0没写保护,WD0=0W01=1//WD1=0WD1=0看门狗复位时间1.4S

SCK=0;

CS=1;

zlg7289_cs=1;

WIPCHK();//判断是否写入

}

unsignedcharRSDR(void)//读状态寄存器

{

unsignedcharTemp;

zlg7289_cs=1;

SCK=0;

CS=0;

OUTByte(0x05);//发送05H读状态寄存器命令字

Temp=INPUTByte();//读状态寄存器值

SCK=0;

CS=1;

returnTemp;;//这一个调试时没有执行,Temp的值总是0xFF;???????????zlg7289_cs=1;

}

voidWIPCHK(void)//检查WIP位,判断是否写入完成

{

unsignedcharTemp,TempCyc;

for(TempCyc=0;TempCyc<50;TempCyc++)

{

Temp=RSDR();//读状态寄存器

if(Temp&0x01==0)

TempCyc=50;

}

}

//单字节指令或数据写入X25045

//在SI线上输入的数据在SCK的上升沿被锁存。voidOUTByte(unsignedcharByte)//输出一个定节{

unsignedcharTempCyc;

zlg7289_cs=1;

for(TempCyc=0;TempCyc<8;TempCyc++)

{

SCK=0;

if(Byte&0x80)

SI=1;

else

SI=0;

SCK=1;

Byte=Byte<<1;//右移

}

SI=0;//使SI处于确定的状态

zlg7289_cs=1;

}

//单字节数据从X25045读到单片机

//数据由SCK的下降沿输出到SO线上。

unsignedcharINPUTByte(void)//输入一个字节{

unsignedcharTemp=0,TempCyc;

zlg7289_cs=1;

for(TempCyc=0;TempCyc<8;TempCyc++)

{

Temp=Temp<<1;//右移

SCK=1;

SCK=0;

if(SO)

Temp=Temp|0x01;//SO为1,则最低位为1else

Temp&=0xFE;

}

returnTemp;;//这一个调试时没有执行,Temp的值总是0

zlg7289_cs=1;

}

unsignedcharReadByte(unsignedcharADD)//读地址中的数据这里不做先导字处理,只能读00-FFH

{

unsignedcharTemp;

zlg7289_cs=1;

SCK=0;

CS=0;

SO=1;

SI=1;

OUTByte(0x3);//发送读指令03H如要支持000-FFF则要把高位地址左移3位再为03H相或

OUTByte(ADD);//发送低位地址

Temp=INPUTByte();

SCK=0;

CS=1;

returnTemp;//这一个调试时没有执行,Temp的

zlg7289_cs=1;

}

voidWriteByte(unsignedcharByte,ADD)//向地址写入数据这里同样不做先导字处理,只能写00-FFH

{

WREN();

zlg7289_cs=1;

SCK=0;

CS=0;

SO=1;

SI=1;

OUTByte(0x2);//发送写指令02H如要支持000-FFF则要把高位地址左移2位再为02H相或

OUTByte(ADD);//发送低位地址

OUTByte(Byte);//发送数据

SCK=0;

第11 / 32页

CS=1;

WIPCHK();

zlg7289_cs=1;

}

/***********************************************************************************模拟I2C总线传输程序

***********************************

********************************************************************/bitack;/*应答标志位*/

/*******************************************************************

起动总线函数

********************************************************************/voidStart_I2c()

{

SDA=1;/*发送起始条件的数据信号*/

_Nop();

SCL=1;

_Nop();/*起始条件建立时间大于4.7us,延时*/

_Nop();

_Nop();

_Nop();

_Nop();

SDA=0;/*发送起始信号*/

_Nop();/*起始条件锁定时间大于4μs*/

_Nop();

_Nop();

_Nop();

_Nop();

SCL=0;/*钳住I2C总线,准备发送或接收数据*/

_Nop();

_Nop();

}

/*******************************************************************

结束总线函数

********************************************************************/voidStop_I2c()

{

SDA=0;/*发送结束条件的数据信号*/

_Nop();/*发送结束条件的时钟信号*/

SCL=1;/*结束条件建立时间大于4μs*/

_Nop();

_Nop();

_Nop();

_Nop();

_Nop();

SDA=1;/*发送I2C总线结束信号*/

_Nop();

_Nop();

_Nop();

_Nop();

}

/*******************************************************************

字节数据传送函数

********************************************************************/voidSendByte(ucharc)

{

ucharBitCnt;

for(BitCnt=0;BitCnt<8;BitCnt++)/*要传送的数据长度为8位*/{

if((c<<BitCnt)&0x80)SDA=1;/*判断发送位*/

elseSDA=0;

_Nop();

SCL=1;/*置时钟线为高,通知被控器开始接收数据位*/_Nop();

_Nop();/*保证时钟高电平周期大于4μs*/

_Nop();

_Nop();

_Nop();

SCL=0;

}

_Nop();

_Nop();

SDA=1;

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop();

_Nop();/*8位发送完后释放数据线,准备接收应答位*/

if(SDA==1)ack=0;

elseack=1;

SCL=0;

_Nop();

_Nop();

}/*判断是否接收到应答信号*/

/*******************************************************************

字节数据接收函数

********************************************************************/ucharRcvByte()

{

ucharretc;

ucharBitCnt;

retc=0;

SDA=1;/*置数据线为输入方式*/

for(BitCnt=0;BitCnt<8;BitCnt++)

{

_Nop();

SCL=0;/*置时钟线为低,准备接收数据位*/

_Nop();

_Nop();/*时钟低电平周期大于4.7s*/

_Nop();

_Nop();

_Nop();

SCL=1;/*置时钟线为高使数据线上数据有效*/

_Nop();

_Nop();

retc=retc<<1;

if(SDA==1)retc=retc+1;/*读数据位,接收的数据位放入retc中*/_Nop();

_Nop();

}

SCL=0;

_Nop();

_Nop();

return(retc);

}

/********************************************************************

应答子函数

********************************************************************/voidAck_I2c(bita)

{

if(a==0)SDA=0;

elseSDA=1;

_Nop();

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop();

_Nop();

_Nop();

_Nop();

SCL=0;

_Nop();

_Nop();

}

/*******************************************************************

向有子地址器件发送多字节数据函数

********************************************************************/bitISendStr(ucharsla,ucharsuba,uchar*s)

{

uchari;

Start_I2c();

SendByte(sla);

if(ack==0)return(0);

SendByte(suba);

if(ack==0)return(0);/*启动总线*//*发送器件地址*//*发送器件子地址*//*在此发出应答或非应答信号*//*时钟低电平周期大于4μs*//*清时钟线,钳住I2C总线以便继续接收*/

for(i=0;i<9;i++)

{

SendByte(*s);/*发送数据*/

if(ack==0)return(0);

s++;

}

Stop_I2c();/*结束总线*/

return(1);

}

/*******************************************************************

第15 / 32页

向有子地址器件读取多字节数据函数

********************************************************************/bitIRcvStr(ucharsla,ucharsuba,uchar*s)

{

uchari;

Start_I2c();

SendByte(sla);

if(ack==0)return(0);

SendByte(suba);

if(ack==0)return(0);

Start_I2c();

SendByte(sla+1);

if(ack==0)return(0);

for(i=0;i<8;i++)

{

*s=RcvByte();

Ack_I2c(0);

s++;

}

*s=RcvByte();

Ack_I2c(1);

Stop_I2c();

return(1);

}

/**********模拟I2C程序结束***************************/

/*显示函数*******************************************/

voiddisplay(uintdis)

{

ucharj;

zlg7289_clk=0;

delay(20);

zlg7289_cs=0;

for(j=0;j<16;j++)

{

if((dis&0x8000)==0x8000)zlg7289_dio=1;

elsezlg7289_dio=0;

delay(20);

zlg7289_clk=1;

delay(10);/*启动总线*//*发送器件地址*//*发送器件子地址*//*发送数据*//*发送就答位*//*发送非应位*//*结束总线*/

zlg7289_clk=0;

delay(10);

dis=dis<<1;

}

zlg7289_cs=1;

delay(20);

}

voiddis_play(ucharaa)

{

uchari;

for(i=0;i<8;i++)

{

if(_crol_(aa,i)&0x80)

zlg7289_dio=1;

else

zlg7289_dio=0;

zlg7289_clk=1;

delay(10);/*延时*/

zlg7289_clk=0;

}

}

voiddisplaymonth()

{

bufdata=buf[5]&0x0f;

zlg7289_cs=0;

delay(10);

dis_play(0xc8);

delay(10);

dis_play(bufdata);/*显示日个位*/zlg7289_cs=1;

delay(70);

bufdata=buf[5]&0x30;

bufdata=bufdata>>4;

bufdata=bufdata&0x0f;

zlg7289_cs=0;

delay(10);

dis_play(0xc9);

delay(10);

dis_play(bufdata);

zlg7289_cs=1;

delay(70);/*显示日十位*/

bufdata=buf[7]&0x0f;zlg7289_cs=0;delay(10);

dis_play(0xca);delay(10);

dis_play(bufdata);zlg7289_cs=1;delay(70);

bufdata=buf[7]&0x10;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);

dis_play(0xcf);delay(10);

dis_play(bufdata);zlg7289_cs=1;delay(70);

}

voiddisplaytime(){

bufdata=buf[3]&0x0f;zlg7289_cs=0;delay(10);

dis_play(0xce);delay(10);

dis_play(bufdata);zlg7289_cs=1;delay(70);

bufdata=buf[3]&0x70;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);

dis_play(0xcd);delay(10);

dis_play(bufdata);zlg7289_cs=1;delay(70);

bufdata=buf[4]&0x0f;zlg7289_cs=0;/*显示月个位*//*显示月十位*//*显示分个位*//*显示分十位*/

delay(10);

dis_play(0xcc);delay(10);

dis_play(bufdata);zlg7289_cs=1;delay(70);

bufdata=buf[4]&0x30;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);

dis_play(0xcb);delay(10);

dis_play(bufdata);zlg7289_cs=1;delay(70);

}

voiddisplay_x5045(){

date=ReadByte(0x40);close_date=date;bufdata=date&0x0f;zlg7289_cs=0;delay(10);

dis_play(0xce);delay(10);

dis_play(bufdata);zlg7289_cs=1;delay(70);

bufdata=date&0x70;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);

dis_play(0xcd);delay(10);

dis_play(bufdata);zlg7289_cs=1;delay(70);

date=ReadByte(0x42);bufdata=date&0x0f;/*显示时个位*//*显示时十位*//*显示分个位*//*显示分十位*/

zlg7289_cs=0;

open_date=ReadByte(0x42);

delay(10);

dis_play(0xcc);

delay(10);

dis_play(bufdata);/*显示时个位*/

zlg7289_cs=1;

delay(70);

bufdata=date&0x30;

bufdata=bufdata>>4;

bufdata=bufdata&0x0f;

zlg7289_cs=0;

delay(10);

dis_play(0xcb);

delay(10);

dis_play(bufdata);

zlg7289_cs=1;

delay(70);/*显示时十位*/

}

/****************按键处理程序*********************///key=47:闪烁移位键(shift)

//key=39:+

//key=39:-

//key=31:确认键(ok)

voidkey_int()interrupt0/*键盘中断程序*/{

keyint=1;

}

voidkeyexe()

{

uchari;

uchartemp=0;

ucharaa;

p06=1;

EX0=1;

zlg7289_cs=0;

delay(10);

dis_play(0x15);

delay(10);

for(i=0;i<8;i++)

{

temp=temp<<1;/*写入读键盘数据指令*/

aa=zlg7289_dio;//按位或

if(aa==1)//读数据位,接收的数据位放入retc中temp=temp+1;

zlg7289_clk=1;

delay(10);//延时

zlg7289_clk=0;

}

zlg7289_cs=1;

key=temp;

if(key==47)//闪烁移位键

{

key=0;

keyok=0;

EX0=0;

if(num==8)

{

num=1;

}

else

num++;

switch(num)

{case1:{display(0x88fe);}break;

case2:{display(0x88fd);}break;

case3:{display(0x88fb);}break;

case4:{display(0x88f7);}break;

case5:{display(0x88ef);}break;

case6:{display(0x88df);}break;

case7:{display(0x88bf);}break;

case8:{display(0x887f);}break;

default:;

}

EX0=1;

}

elseif(key==39)//+

{

EX0=0;

key=0;

RESWDI();

if(num!=0)

{

keyok=0;

keychange=1;

RESWDI();

}

if(num==7)//在分个位上

{

if((buf[3]&0x0f)==0x09)buf[3]&=0xf0;else++buf[3];

EX0=1;

bufdata=buf[3]&0x0f;

zlg7289_cs=0;

delay(10);

dis_play(0xce);

delay(10);

dis_play(bufdata);/*显示分个位*/zlg7289_cs=1;

delay(70);

RESWDI();

}

elseif(num==6)//在分十位上

{

if((buf[3]&0xf0)==0x50)buf[3]&=0x0f;elsebuf[3]+=0x10;

EX0=1;

bufdata=buf[3]&0x70;

bufdata=bufdata>>4;

bufdata=bufdata&0x0f;

zlg7289_cs=0;

delay(10);

dis_play(0xcd);

delay(10);

dis_play(bufdata);/*显示分十位*/zlg7289_cs=1;

delay(70);

RESWDI();

}

elseif(num==5)//在小时个位上

{

if((buf[4]&0xf0)==0x20)

{

if((buf[4]&0x0f)>0x02)buf[4]&=0xf0;else++buf[4];

}

elseif((buf[4]&0x0f)==0x09)buf[4]&=0xf0;else++buf[4];

EX0=1;

久久建筑网m.kkreddy.com提供大量:建筑图纸、施工方案、工程书籍、建筑论文、合同表格、标准规范、CAD图纸等内容。


TOP最近更新内容

    刑法的二十个钻石考点 【阮齐林】 系统防雷方案 梁凯恩 ——《福布斯导师商学院》精华 郭硕鸿 电动力学 2013 3月二级c无纸化题库 南京理工大学考研计算机复试上机题目 山东省威海市2011届高三模拟考试(数学文) 富士康科技公司基础IE培训--现场改善.ppt 宋鸿兵语录 PS技术 在学校里 学三年 也学不到这么多x DLT 1080.4-2010 电力企业应用集成 配电管 语言学概论笔记 德隆的资本运作与行业整合 ANSYS工程结构数值分析命令查询表 建筑装饰装修工程施工质量验收规范(GB5021