1 功能和特性简介
ISL1208是Intersil公司的一款低功耗实时时钟集成电路,为用户提供了 2个字节的静态存储器。它要求外置一个32.768 kHz的晶体振荡器以提供振荡源;提供I2C总线接口以方便与微处理器通信,最高传输速率达400 kHz。专用的寄存器用于寄存时、分、秒、年、月、日和星期。日历的有效范围值为2000~2099年,且能自动识别闰年。
与其他类型的实时时钟电路相比,ISL1208的突出优点在于:
①频率补偿功能。晶振频率的准确性关系到整个实时时钟的准确性,20 ppm的频率误差在一个月内将会累计产生1 min的误差。晶体振荡器在不同的环境温度下均会产生频率漂移,为此必须根据不同的环境温度对实际工作频率进行补偿以确保振荡信号的准确性。ISL1208采用数字式的电容容量调整方式,对晶振频率进行修正,修正范围达-94~+140 ppm。
②备用电源自动切换功能。无需增加额外的元器件就可以在正常工作电源与备用电源之间进行切换。备用电源可以是可充电电池,也可以是大容量电容。
③超低功耗。ISL1208在5 V供电下的典型工作电流仅为2μA,一个0.47 F的电容可以维持其正常工作一个月的时间。
X1和X2为内部反相放大器的输入和输出引脚。外置的32.768 kHz晶体振荡器连接到X1和X2,以产生实时时钟的基本振荡信号。VBAT为备用电源提供端,当VDD电源失效时,VRAT端的备用电源立即生效;在外部供电中断的情况下,内部的时钟信号产生电路依旧可以正常工作。SDA和SCL为连接到I2C总线的两个引脚。SDA是开漏输出结构,可双向输入和输出,用于传输串行数据信号;SCL为I2C总线上的时钟信号线。IRQ/FOUT是一个多功能引脚,通过对配置寄存器的设定,可以定义其为中断输出或固定频率输出端。VDD和GND分别为电源端和地,ISL1208的工作电压为2.0~5.5 V。
2 寄存器描述
ISL1208在I2C总线上的器件地址为1101111X,器件内共有20个子地址分别对应于20个寄存器。实时时钟占用00h~06h,控制与状态寄存器占用07h~OBh,报警寄存器占用0Ch~11h,用户SRAM占用12h和13h。任何一个寄存器的内容既可以读,也可以写;可以采用单字节读写,也可以采用页地址读写。在对实时时钟寄存器进行写之前,要确保状态寄存器的WRTC位置1。以页为单位读写时,一次不能超过一个区段,例如连续读了7个字节的时钟寄存器之后,不能继续读控制与状态寄存器。表1列出了实时时钟寄存器、控制与状态寄存器的地址和内容。
实时时钟的数字形式为BCD码,例如26日,在03h单元中的数值为26h。在06h单元中,星期日对应于数值00h,星期一到星期六对应于01h~06h。在02h单元中,如果MIL位为1,则表示02h单元保存的小时数值为24小时制;如果为0,则表示为12小时制,此时HR21为上/下午的标志位,1代表下午,0代表上午。
3 接口技术
ISL1208与单片机的典型接口电路。单片机采用Winbond公司的78E58,它在I2C总线上为主器件,ISL1208和LM75A为从器件。P10和P11脚分别模拟I2C总线的SDA和SCL。LM75A是I2C总线的数字温度传感器,在此实时时钟电路的应用中并非是必需的。在需要根据环境温度对晶振频率进行补偿的场合,则需要一个温度传感器来检测环境温度。
SDA和SCL必须对电源有上拉电阻。当外部电源供电正常时,主电源+5 V通过二极管D1对电容C1进行充电。当主电源电压比后备电源的电压至少低50 mV且主电源电压低于2.2 V时,后备电源开始向ISL1208供电。将ISL1208的IRQ/FOUT输出设定为固定的方波输出,频率设定为1Hz。将该信号连接到单片机的中断输入端INT1,每产生一次中断表明实时时钟刷新了一次,中断周期为1 s。
4 接口软件
ISL1208完全符合I2C总线的通信规范。Winbond 78E58没有I2C接口,因此用普通的I/O口采用软件的方式模拟I2C通信。在此应用中它是主器件,由它发起总线传输并提供时钟信号。在任何应用场合,ISL1208始终是从器件。
5 程序源码
/****************************************************************************
* 文件名:I2CINT.C
* 功能:硬件I2C软件包,利用中断方式操作。
* 说明:主程序要配置好I2C总线接口(I2C引脚功能和I2C中断,并已使能I2C主模式)
****************************************************************************/
#include "config.h"
#define ISL1208 0xde /* 定义器件地址 */
typedef unsigned char uint8; /* defined for unsigned 8-bits integer variable 无符号8位整型变量 */
typedef signed char int8; /* defined for signed 8-bits integer variable 有符号8位整型变量 */
typedef unsigned short uint16; /* defined for unsigned 16-bits integer variable 无符号16位整型变量 */
typedef signed short int16; /* defined for signed 16-bits integer variable 有符号16位整型变量 */
typedef unsigned int uint32; /* defined for unsigned 32-bits integer variable 无符号32位整型变量 */
typedef signed int int32; /* defined for signed 32-bits integer variable 有符号32位整型变量 */
typedef float fp32; /* single precision floating point variable (32bits) 单精度浮点数(32位长度) */
typedef double fp64; /* double precision floating point variable (64bits) 双精度浮点数(64位长度) */
/* 以下为I2C操作时所需要的变量 */
volatile uint8 I2C_sla; // 从机地址(即器件地址)
volatile uint8 I2C_suba; // 子地址
volatile uint8 *I2C_buf; // 数据缓冲区指针 (读操作时会被更改)
volatile uint8 I2C_num; // 操作数据个数 (会被更改)
volatile uint8 I2C_end; // 操作结束标志,为1时表示操作结束,为0xFF时表示操作失败 (会被设置)
volatile uint8 I2C_suba_en; // 子地址使能控制,读操作时请设置为1,写操作时请设置为2 (会被更改)
extern volatile uint8 rtc_y; //年
extern volatile uint8 rtc_m; //月
extern volatile uint8 rtc_d; //日
extern volatile uint8 rtc_h; //时
extern volatile uint8 rtc_mn; //分
extern volatile uint8 rtc_s; //秒
extern volatile uint8 rtc_dw; //星期
/****************************************************************************
* 名称:IRQ_I2C()
* 功能:I2C中断,通过判断I2C状态字进行相应的操作。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void __irq IRQ_I2C(void)
{ uint8 sta;
sta = I2STAT; // 读出I2C状态字
switch(sta)
{ case 0x08: // 己发送起始条件
if(1==I2C_suba_en) I2DAT = I2C_sla&0xFE; // 指定子地址读时,先写入地址
else I2DAT = I2C_sla; // 否则直接发送从机地址
I2CONCLR = 0x28; // SI=0
break;
case 0x10:
I2DAT = I2C_sla; // 重启动总线后,发送从地址
I2CONCLR = 0x28; // SI=0
break;
case 0x18: // 已发送SLA+W,并已接收应答
if(0==I2C_suba_en) // 无子地址,则直接发送数据
{ if(I2C_num>0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28;
I2C_num--;
}
else
{ I2CONSET = 0x10; // 无数据发送,结束总线
I2CONCLR = 0x28;
I2C_end = 1; // 设置总线操作结束标志
}
break;
}
if(1==I2C_suba_en) // 发送子地址
{ I2DAT = I2C_suba;
I2CONCLR = 0x28;
}
if(2==I2C_suba_en)
{ I2DAT = I2C_suba;
I2CONCLR = 0x28;
I2C_suba_en = 0; // 子地址己处理
}
break;
case 0x28: // 已发送I2C数据,并接收到应答
if(0==I2C_suba_en) // 无子地址,则直接发送数据
{ if(I2C_num>0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28;
I2C_num--;
}
else
{ I2CONSET = 0x10; // 无数据发送,结束总线
I2CONCLR = 0x28;
I2C_end = 1;
}
break;
}
if(1==I2C_suba_en) // 若是指定地址读,则重新启动总线
{ I2CONSET = 0x20;
I2CONCLR = 0x08;
I2C_suba_en = 0; // 子地址己处理
}
break;
case 0x20:
case 0x30:
case 0x38:
I2CONCLR = 0x28; // 总线进入不可寻址从模式
I2C_end = 0xFF; // 总线出错,设置标志
break;
case 0x40: // 己发送SLA+R,并已接收到应答
if(1==I2C_num) // 最后一字节,接收数据后发送非应答信号
{ I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答
}
else // 接收数据并发送应答信号
{ I2CONSET = 0x04; // AA=1,接收到数据后产生应答
I2CONCLR = 0x28;
}
break;
case 0x50:
*I2C_buf++ = I2DAT; // 读取数据
I2C_num--;
if(1==I2C_num)
{ I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答
}
else
{ I2CONSET = 0x04; // AA=1,接收到数据后产生应答
I2CONCLR = 0x28;
}
break;
case 0x58:
*I2C_buf++ = I2DAT; // 读取最后一字节数据
I2CONSET = 0x10; // 结束总线
I2CONCLR = 0x28;
I2C_end = 1;
break;
case 0x48:
I2CONCLR = 0x28; // 总线进入不可寻址从模式
I2C_end = 0xFF;
break;
default:
break;
}
VICVectAddr = 0x00; // 中断处理结束
}
/****************************************************************************
* 名称:ISendStr()
* 功能:向有子地址器件发送多字节数据。
* 入口参数:sla 器件从机地址
* suba 器件子地址
* s 数据发送缓冲区指针
* no 发送数据个数
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
{ /* 参数设置 */
I2C_sla = sla; // 写操作的器件地址
I2C_suba = suba; // 子地址
I2C_buf = s;
I2C_num = no;
I2C_suba_en = 2; // 有子地址写
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:IRcvStr()
* 功能:向有子地址器件读取多字节数据。
* 入口参数:sla 器件地址
* suba 器件子地址
* s 数据接收缓冲区指针
* no 读取数据个数
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 IRcvStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
{ if(0==no) return(0);
/* 参数设置 */
I2C_sla = sla+1; // 读操作的器件地址
I2C_suba = suba;
I2C_buf = s;
I2C_num = no;
I2C_suba_en = 1; // 有子地址读
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:I2C_Init()
* 功能:主模式I2C初始化,包括初始化其中断为向量IRQ中断。
* 入口参数:fi2c 初始化I2C总线速率,最大值为400K
* 出口参数:无
****************************************************************************/
void I2C_Init(uint32 fi2c)
{ if(fi2c>400000) fi2c = 400000;
PINSEL0 = (PINSEL0&0xFFFFFF0F) | 0x50; // 设置I2C控制口有效
I2SCLH = (Fpclk/fi2c + 1) / 2; // 设置I2C时钟为fi2c
I2SCLL = (Fpclk/fi2c) / 2;
I2CONCLR = 0x2C;
I2CONSET = 0x40; // 使能主I2C
/* 设置I2C中断允许 */
VICIntSelect = 0x00000000; // 设置所有通道为IRQ中断
VICVectCntl7 = 0x29; // I2C通道分配到IRQ slot 0,即优先级最高
VICVectAddr7 = (int)IRQ_I2C; // 设置I2C中断向量地址
VICIntEnable = 0x0200; // 使能I2C中断
}
/****************************************************************************
* 名称:Write_Rtc()
* 功能:向实时时钟芯片写入时间
* 入口参数:
* 出口参数:无
****************************************************************************/
void Write_Rtc(void)
{
uint8 data_buf[7];
uint16 i;
//I2C_Init(100000); // I2C初始化
data_buf[0]=0x90; //WRTC位置1
ISendStr(ISL1208,0x07,data_buf, 1);
i=YEAR;
i=i-2000;
rtc_y=(i/10)*16+i%10;
i=MONTH;
rtc_m=(i/10)*16+i%10;
i=DOM;
rtc_d=(i/10)*16+i%10;
i=HOUR;
rtc_h=0x80+(i/10)*16+i%10;
i=MIN;
rtc_mn=(i/10)*16+i%10;
i=SEC;
rtc_s=(i/10)*16+i%10;
data_buf[0]=rtc_s; //秒
data_buf[1]=rtc_mn; //分
data_buf[2]=rtc_h; //时
data_buf[3]=rtc_d; //日
data_buf[4]=rtc_m; //月
data_buf[5]=rtc_y; //年
data_buf[6]=rtc_dw; //星期
ISendStr(ISL1208,0x00,data_buf,7);
}
/****************************************************************************
* 名称:Read_Rtc()
* 功能:从实时时钟芯片读出时间
* 入口参数:
* 出口参数:无
****************************************************************************/
void Read_Rtc(void)
{
uint8 data_buf[7];
//I2C_Init(100000); // I2C初始化
IRcvStr(ISL1208, 0x00, data_buf, 7);
rtc_s=data_buf[0]; //秒
rtc_mn=data_buf[1]; //分
rtc_h=data_buf[2]; //时
rtc_d=data_buf[3]; //日
rtc_m=data_buf[4]; //月
rtc_y=data_buf[5]; //年
rtc_dw=data_buf[6]; //星期
}
/****************************************************************************
* 名称:RTCIni()
* 功能:初始化实时时钟。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void RTCIni(void)
{
PREINT = Fpclk / 32768 - 1; // 设置基准时钟分频器
PREFRAC = Fpclk - (Fpclk / 32768) * 32768;
Read_Rtc();
YEAR = 2000+((rtc_y&0xf0)>>4)*10+(rtc_y&0x0f); // 初化年
MONTH = ((rtc_m&0xf0)>>4)*10+(rtc_m&0x0f); // 初化月
DOM = ((rtc_d&0xf0)>>4)*10+(rtc_d&0x0f); // 初化日
HOUR = ((rtc_h&0x70)>>4)*10+(rtc_h&0x0f);
MIN = ((rtc_mn&0xf0)>>4)*10+(rtc_mn&0x0f);
SEC = ((rtc_s&0xf0)>>4)*10+(rtc_s&0x0f);
ILR=0X03;
CIIR = 0x01; // 设置秒值的增量产生一次中断
CCR = 0x01; // 启动RTC
VICVectCntl3 = 0x2D; // RTC中断通道分配(向量控制器)。2:IRQ使能,D:中断编号为13
VICVectAddr3 = (uint32)IRQ_RTC; // 设置RTC中断服务程序地址向量
VICIntEnable = 0x00002000; // 使能定RTC中断
}
6 原理图
ISL1208电路.JPG
7 其他资料
ISL1208cn.pdf (527.39 KB, 下载次数: 2)
ISL1208IB8Z-TK.pdf (393.58 KB, 下载次数: 2)
LPC2210-01_cn.pdf (1.61 MB, 下载次数: 2) |