加载中...

实验十七 实时时钟实验

实验十七 实时时钟实验

实验目的

1.学习模拟I2C总线的软件实现方法。
2.了解实时芯片PCF8563的读写方法。
3.掌握单片机读写实时时钟芯片PCF8563的模块程序设计方法。

实验说明

  1. 实时时钟(RTC)器件介绍
    实时时钟(RTC)器件是一种能提供日历/时钟、数据存储等功能的专用集成电路,常用作各种计算机系统的时钟信号源和参数设置存储电路。RTC具有计时准确、耗电低和体积小等特点,特别是在各种嵌入式系统中用于记录事件发生的时间和相关信息,如通信工程、电力自动化、工业控制等自动化程度高的领域的无人值守环境中。随着集成电路技术的不断发展,RTC器件的新品也不断推出,这些新品不仅具有准确的RTC,还有大容量的存储器、温度传感器是A/D数据采集通道等,已成为集RTC、数据采集和存储于一体的综合功能器件,特别适用于以微控制器为核心的嵌入式系统。
    RTC器件与微控制器之间的接口大都采用连线简单的串行接口,诸如I2C、SPI、MICROWIRE和CAN等串行总线接口。
  2. 实时时钟芯片PCF8563
    PCF8563是低功耗CMOS时钟/日历芯片(引脚如图4.3.1所示),它提供一个可编程时钟输出,一个中断输出和一个掉电检测器,所有的地址和数据通过I2C总线接口串行传送。每次读写数据后,内嵌的字地址寄存器会自动产生总量。
    引脚说明:
    1:OSCI 振荡器输入
    2:OSCO 振荡器输出
    3:/INT 中断输出(开漏;低电平有效)
    4:VSS 地
    5:SDA 串行数据I/O
    6:SCL 串行时钟输入
    7:CLKOUT 时钟输出 (开漏)
    8:VDD 正电源


图4.3.1 PCF8563引脚

PCF8563 有16 个8位寄存器:一个可自动增量的地址寄存器,一个内置32.768KHz 的振荡器(带有一个内部集成的电容),一个分频器(用于给实时时钟RTC 提供源时钟),一个可编程时钟输出,一个定时器,一个报警器,一个掉电检测器和一个I2C总线接口。
所有16个寄存器设计成可寻址的8 位并行寄存器,但不是所有位都有用。前两个寄存器(内存地址00H,01H)用于控制寄存器和状态寄存器,内存地址02H~08H 用于时钟计数器(秒~年计数器),地址09H~0CH 用于报警寄存器(定义报警条件),地址0DH 控制CLKOUT 管脚的输出频率,地址0EH 和0FH 分别用于定时器控制寄存器和定时器寄存器。秒、分钟、小时、日、月、年、分钟报警、小时报警、日报警寄存器,编码格式为BCD,星期和星期报警寄存器不以BCD 格式编码。

表17-1 PCF8563寄存器结构

地址 寄存器名称 D7 D6 D5 D4 D3 D2 D1 D0
00H 控制/状态寄存器1 TEST 0 STOP 0 TTESTC 0 0 0
01H 控制/状态寄存器2 0 0 0 TI/TP AF TF AIE TIE
02H 秒寄存器 VL 00~59 BCD码格式数
03H 分寄存器 - 00~59 BCD码格式数
04H 时寄存器 - 00~23 BCD码格式数
05H 日寄存器 - 00~31 BCD码格式数
06H 星期寄存器 - 00~06 BCD码格式数
07H 月/世纪寄存器 C 00~12 BCD码格式数
08H 年寄存器 00~99 BCD码格式数
09H 分钟报警寄存器 AE 00~59 BCD码格式数
0AH 时钟报警寄存器 AE 00~23 BCD码格式数
0BH 日报警寄存器 AE 00~31 BCD码格式数
0CH 星期报警寄存器 AE 00~06 BCD码格式数
0DH CLKOUT频率寄存器 FE FD1 FD0
0EH 定时控制寄存器 TE - - - - - TD1 TD0
0FH 定时器倒计时数值寄存器 定时器倒数计数数值

