RTC(Real Time Clock)是实时时钟的简称,可以为我们提供精确的实时时间,其中具有代表性的就是 DS1302 数字时钟芯片,通过单片机与 DS1302 的通信就可以读取 DS1302 中存储的时间信息。利用下面的程序可以实现在 LCD1602 上显示当前的时间(Brust 模式):
ds1302.h:
#ifndef _DS1302_H
#define _DS1302_H
#include "reg52.h"
extern unsigned char *week;
void WriteByte_1302(unsigned char dat);
unsigned char ReadByte_1302(void);
void Write_1302( unsigned char addr , unsigned char dat );
unsigned char Read_1302( unsigned char addr );
void DS1302_Init( unsigned char *InitTime );
void GetCurrentTime( unsigned char *CurrentTime );
void BurstWrite_1302( unsigned char *Time );
void BrustRead_1302( unsigned char *CurrentTime );
void WeekTransform( unsigned char w );
#endif
ds1302.c:
#include "ds1302.h"
sbit CE = P0^5; //位定义DS1302CE、I/O和SCLK引脚
sbit IO = P0^4;
sbit SCLK = P0^3;
unsigned char *week;
//向DS1302写入一个字节的函数
void WriteByte_1302(unsigned char dat)
{
unsigned char i;
bit flag;
for(i=0;i<8;i++)
{
//写入数据时候从低位到高位
flag = dat & 0x01; //待传送的数据的低位存入flag等待传输
IO = flag;
SCLK = 0;
SCLK = 1; //在SCLK上产生一个上升沿,完成一位数据写入
dat = dat >>1; //将dat右移一位,继续写入
}
}
//从DS1302读出一个字节的函数,返回值为一个字节的数据
unsigned char ReadByte_1302(void)
{
unsigned char i,flag,dat;
for(i=0;i<8;i++)
{
SCLK = 1;
SCLK = 0; //在SCLK上产生一个下降沿,完成一位数据的读出
flag = IO; //将读出的一位数据放入flag中
dat = ( dat >>1 ) | ( flag <<7 ); //循环8次,每次都将读出的数据放入最高位
}
return dat; //将读出的数据返回
}
//向固定地址写入单字节数据的函数
void Write_1302( unsigned char addr , unsigned char dat )
{
CE = 1; //拉高CE引脚
WriteByte_1302( addr ); //写入地址数据
WriteByte_1302( dat ); //写入数据
CE = 0; //拉低CE引脚
SCLK = 0; //拉低SCLK,为下一次传输做准备
}
//从固定地址读出数据
unsigned char Read_1302( unsigned char addr )
{
unsigned char dat;
CE = 1; //拉高CE引脚
WriteByte_1302( addr ); //写入地址数据
dat = ReadByte_1302(); //将读出的数据存放到dat中
CE = 0; //拉低CE引脚
return dat;
}
//DS1302初始化,写入初始化时间
void DS1302_Init( unsigned char *InitTime )
{
// unsigned char i;
CE = 0; //拉低CE引脚
SCLK = 0; //拉低SCLK引脚
Write_1302( 0x8E , 0x00 ); //向0x8E寄存器写入0,解除写保护
/****
for( i=0;i<7;i++ )
{
Write_1302( 0x80 + 2*i , InitTime[i] ); //依次写入秒、分、时、日、月、星期、年的数据
}
****/
BurstWrite_1302( InitTime );
}
//获取当前时间
void GetCurrentTime( unsigned char *CurrentTime )
{
//unsigned char i;
CE = 0; //拉低CE引脚
SCLK = 0; //拉低SCLK引脚
/****
for( i=0;i<7;i++ )
{
*CurrentTime = Read_1302( 0x81 + 2*i ); //依次读取秒、分、时、日、月、星期、年的数据
CurrentTime ++; //地址+1,存储数据
}
****/
BrustRead_1302( CurrentTime );
}
/****下面是突发模式下的读写函数****/
//突发写数据函数
void BurstWrite_1302( unsigned char *Time )
{
unsigned char i;
CE = 1; //拉高CE引脚
WriteByte_1302(0xBE); //突发模式专用写指令
for( i=0;i<7;i++ )
{
WriteByte_1302(Time[i]); //向1302写入时间数据
}
WriteByte_1302(0); //向第八个寄存器写入0,防止出错
CE = 0; //拉低CE引脚
}
//突发读数据函数
void BrustRead_1302( unsigned char *CurrentTime )
{
unsigned char i;
CE = 1; //拉高CE引脚
WriteByte_1302(0xBF); //突发模式专用写指令
for( i=0;i<7;i++ )
{
*CurrentTime = ReadByte_1302(); //读取一个字节的数据
CurrentTime ++; //地址+1
}
CE = 0; //拉低CE引脚
}
void WeekTransform( unsigned char w )
{
switch( w )
{
case 1:week = "Mon";break;
case 2:week = "Tue";break;
case 3:week = "Wed";break;
case 4:week = "Thu";break;
case 5:week = "Fri";break;
case 6:week = "Sat";break;
case 7:week = "Sun";break;
default: week = "error";break;
}
}
main.c:
#include "reg52.h"
#include "intrins.h"
#include "stdio.h"
#include "LCD1602.h"
#include "ds1302.h"
bit flag; //定时500ms标志位
//定义初始时间,秒、分、时、日、月、星期、年
unsigned char code InitTime[7] = { 0x55,0x15,0x08,0x21,0x05,0x04,0x21 };
//存储获取时间的数组
unsigned char CurrentTime[7];
//显示字符存储变量
unsigned char DisplayString[20];
void Timer0_Init(void)
{
TMOD |= 0x01; //配置定时器工作模式
TH0 = 0x4C;
TL0 = 0x00; //定时50ms初值
TR0 = 1;
ET0 = 1;
EA = 1; //启动定时器,开定时器中断和总中断
}
void main()
{
LCD_Init(); //初始化LCD1602
Timer0_Init(); //初始化定时器
DS1302_Init(InitTime); //初始化时钟
while(1)
{
if( flag ) //flag=1时,即500ms定时时间到时
{
flag = 0; //标志位清零
GetCurrentTime(CurrentTime); //获取当前时间
DisplayString[0] = '2';DisplayString[1] = '0';
//取出年的十位、个位,然后转换成对应数字的ASCII码
DisplayString[2] = (CurrentTime[6]>>4)+'0'; DisplayString[3] = (CurrentTime[6]&0x0F)+'0';
DisplayString[4] = '-';
//取出月的十位、个位,然后转换成对应数字的ASCII码
DisplayString[5] = (CurrentTime[4]>>4)+'0'; DisplayString[6] = (CurrentTime[4]&0x0F)+'0';
DisplayString[7] = '-';
//取出日的十位、个位,然后转换成对应数字的ASCII码
DisplayString[8] = (CurrentTime[3]>>4)+'0'; DisplayString[9] = (CurrentTime[3]&0x0F)+'0';
DisplayString[10] = '0'; //结束
//取出时的十位、个位,然后转换成对应数字的ASCII码
DisplayString[11] = (CurrentTime[2]>>4)+'0'; DisplayString[12] = (CurrentTime[2]&0x0F)+'0';
DisplayString[13] = ':';
//取出分的十位、个位,然后转换成对应数字的ASCII码
DisplayString[14] = (CurrentTime[1]>>4)+'0'; DisplayString[15] = (CurrentTime[1]&0x0F)+'0';
DisplayString[16] = ':';
//取出秒的十位、个位,然后转换成对应数字的ASCII码
DisplayString[17] = (CurrentTime[0]>>4)+'0'; DisplayString[18] = (CurrentTime[0]&0x0F)+'0';
DisplayString[19] = '0'; //结束
WeekTransform( ( (CurrentTime[5]&0x0F) ) ); //将星期转换成对应的英文
LCD_WriteString(1,2,DisplayString);
LCD_WriteString(2,2,DisplayString+11);
LCD_WriteString(2,12,week); //分两行显示
}
}
}
void Timer0(void) interrupt 1 using 1
{
static unsigned int i;
TH0 = 0x4C;
TL0 = 0x00; //重新赋初值
i++;
if( i == 10 ) //10次50ms就到了500ms
{
i=0;
flag = 1; //500ms定时到,标志位置1,由main函数置0
}
}