7.1 DS1302时钟简单分析
★ 实时时钟计算年、月、日、时、分、秒、星期,直到 2100 年,并有闰年调节功能
★ 31 x 8 位 通用暂存 RAM
★ 串行输入输出使管脚数最少
★ 2.0V 至 5.5V 宽电压范围操作
★ 在 2.0V 时工作电流小于 300nA
★ 读写时钟或 RAM 数据时有单字节或多字节(脉冲串模式)数据传送方式
★ 8 管脚 DIP 封装或可选的 8 管脚表面安装 SO 封装
★ 简单的 3 线接口
★ 与 TTL 兼容 (VCC = 5V)
★ 可选的工业温度范围:-40°C to +85°C
★ 与 DS1202 兼容
DS1302 涓流充电计时芯片包含一个实时时钟/日历和 31 字节的静态 RAM.通过简单的串行接口与微处理器通讯.这个实时时钟/日历提供年月日,时分秒信息.对于少于 31 天的月份月末会自动调整,还有闰年校正.由于有一个 AM/PM 指示器,时钟可以工作在 12 小时制或者 24小时制。使用同步串行通讯简化了 DS1302 与微处理器的接口。与时钟/RAM 通讯只需要三根线: CE,I/O (数据线), and SCLK (串行时钟). 数据输出输入时钟/RAM 一次1字节或者在脉冲串中多管脚定义
DS1302涓流充电计时芯片达 31 字节. DS1302 被设计工作在非常低的电能下,在低于 1μW 时还能保持数据和时钟信息.DS1302 是 DS1202 的后继者. 除了 DS1202 的基本计时功能以外, DS1302 有额外特点比如,双管脚主电源和备用电源,可编程涓流充电器 VCC1,还附加 7 字节的暂存器.
电路上面我们简单分析一下,
- C4和R9构成RC滤波电路,可以提供稳定的电源,
- X1为32.768KHZ
- 电容C6、C8最好是22-30pF
- RC就是我们开发板的电池,这里我们在设计时没有加上二极管,这里最好可以加上一个二极管,防止电流反灌到电池,可以起到保护电路的作用。
- R10、R11、R14是上拉电阻可以提供更稳定的信号,防止单片机无法拉高。
7.2 DS1302驱动程序
ds1302.c
/**********************************
包含头文件
**********************************/
#include "ds1302.h"
/**********************************
变量定义
**********************************/
//初始时间2023年9月5号15点15分30秒 星期二
char time_buf[8] = {0x20,0x23,0x09,0x05,0x15,0x15,0x30,0x02};
/****
*******向DS1302写入一字节数据
*****/
void ds1302_write_byte(uchar addr, uchar d)
{
uchar i;
DS1302_RST=0;
_nop_();
DS1302_SCK=0;//CLK低电平
_nop_();
DS1302_RST=1;//RST由低到高变化
_nop_();
//写入目标地址:addr
addr = addr & 0xFE; //最低位置零,寄存器0位为0时写,为1时读
for(i = 0; i < 8; i ++)
{
if (addr & 0x01)
{
DS1302_DAT=1;
}
else
{
DS1302_DAT=0;
}
DS1302_SCK=1; //产生时钟
DS1302_SCK=0;
addr = addr >> 1;
}
//写入数据:d
for(i = 0; i < 8; i ++)
{
if (d & 0x01)
{
DS1302_DAT=1;
}
else
{
DS1302_DAT=0;
}
DS1302_SCK=1; //产生时钟
DS1302_SCK=0;
d = d >> 1;
}
DS1302_RST=0; //停止DS1302总线
_nop_();
}
/****
*******从DS1302读出一字节数据
*****/
uchar ds1302_read_byte(uchar addr)
{
uchar i,temp;
DS1302_RST=0;
_nop_();
DS1302_SCK=0;//CLK低电平
_nop_();
DS1302_RST=1;//RST由低到高变化
_nop_();
//写入目标地址:addr
addr = addr | 0x01; //最低位置高,寄存器0位为0时写,为1时读
for (i = 0; i < 8; i ++)
{
if (addr & 0x01)
{
DS1302_DAT=1;
}
else
{
DS1302_DAT=0;
}
DS1302_SCK=1;
DS1302_SCK=0;
addr = addr >> 1;
}
//输出数据:temp
for (i = 0; i < 8; i ++)
{
temp = temp >> 1;
if (DS1302_DAT)
{
temp |= 0x80;
}
else
{
temp &= 0x7F;
}
DS1302_SCK=1;
DS1302_SCK=0;
}
DS1302_RST=0; //停止DS1302总线
_nop_();
DS1302_SCK=1;
return temp;
}
/****
*******向DS302写入时钟数据
*****/
void ds1302_write_time(void)
{
ds1302_write_byte(ds1302_control_add,0x00); //关闭写保护
ds1302_write_byte(ds1302_sec_add,0x80); //暂停时钟
ds1302_write_byte(ds1302_charger_add,0xa9); //涓流充电
ds1302_write_byte(ds1302_year_add,time_buf[1]); //年
ds1302_write_byte(ds1302_month_add,time_buf[2]); //月
ds1302_write_byte(ds1302_date_add,time_buf[3]); //日
ds1302_write_byte(ds1302_hr_add,time_buf[4]); //时
ds1302_write_byte(ds1302_min_add,time_buf[5]); //分
ds1302_write_byte(ds1302_sec_add,time_buf[6]); //秒
ds1302_write_byte(ds1302_day_add,time_buf[7]); //周
ds1302_write_byte(ds1302_control_add,0x80); //打开写保护
}
/****
*******从DS302读出时钟数据
*****/
void ds1302_read_time(void)
{
time_buf[1]=ds1302_read_byte(ds1302_year_add); //年
time_buf[2]=ds1302_read_byte(ds1302_month_add); //月
time_buf[3]=ds1302_read_byte(ds1302_date_add); //日
time_buf[4]=ds1302_read_byte(ds1302_hr_add); //时
time_buf[5]=ds1302_read_byte(ds1302_min_add); //分
time_buf[6]=(ds1302_read_byte(ds1302_sec_add))&0x7f; //秒,屏蔽秒的第7位,避免超出59
time_buf[7]=ds1302_read_byte(ds1302_day_add); //周
}
ds1302.h
#ifndef _DS1302_H_
#define _DS1302_H_
/**********************************
包含头文件
**********************************/
#include "main.h"
/**********************************
PIN口定义
**********************************/
sbit DS1302_RST=P1^4; //ds1302复位引脚P1.4
sbit DS1302_DAT=P1^3; //ds1302数据引脚P1.5
sbit DS1302_SCK=P1^2; //ds1302时钟引脚P1.6
/**********************************
重定义关键词
**********************************/
#define ds1302_sec_add 0x80 //秒数据地址
#define ds1302_min_add 0x82 //分数据地址
#define ds1302_hr_add 0x84 //时数据地址
#define ds1302_date_add 0x86 //日数据地址
#define ds1302_month_add 0x88 //月数据地址
#define ds1302_day_add 0x8a //星期数据地址
#define ds1302_year_add 0x8c //年数据地址
#define ds1302_control_add 0x8e //控制数据地址
#define ds1302_charger_add 0x90 //涓流充电地址
#define ds1302_clkburst_add 0xbe //分页地址
/**********************************
变量定义
**********************************/
extern char time_buf[8];
/**********************************
函数声明
**********************************/
void ds1302_write_time(void); //向DS302写入时钟数据
void ds1302_read_time(void); //从DS302读出时钟数据
#endif
main.c
/**********************************
包含头文件
**********************************/
#include "main.h"
#include "lcd1602.h"
#include "ds1302.h"
/**********************************
变量定义
**********************************/
uchar dis_buf[20];
uint nian;
uint yue,ri,shi,fen,miao,xingqi;
/**********************************
函数名: usleep
传递参数: ms
返回参数: 无
函数作用: 延时1ms函数
**********************************/
void usleep(unsigned int ms)
{
unsigned int m,n;
for(m=ms;m>0;m--)
for(n=110;n>0;n--);
}
/**********************************
函数名: main
传递参数:无
返回参数:无
函数作用:主函数
**********************************/
void main(void)
{
lcd1602_init(); //LCD1602初始化
lcd1602_clear(); //清屏
// ds1302_write_time(); //预设初始时间
while(1)
{
ds1302_read_time();
nian = time_buf[1]/0x10*10 + time_buf[1]%0x10;
yue = time_buf[2]/0x10*10 + time_buf[2]%0x10;
ri = time_buf[3]/0x10*10 + time_buf[3]%0x10;
shi = time_buf[4]/0x10*10 + time_buf[4]%0x10;
fen = time_buf[5]/0x10*10 + time_buf[5]%0x10;
miao = time_buf[6]/0x10*10 + time_buf[6]%0x10;
xingqi = time_buf[7]/0x10*10 + time_buf[7]%0x10;
sprintf(dis_buf,"20%.2d-%.2d-%.2d",nian,yue,ri);
lcd1602_show_string(0,0,dis_buf);
sprintf(dis_buf,"%.2d:%.2d:%.2d",shi,fen,miao);
lcd1602_show_string(4,1,dis_buf);
if(xingqi == 1)
{
lcd1602_show_string(12,0,"Mon "); //显示星期一英文缩写
}
else if(xingqi == 2)
{
lcd1602_show_string(12,0,"Tues"); //显示星期二英文缩写
}
else if(xingqi == 3)
{
lcd1602_show_string(12,0,"Wed "); //显示星期三英文缩写
}
else if(xingqi == 4)
{
lcd1602_show_string(12,0,"Thur"); //显示星期四英文缩写
}
else if(xingqi == 5)
{
lcd1602_show_string(12,0,"Fri "); //显示星期五英文缩写
}
else if(xingqi == 6)
{
lcd1602_show_string(12,0,"Sat "); //显示星期六英文缩写
}
else
{
lcd1602_show_string(12,0,"Sun "); //显示星期天英文缩写
}
}
}
主题授权提示:请在后台主题设置-主题授权-激活主题的正版授权,授权购买:RiTheme官网