3.PCF8563与MCU的连接硬件电路


图17-1 PCF8563的硬件电路图

系统中用到的PCF8563与MCU采用的连接方式是模拟I2C总线进行数据传输的,硬件电路如图17-1所示。

4.PCF8563读写子程序模块
(1)写N个字节数据子程序模块(C51程序)

bit Nsend(uchar sla, uchar suba, uchar *s,uchar no)
{
 uchar i;
 Start_I2c();
 SendByte(sla);
 if (ack==0) return(0);
 for (i=0;i<no;i++) 
  {
    SendByte(*s);
    if (ack==0)return(0);
    s++;
}
Stop_I2c();
return(1);
}

(2)读N个字节数据子程序模块(C51程序)

bit Read(uchar sla, uchar suba, uchar *s, uchar no)
{
uchar i;
Start_I2c();
SendByte(sla);
if (ack==0)return(0);
Start_I2c();
SendByte(sla+1);
if(ack==0)return(0);
for (i=0;i<no-1;i++)
{
*s=RcvByte();
Ack_I2c(0);
s++;
}
Ack_I2c(0);
Stop_I2c();
return(1);
}

(3)初始化PCF8563程序模块及其写数据程序(A51)

FIRSTINT:
			MOV  	MTD,#00H    	  ;送初始化命令字1
			MOV  	MTD+1,#21H		    ;送初始化命令字2
			MOV  	SLA,#PCF8563	   ;送器件地址
			MOV  	SUBA,#00H		     ;送子地址为00H
			MOV  	NUMBYTE,#02	     ;写2个字节数据
			LCALL  IWRNBYTE		   ;调用写程序
			RET

(4)读取PCF8563数据程序模块(A51)

RDSFM:	MOV	SLA,#PCF8563     		;送器件地址
		MOV  	SUBA,#02H			             ;送子地址
		MOV  	NUMBYTE,#3		           ;读取3个字节
		LCALL  IRDNBYTE            			;调用读字节子程序
		RET

实验内容及步骤

1、7279阵列式键盘中的J9的短路帽打在上方,J10打在右边VCC处,JD7和JD8分别接数码显示的JD11和JD12。
2、实时时钟的SDA接最小系统的T1,SCL接INT1。
3、把89S52或89S51插到最小系统的40P插座中(ISP烧录器的使用查看附录二),把RCT.HEX文件烧录到S52/S51芯片中。运行程序,看八位数码管显示时钟,正确运行时在数码管上首先显示“00-00-00”,时间将不停的走动,把其中的一根导线断开一段时间,再接上可以看到时钟已经走了一段时间。

源程序

7279.h

extern void reset(void);
extern void write7279(unsigned char cmd, unsigned char dta);
extern unsigned char read7279(unsigned char command);
extern void send_byte1( unsigned char out_byte);
extern unsigned char receive_byte();

C8563.C

/*
1、7279阵列式键盘中的J9的短路帽打在上方,J10打在右边VCC处,
JD7和JD8分别接数码显示的JD11和JD12。
2、实时时钟的SDA接最小系统的T1,SCL接INT1。
3、把89S52或89S51插到最小系统的40P插座中(ISP烧录器的使用查看附录二),
把RTC.HEX文件烧录到S52/S51芯片中。运行程序,看八位数码管显示时钟,
正确运行时在数码管上首先显示"00-00-00",时间将不停的走动,
把其中的一根导线断开一段时间,再接上可以看到时钟已经走了一段时间。

*/
#include	<reg52.h>
#include	<I2C_C51.H>	//包含VI2C软件包
#include    <7279.h>
#include <stdio.h>

#define	PCF8563	0xA2	//定义器件地址
#define	PCF85631	0xA3	//定义器件地址
#define	WRADDR	0x00	//定义写单元首地址
#define	RDADDR	0x02	//定义读单元首地址
#define DECODE0 0x80
#define DECODE1 0xc8
#define BLINKCTL 0x88
unsigned char disp_buf[8]={0,0,0,0,0,0,0,0};

