主要参考学习资料:B站【普中官方】51单片机手把手教学视频
开发资料下载链接:http://www.prechin.cn/gongsixinwen/208.html
单片机套装:普中STC51单片机开发板A4标准版套餐7
目录
- DS1302时钟芯片介绍
- 硬件设计
- [实验16 DS1302时钟](#实验16 DS1302时钟)
DS1302时钟芯片介绍
DS1302简介

DS1302是达拉斯公司生产的时钟芯片,其具体特点如下:
①具有涓流充电的充电方式,涓流充电通过小电流持续充电来补偿电池的自放电损失,可以有效延长电池使用寿命,保持高饱和度的电量状态。且有主电源和备用电源双电源管脚,避免断电后时钟数据损失。
②具有时钟、日历功能,可以计算2100年之前的时间信息,有闰年调整功能。
③工作电压为3.0~5.5V,在2.0V时电流为300nA,功耗极低。
④具有单字节传送和多字节传送字符组两种读写方式。
⑤具有DIP和SIOC两种封装方式,本实验板载为SIOC封装,体积非常小。
⑥通过三线制SPI串行接口与单片机通信,分别为复位信号线(使能线)、I/O数据线和时钟线,而标准的SPI分别由MISO和MOSI来实现数据的输出和输入。
⑦兼容TTL电平,可以直接跟单片机IO口连接。
⑧工作温度范围为-40℃~85℃。
DS1302八个管脚的功能如下:
名称 | 功能 |
---|---|
VCC2/VCC1 | 主电源/备用电源 |
X1/X2 | 外部晶振管脚,提供晶振源 |
CE | 使能管脚,高电平时芯片工作 |
I/O | 串行数据输入输出引脚 |
SCLK | 时钟引脚 |
DS1302使用
DS1302的使用分为两步:①从中读取时间②将读取到的时间转换到数码管或液晶显示
控制寄存器
控制寄存器用于存放DS1302的控制命令,对DS1302的读写进行控制。
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
1 | RAM/CK | A4 | A3 | A2 | A1 | A0 | RD/WR |
- RAM/CK:设置操作对象,1为RAM,0为内部寄存器。
- A0~A4:操作对象的操作地址位。
- RD/WR:设置读写方向,1为读操作,2为写操作。
以下是内部寄存器和RAM的地址表:


日历/时钟寄存器
DS1302共有12个寄存器,其中7个与日历/时钟功能相关,它们的数据以BCD码格式存入。
BCD码用4位二进制位来表示1位十进制位中的0~9,表示两位数时高八位表示十位,低八位表示个位,在处理二进制数据时通过整除16提取十位,对16取余提取个位。
各个寄存器各个位的功能如下表所示:


特别说明:
- 秒寄存器D7为DS1302运行标志位,0为工作状态,1为停止工作。
- 小时寄存器D7为时间格式位,1为12小时制,0为24小时制,。D5和D6在12小时制下,D5区分AM/PM,D6存储小时的十位0/1;在24小时制下,D5和D6共同存储小时的十位0/1/2。
- 写保护寄存器D7为写保护位,1开启写保护,0关闭写保护。
- 慢充电寄存器控制涓流充电方式,很少用到,不作深入介绍。
读写时序

DS1302的数据传输方式和DS18B20相同,先传低位后传高位。
在读写操作过程中,CE必须保持高电平。读写操作完成后设置CE为低电平,等待下一次操作。
在时钟产生上升沿时数据一位一位由低到高进行写入,先写入控制命令,随后读字节在控制命令发送完成后的第一个下降沿开始读取,而写字节在控制命令发送完成后的第一个上升沿继续写入数据。
在进行写操作前,需先将写保护寄存器的WP位设置为0,写完后再设置为1。写和读的时候数据都以BCD码格式传输。
硬件设计

实验16 DS1302时钟
实现功能:数码管显示电子时钟时分秒,格式为"XX-XX-XX"。
数码管驱动沿用自实验14
DS1302驱动
ds1302.h
c
#ifndef _ds1302_H
#define _ds1302_H
#include "public.h"
//定义复位线、时钟线和数据线管脚
sbit DS1302_RST = P3^5;
sbit DS1302_CLK = P3^6;
sbit DS1302_IO = P3^4;
//定义存储秒分时日月周年的数组
extern u8 gDS1302_TIME[7];
void ds1302_init(void);
void ds1302_read_time(void);
#endif
ds1302.c
c
#include "ds1302.h"
#include "intrins.h"
//存储秒分时日月周年地址读写的命令
u8 gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
u8 gREAD_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
//存储秒分时日月周年的数组
//赋值作为初始化的时间,以2025年星期二3月11日11点45分14秒为例
u8 gDS1302_TIME[7] = {0x14, 0x45, 0x11, 0x11, 0x03, 0x02, 0x25};
//写字节函数
void ds1302_write_byte(u8 addr, u8 dat)
{
//循环控制变量
u8 i = 0;
//复位并将时钟设为低电平
DS1302_RST = 0;
_nop_();
DS1302_CLK = 0;
_nop_();
DS1302_RST = 1;
//由低到高写入地址
for(i=0;i<8;i++)
{
//IO管脚准备好最低位信号
DS1302_IO = addr & 0x01;
//次低位移至最低位
addr >>= 1;
//产生上升沿使信号写入
DS1302_CLK = 1;
_nop_();
DS1302_CLK = 0;
_nop_();
}
//由低到高写入数据
for(i=0;i<8;i++)
{
DS1302_IO = dat & 0x01;
dat >>= 1;
DS1302_CLK = 1;
_nop_();
DS1302_CLK = 0;
_nop_();
}
//拉低复位线等待下次操作
DS1302_RST = 0;
}
//读字节函数
u8 ds1302_read_byte(u8 addr)
{
//循环控制变量
u8 i = 0;
//一位存储变量
u8 temp = 0;
//一字节存储变量
u8 value = 0;
//复位并拉低时钟
DS1302_RST = 0;
_nop_();
DS1302_CLK = 0;
_nop_();
DS1302_RST = 1;
//写入地址
for(i=0;i<8;i++)
{
DS1302_IO = addr & 0x01;
addr >>= 1;
DS1302_CLK = 1;
_nop_();
DS1302_CLK = 0;
_nop_();
}
//由低到高读取数据
for(i=0;i<8;i++)
{
//存储一位
temp = DS1302_IO;
//将字节整体右移一位并将新数据移到最高位后放入
value = (temp<<7) | (value>>1);
DS1302_CLK = 1;
_nop_();
//产生下降沿读取下一位
DS1302_CLK = 0;
_nop_();
}
//拉低复位线等待下次操作
DS1302_RST = 0;
//如果板载P3.4没有外接上拉电阻需要手动产生上升沿脉冲
DS1302_CLK = 1;
_nop_();
DS1302_IO = 0;
_nop_();
DS1302_IO = 1;
_nop_();
//返回读取到的字节
return value;
}
//时间初始化函数
void ds1302_init(void)
{
//循环控制变量
u8 i = 0;
//将写保护寄存器的写保护位置零以关闭写保护
ds1302_write_byte(0x8e, 0x00);
for(i=0;i<7;i++)
{
//将寄存器地址与时间数据一一对应写入
ds1302_write_byte(gWRITE_RTC_ADDR[i], gDS1302_TIME[i]);
}
//打开写保护
ds1302_write_byte(0x8e, 0x00);
}
//时间读取函数
//由于函数不便返回数组,因此直接用开头定义好的数组存储
void ds1302_read_time(void)
{
//循环控制变量
u8 i = 0;
for(i=0;i<7;i++)
{
//将对应寄存器地址的时间数据读取到数组
gDS1302_TIME[i] = ds1302_read_byte(gREAD_RTC_ADDR[i]);
}
}
主函数
c
#include "public.h"
#include "smg.h"
#include "ds1302.h"
void main()
{
//存储数码管显示段码值数组
u8 time_buf[8];
//时间初始化
ds1302_init();
while(1)
{
//读取时间
ds1302_read_time();
//八位数码管依次存储时分秒的十位和个位,中间用杠隔开
//BCD码整除16提取十位,对16取余提取个位
time_buf[0] = gseg_code[gDS1302_TIME[2]/16];
time_buf[1] = gseg_code[gDS1302_TIME[2]%16];
time_buf[2] = 0x40;
time_buf[3] = gseg_code[gDS1302_TIME[1]/16];
time_buf[4] = gseg_code[gDS1302_TIME[1]%16];
time_buf[5] = 0x40;
time_buf[6] = gseg_code[gDS1302_TIME[0]/16];
time_buf[7] = gseg_code[gDS1302_TIME[0]%16];
//显示在数码管上
seg_display(time_buf, 1);
}
}