圣源电子制作
标题:
DS1302 带RAM的实时时钟模块-掉电时间保持时钟-制作-DIY
[打印本页]
作者:
sydz
时间:
2012-4-21 15:20
标题:
DS1302 带RAM的实时时钟模块-掉电时间保持时钟-制作-DIY
DS1302的结构、工作原理及其在实时显示时间中的应用。它可以对年、月、日、周、日、时、分、秒进行计时,且具有闰年补偿等多种功能。给出DS1302在读写中的C51程序及流程图,以及在调试过程中的注意事项。
DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的
时钟信号
或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后备电源双电源引脚,同时提供了对后备电源进行涓细电流充电的能力。
引脚功能及结构
DS1302的引脚排列,其中Vcc1为后备电源,VCC2为主电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。X1和X2是振荡源,外接32.768kHz晶振。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc>2.0V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。I/O为串行数据输入输出端(双向),后面有详细说明。SCLK为时钟输入端。 下图为DS1302的引脚功能图:
(, 下载次数: 87)
上传
点击文件名下载附件
DS1302的控制字节
DS1302 的控制字如图2所示。控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出。
(, 下载次数: 91)
上传
点击文件名下载附件
数据输入输出(I/O)
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
DS1302的寄存器
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见表1。
此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。 DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
DS1302实时显示时间的软硬件
DS1302与CPU的连接需要三条线,即SCLK(7)、I/O(6)、RST(5)。图3示出DS1302与89C2051的连接图,其中,时钟的显示用LCD。
(, 下载次数: 91)
上传
点击文件名下载附件
简介
电源:直流5V
带有反向二极管保护
带有记忆电池
带LED指示
RAM的实时时钟模块
掉电时间保持时钟
可以对年、月、日、周、日、时、分、秒进行计时,且具有闰年补偿等多种功能
DS1302与CPU的连接需要三条线,即SCLK(7)、I/O(6)、RST(5)
C例程,二楼 查看!!!
(, 下载次数: 96)
上传
点击文件名下载附件
模块输出引脚定义!!
(, 下载次数: 93)
上传
点击文件名下载附件
散件全家福!!
(, 下载次数: 92)
上传
点击文件名下载附件
(, 下载次数: 93)
上传
点击文件名下载附件
(, 下载次数: 96)
上传
点击文件名下载附件
(, 下载次数: 99)
上传
点击文件名下载附件
原理图
(, 下载次数: 101)
上传
点击文件名下载附件
配件表
R1
4.7K
LED
LED
D1
1N4148
BT1
电池座
U1
DS1302
P1
5P插针
Y1
32.768k/6P
电路板
点击
进入购买
作者:
sydz
时间:
2012-4-21 15:25
DS1302驱动程序分析图
(, 下载次数: 95)
上传
点击文件名下载附件
C程序 C51例子
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
uchar count_10ms; //定义10ms计数器
sbit K1 = P3^2; //定义K1键
sbit K2 = P3^3; //定义K2键
sbit K3 = P3^4; //定义K3键
sbit K4 = P3^5; //定义K4键
sbit BEEP=P3^7; //定义蜂鸣器
sbit reset = P1^2;
sbit sclk = P1^0;
sbit io = P1^1;
sbit LCD_RS=P2^0;
sbit LCD_RW=P2^1 ;
sbit LCD_EN=P2^2;
bit K1_FLAG=0; //定义按键标志位,当按下K1键时,该位置1,K1键未按下时,该位为0。
uchar code line1_data[] = {"---LCD Clcok---"}; //定义第1行显示的字符
uchar code line2_data[] = {"****"}; //定义第2行显示的字符
uchar disp_buf[8] ={0x00}; //定义显示缓冲区
uchar time_buf[7] ={0,0,0x12,0,0,0,0}; //DS1302时间缓冲区,存放秒、分、时、日、月、星期、年
uchar temp [2]={0}; //用来存放设置时的小时、分钟的中间值
/********以下是函数声明********/
void Delay_ms(uint xms) ;
bit lcd_busy();
void lcd_wcmd(uchar cmd);
void lcd_wdat(uchar dat) ;
void lcd_clr() ;
void lcd_init() ;
void write_byte(uchar inbyte); //写一字节数据函数声明
uchar read_byte(); //读一字节数据函数声明
void write_ds1302(uchar cmd,uchar indata); //写DS1302函数声明
uchar read_ds1302(uchar addr); //读DS1302函数声明
void set_ds1302(uchar addr,uchar *p,uchar n); //设置DS1302初始时间函数声明
void get_ds1302(uchar addr,uchar *p,uchar n); //读当前时间函数声明
void init_ds1302(); //DS1302初始化函数声明
/********以下是延时函数********/
void Delay_ms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--) //i=xms即延时约xms毫秒
for(j=110;j>0;j--);
}
/********以下是LCD忙碌检查函数********/
bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result = (bit)(P0&0x80);
LCD_EN = 0;
return result;
}
/********以下是写指令寄存器IR函数********/
void lcd_wcmd(uchar cmd)
{
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 0;
}
/********以下是写寄存器DR函数********/
void lcd_wdat(uchar dat)
{
while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 0;
}
/********以下是LCD清屏函数********/
void lcd_clr()
{
lcd_wcmd(0x01); //清除LCD的显示内容
Delay_ms(5);
}
/********以下是LCD初始化函数********/
void lcd_init()
{
Delay_ms(15); //等待LCD电源稳定
lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据
Delay_ms(5);
lcd_wcmd(0x38);
Delay_ms(5);
lcd_wcmd(0x38);
Delay_ms(5);
lcd_wcmd(0x0c); //显示开,关光标
Delay_ms(5);
lcd_wcmd(0x06); //移动光标
Delay_ms(5);
lcd_wcmd(0x01); //清除LCD的显示内容
Delay_ms(5);
}
/********以下是写一字节数据函数********/
void write_byte(uchar inbyte)
{
uchar i;
for(i=0;i<8;i++)
{
sclk=0; //写时低电平改变数据
if(inbyte&0x01)
io=1;
else
io=0;
sclk=1; //高电平把数据写入DS1302
_nop_();
inbyte=inbyte>>1;
}
}
/********以下是读一字节数据函数********/
uchar read_byte()
{
uchar i,temp=0;
io=1;
for(i=0;i<7;i++)
{
sclk=0;
if(io==1)
temp=temp|0x80;
else
temp=temp&0x7f;
sclk=1; //产生下跳沿
temp=temp>>1;
}
return (temp);
}
/********写DS1302函数, 往DS1302的某个地址写入数据 ********/
void write_ds1302(uchar cmd,uchar indata)
{
sclk=0;
reset=1;
write_byte(cmd);
write_byte(indata);
sclk=0;
reset=0;
}
/********读DS1302函数,读DS1302某地址的的数据********/
uchar read_ds1302(uchar addr)
{
uchar backdata;
sclk=0;
reset=1;
write_byte(addr); //先写地址
backdata=read_byte(); //然后读数据
sclk=0;
reset=0;
return (backdata);
}
/********设置初始时间函数********
void set_ds1302(uchar addr,uchar *p,uchar n)
{
write_ds1302(0x8e,0x00); //写控制字,允许写操作
for(;n>0;n--)
{
write_ds1302(addr,*p);
p++;
addr=addr+2;
}
write_ds1302(0x8e,0x80); //写保护,不允许写
}
********读取当前时间函数********
void get_ds1302(uchar addr,uchar *p,uchar n)
{
for(;n>0;n--)
{
*p=read_ds1302(addr);
p++;
addr=addr+2;
}
}
********初始化DS1302函数********/
void init_ds1302()
{
reset=0;
sclk=0;
write_ds1302(0x80,0x00); //写秒寄存器
write_ds1302(0x90,0xab); //写充电器
write_ds1302(0x8e,0x80); //写保护控制字,禁止写
}
/*********以下是蜂鸣器响一声函数********/
void beep()
{
BEEP=0; //蜂鸣器响
Delay_ms(100);
BEEP=1; //关闭蜂鸣器
Delay_ms(100);
}
/********以下是转换函数,负责将走时数据转换为适合LCD显示的数据********/
void LCD_conv (uchar in1,in2,in3 )
//形参in1、in2、in3接收实参time_buf[2]、time_buf[1]、time_buf[0]传来的小时、分钟、秒数据
{
disp_buf[0]=in1/10+0x30; //小时十位数据
disp_buf[1]=in1%10+0x30; //小时个位数据
disp_buf[2]=in2/10+0x30; //分钟十位数据
disp_buf[3]=in2%10+0x30; //分钟个位数据
disp_buf[4]=in3/10+0x30; //秒十位数据
disp_buf[5]=in3%10+0x30; //秒个位数据
}
/********以下是LCD显示函数,负责将函数LCD_conv转换后的数据显示在LCD上********/
void LCD_disp ()
{
lcd_wcmd(0x44 | 0x80); //从第2行第4列开始显示
lcd_wdat(disp_buf[0]); //显示小时十位
lcd_wdat(disp_buf[1]); //显示小时个位
lcd_wdat(0x3a); //显示':'
lcd_wdat(disp_buf[2]); //显示分钟十位
lcd_wdat(disp_buf[3]); //显示分钟个位
lcd_wdat(0x3a); //显示':'
lcd_wdat(disp_buf[4]); //显示秒十位
lcd_wdat(disp_buf[5]); //显示秒个位
}
/********以下是按键处理函数********/
void KeyProcess()
{
uchar min16,hour16; //定义16进制的分钟和小时变量
write_ds1302(0x8e,0x00); //DS1302写保护控制字,允许写
write_ds1302(0x80,0x80); //时钟停止运行
if(K2==0) //K2键用来对小时进行加1调整
{
Delay_ms(10); //延时去抖
if(K2==0)
{
while(!K2); //等待K2键释放
beep();
time_buf[2]=time_buf[2]+1; //小时加1
if(time_buf[2]==24) time_buf[2]=0; //当变成24时初始化为0
hour16=time_buf[2]/10*16+time_buf[2]%10; //将所得的小时数据转变成16进制数据
write_ds1302(0x84,hour16); //将调整后的小时数据写入DS1302
}
}
if(K3==0) // K3键用来对分钟进行加1调整
{
Delay_ms(10); //延时去抖
if(K3==0)
{
while(!K3); //等待K3键释放
beep();
time_buf[1]=time_buf[1]+1; //分钟加1
if(time_buf[1]==60) time_buf[1]=0; //当分钟加到60时初始化为0
min16=time_buf[1]/10*16+time_buf[1]%10; //将所得的分钟数据转变成16进制数据
write_ds1302(0x82,min16); //将调整后的分钟数据写入DS1302
}
}
if(K4==0) //K4键是确认键
{
Delay_ms(10); //延时去抖
if(K4==0)
{
while(!K4); //等待K4键释放
beep();
write_ds1302(0x80,0x00); //调整完毕后,启动时钟运行
write_ds1302(0x8e,0x80); //写保护控制字,禁止写
K1_FLAG=0; //将K1键按下标志位清0
}
}
}
/********以下是读取时间函数,负责读取当前的时间,并将读取到的时间转换为10进制数********/
void get_time()
{
uchar sec,min,hour; //定义秒、分和小时变量
write_ds1302(0x8e,0x00); //控制命令,WP=0,允许写操作
write_ds1302(0x90,0xab); //涓流充电控制
sec=read_ds1302(0x81); //读取秒
min=read_ds1302(0x83); //读取分
hour=read_ds1302(0x85); //读取时
time_buf[0]=sec/16*10+sec%16; //将读取到的16进制数转化为10进制
time_buf[1]=min/16*10+min%16; //将读取到的16进制数转化为10进制
time_buf[2]=hour/16*10+hour%16; //将读取到的16进制数转化为10进制
}
/********以下是主函数********/
void main(void)
{
uchar i;
P0 = 0xff;
P2 = 0xff;
lcd_init(); //LCD初始化函数(在LCD驱动程序软件包中)
lcd_clr(); //清屏函数(在LCD驱动程序软件包中)
lcd_wcmd(0x00|0x80); //设置显示位置为第1行第0列
i = 0;
while(line1_data[i] != '\0') //在第1行显示"---LCD Clcok---"
{
lcd_wdat(line1_data[i]); //显示第1行字符
i++; //指向下一字符
}
lcd_wcmd(0x40|0x80); //设置显示位置为第2行第0列
i = 0;
while(line2_data[i] != '\0') //在第2行0~3列显示"****"
{
lcd_wdat(line2_data[i]); //显示第2行字符
i++; //指向下一字符
}
lcd_wcmd(0x4c|0x80); //设置显示位置为第2行第12列
i = 0;
while(line2_data[i] != '\0') //在第2行12列之后显示"****"
{
lcd_wdat(line2_data[i]); //显示第2行字符
i++; //指向下一字符
}
init_ds1302(); //DS1302初始化
while(1)
{
get_time(); //读取当前时间
if(K1==0) //若K1键按下
{
Delay_ms(10); //延时10ms去抖
if(K1==0)
{
while(!K1); //等待K1键释放
beep(); //蜂鸣器响一声
K1_FLAG=1; //K1键标志位置1,以便进行时钟调整
}
}
if(K1_FLAG==1)KeyProcess(); //若K1_FLAG为1,则进行走时调整
LCD_conv(time_buf[2],time_buf[1],time_buf[0]); //将DS1302的小时/分/秒传送到转换函数
LCD_disp(); //调LCD显示函数,显示小时、分和秒
}
}
复制代码
欢迎光临 圣源电子制作 (https://sydz.syyyd.com/)
Powered by Discuz! X3.4