/*********************************************************************************************************
** 函数名称: 	display
** 功能描述: 	7298A led显示
** 输 入: *sd :	显示缓冲区的头地址
**         
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
unsigned char display(unsigned char  *sd)
{     
	sd[0]=sd[0]&0x7f;
	sd[1]=sd[1]&0x7f;
	sd[2]=sd[2]&0x3f;
  	disp_buf[0] =(sd[0]%16);			
    disp_buf[1] =(sd[0]/16);		
    disp_buf[2] = 0x0a;
    disp_buf[3] =(sd[1]%16);
    disp_buf[4] =(sd[1]/16);
    disp_buf[5] = 0x0a;
    disp_buf[6] =(sd[2]%16);	
    disp_buf[7] =(sd[2]/16);
	write7279(BLINKCTL,0xff);
    write7279(DECODE0,disp_buf[0]); 
    write7279(DECODE0+1,disp_buf[1]);
    write7279(DECODE0+2,disp_buf[2]); 
    write7279(DECODE0+3,disp_buf[3]);
    write7279(DECODE0+4,disp_buf[4]); 
    write7279(DECODE0+5,disp_buf[5]);
    write7279(DECODE0+6,disp_buf[6]); 
    write7279(DECODE0+7,disp_buf[7]);
	return 0;
}

/*********************************************************************************************************
** 函数名称: 	DelayNS
** 功能描述: 	长软件延时
** 输 入: no :	延时参数,值越大时延时越久
**         
** 输 出: 0 :	OK;
**         1 :	FAIL;
** 全局变量:	无
** 调用模块: 	无
** 日 期: 2003-3-4
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
unsigned char DelayNS(unsigned char  no)
{ 
	unsigned char  i,j;					//延时参数
  	for(; no>0; no--)
  	{ 
		for(i=0; i<100; i++)
     	for(j=0; j<100; j++);
  	}
  	return 0; 
}

void	main()
{
  unsigned char td[5]={0x00,0x00,0x00,0x00,0x00};	//定义初始化字
  unsigned char rd[5];	//定义接收法缓冲区
  ISendStr(PCF8563,WRADDR,td,0x5);	//初始化PCF8563,如果需要的话可以不去掉
  while(1)
  { //DelayNS(1);
	IRcvStr(PCF8563,RDADDR,rd,0x3);	//读现在的时、分、秒
	DelayNS(1);
	display(rd);	//调显示子程序
	DelayNS(1);
  }
}

I2C_C51.h

/*****************************************************************
/*文件名:I2C_C51.H(头文件名)
/*创建人:晁洪超
   这个头文件对应的库是I2C_C51.LIB,库中有几个模拟I2C的函数,加入此文件 
即可使用I2C平台(主方式的软件平台),            
   注意: 函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作 
一定的修改....(本例是1us机器周期,即晶振频率要小于12MHZ).
(函数的使用可参考给出的事例程序.)
*****************************************************************/

#ifdef uchar 
  #define READYDEF 1   /*宏uchar已定义*/
#else  
  #define uchar unsigned char
#endif


/*******************************************************************
                     无子地址发送字节数据函数               

功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.
      如果返回1表示操作成功,否则操作有误。
********************************************************************/
extern bit ISendByte(uchar sla,uchar c);
 




/*******************************************************************
                     有子地址发送多字节数据函数               

功能:  从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
       地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
       如果返回1表示操作成功,否则操作有误。
********************************************************************/
extern bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no) ;



/*******************************************************************
                    无子地址读字节数据函数               

功能:     从启动总线到发送地址,读数据,结束总线的全过程,从器件地
          址sla,返回值在c.
           如果返回1表示操作成功,否则操作有误。
********************************************************************/
extern bit IRcvByte(uchar sla,uchar *c);





/*******************************************************************
                    有子地址读取多字节数据函数               
   
功能:  从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
       地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
       如果返回1表示操作成功,否则操作有误。
********************************************************************/
extern bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no);



#ifndef READYDEF
  #undef uchar
#endif

posted @ 2023-05-18 23:09  bujidao1128  阅读(270)  评论(0)    收藏  举报