实验十七 实时时钟实验
实验目的
1.学习模拟I2C总线的软件实现方法。
2.了解实时芯片PCF8563的读写方法。
3.掌握单片机读写实时时钟芯片PCF8563的模块程序设计方法。
实验说明
- 实时时钟(RTC)器件介绍
实时时钟(RTC)器件是一种能提供日历/时钟、数据存储等功能的专用集成电路,常用作各种计算机系统的时钟信号源和参数设置存储电路。RTC具有计时准确、耗电低和体积小等特点,特别是在各种嵌入式系统中用于记录事件发生的时间和相关信息,如通信工程、电力自动化、工业控制等自动化程度高的领域的无人值守环境中。随着集成电路技术的不断发展,RTC器件的新品也不断推出,这些新品不仅具有准确的RTC,还有大容量的存储器、温度传感器是A/D数据采集通道等,已成为集RTC、数据采集和存储于一体的综合功能器件,特别适用于以微控制器为核心的嵌入式系统。
RTC器件与微控制器之间的接口大都采用连线简单的串行接口,诸如I2C、SPI、MICROWIRE和CAN等串行总线接口。 - 实时时钟芯片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
标签:disp,十七,uchar,00,地址,实验,寄存器,时钟
From: https://www.cnblogs.com/bujidao1128/p/17413586.html