简介
DS1302 是 DALLAS 公司推出的涓流充电时钟芯片内含有一个实时时钟/日历和 31 字节静态 RAM 通过简 单的串行接口与单片机进行通信 实时时钟/日历电路提供秒、分、时、日、日期、月和年的信息每月的天数和闰年的天数可自动调整,时钟操作可通过 AM/PM 指示决定采用 24 或 12 小时格式。DS1302 与单片机之间能简单地采用同步串行的方式进行通信。时钟/RAM 的读/写数据以一个字节或多达 31 个字节的字符组方式通信。DS1302 是由DS1202 改进而来增加了以下的特性: 双电源管脚用于主电源和备份电源供应, VCC为可编程涓流充电电源附加七个字节存储器。它广泛应用于电话、传真、便携式仪器以及电池供电的仪器仪表等产品领域。
性能特征
(1)实时时钟具有能计算 2100 年之前的秒分时日日期星期月年的能力还有闰年调整的能力。
(2)31×8 位暂存数据存储 RAM
(3)串行 I/O 口方式使得管脚数量最少
(4)宽范围工作电压 2.0 5.5V
(5)工作电流 2.0V 时,小于 300nA
(6)读/写时钟或 RAM 数据时,有两种传送方式:单字节传送和多字节传送(字符组方式)
(7)简单 3 线接口:RES(复位)、I/O(数据),SCLK(串行时钟)
(8)与TTL兼容Vcc=5V
(9)可选工业级温度范围:-40+85℃
原理图
命令字节
有效位 | 功能 |
---|---|
位7 | 必须为逻辑1;如为0,将禁止写入DS1302 |
位6 | 逻辑0:指定时钟/日历数据 逻辑1:指定RAM数据 |
位1-5 | 指定输入或输出寄存器 |
位0 | 逻辑0:写操作(输入)逻辑1:读操作(输出) |
注意:命令字节总是从LSB(位0)开始输入
复位和时钟控制
驱动RST输入高启动所有数据传输。RST输入有以下两个功能:
其一,RST打开控制逻辑,允许访问地址/命令序列的移位寄存器。
其二,RST信号提供终止单字节或多字节数据传输的方式。
时钟周期是一个上升沿和下降沿的序列。对于数据输入,数据必须在时钟上升沿期间有效,数据位在时钟下降沿上输出。如果RST输入低,所有数据传输终止,I/0引脚进入高阻抗状态。如下图显示了数据传输。在上电时,RST必须为逻辑0,直到VCC>2.0V。另外,当RST被驱动到逻辑1状态时,SCLK必须处于逻辑0。
数据输入
在输入写命令字节的8个SCLK周期之后,在下一个8个SCLK周期的上升沿上输入一个数据字节。如果无意中发生额外的SCLK周期,则忽略它们。数据从0位开始输入。
数据输出
在输入读命令字节的8个SCLK周期之后,在接下来的8个SCLK周期的下降沿上输出一个数据字节。注意,要传输的第一个数据位发生在写入命令字节的最后- -位之后的第一个下降沿上。额外的SCLK周期重新传输数据字节,如果他们无意中发生,只要RST保持高。此操作允许连续突发模式读取能力。此外,I/O引脚在SCLK的每个上升沿上都是三态。数据从0位开始输出。
突发模态
突发模式可以指定时钟/日历或RAM寄存器通过寻址位置31小数(地址/命令位1到5逻辑1)。和以前一样,第6位指定时钟或RAM,第0位指定读或写。时钟/日历寄存器中的位置9到31或RAM寄存器中的位置31没有数据存储容量。以突发方式读写,从地址0的0位开始。
当以突发模式写入时钟寄存器时,必须先写入前8个寄存器,以便传输数据。但是,当以突发模式写入RAM时,没有必要为数据传输写入所有31个字节。无论是否写入所有31个字节,写入的每个字节都将被传输到RAM中。
寄存器地址
寄存器1:Bit7被定义为时钟停止(CH)标志。当该位设置为逻辑1时,时钟振荡器停止,DS1302被置于低功耗待机模式。当这个位写入逻辑0时,时钟将启动。Bit4-Bit6代表秒的十位,Bit0-Bit3则表示秒的个位。
寄存器2:Bit7未使用,Bit4-Bit6代表分钟的十位,则Bit0-Bit3表示分钟的个位。
寄存器3:在12或24小时模式下,Bit7为逻辑1时代表12小时模式,为逻辑0时代表24小时模式;Bit6固定为0,在24小时模式下,Bit5和Bit4一起代表小时的十位,在12小时模式下,Bit5为逻辑0时,代表AM,为逻辑1时代表PM;Bit0-Bit3表示小时的个位。
寄存器4:Bit6和Bit7固定为0,Bit4和Bit5代表日期的十位,则Bit0-Bit3代表日期的个位。
寄存器5:Bit5-Bit7固定为0,Bit4代表月份的十位,Bit0-Bit3则表示月份的个位。
寄存器6:Bit3-Bit7固定为0,Bit0-Bit2表示星期的个位。
寄存器7:Bit4-Bit7表示年的十位,Bit0-Bit3代表年的个位。
寄存器8:Bit7位是写保护位,前7位(Bit0-B it6)被强制为0,读取时总是读0。当Bit7为逻辑1时,写保护位阻止对任何其他寄存器的写操作,所以在对时钟或RAM进行任何写操作之前,Bit7必须为0。
时序图
读取数据传输
写入数据传输
接线图
STM32 | DS1302 | OLED |
---|---|---|
5V | VCC | VCC |
GND | GND | GND |
PA7 | CLK | - |
PA6 | SDA | - |
PA5 | RST | - |
PB11 | - | SCL |
PB10 | - | SDA |
代码
DS1302.c (部分代码)
void DS1302_Init(void)// 写入时钟数据
{
DS1302_wirte_rig(0x8e,0x00);//关闭写保护
DS1302_wirte_rig(0x80,0x00);//seconds00秒
DS1302_wirte_rig(0x82,0x30);//minutes30分
DS1302_wirte_rig(0x84,0x15);//hours15时
DS1302_wirte_rig(0x86,0x17);//date17日
DS1302_wirte_rig(0x88,0x03);//months03月
DS1302_wirte_rig(0x8a,0x01);//days星期一
DS1302_wirte_rig(0x8c,0x25);//year2025年
DS1302_wirte_rig(0x8e,0x80);//开启写保护
}
初始化DS1302,初始化时钟时间为“2025年3月17日15时30分,星期一”。确保后续时钟正常运行计时
void DS1302_read_time(void)
{
read_time[0]=DS1302_read_rig(0x81);//读秒
read_time[1]=DS1302_read_rig(0x83);//读分
read_time[2]=DS1302_read_rig(0x85);//读时
read_time[3]=DS1302_read_rig(0x87);//读日
read_time[4]=DS1302_read_rig(0x89);//读月
read_time[5]=DS1302_read_rig(0x8B);//读星期
read_time[6]=DS1302_read_rig(0x8D);//读年
}
读取实时时间,按手册的寄存器说明,读取秒、分、时、日、月、星期和年,以便输出显示。
main.c
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "ds1302.h"
#include "timer.h"
char realTime[50];
int main(void)
{
u16 ii=0;
delay_init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
DS1302_GPIO_Init();
DS1302_Init(); //时间设置
DS1302_read_realTime(); //读取实时数据
LED_Init();
USART1_Config();//串口初始化
OLED_Init(); //屏幕初始化
OLED_Clear();
while(1)
{
DS1302_read_realTime(); //读取此时时刻
printf("%d ",TimeData.year);
printf("年");
printf("%d ",TimeData.month);
printf("月");
printf("%d ",TimeData.day);
printf("日");
printf("%d ",TimeData.hour);
printf("时");
printf("%d ",TimeData.minute);
printf("分");
printf("%d ",TimeData.second);
printf("秒");
printf("星期");
printf("%d ",TimeData.week);
sprintf(realTime,"%d ",TimeData.year);
OLED_ShowString(8,0,realTime,16,1);
OLED_ShowChinese(40,0,9,16,1);//年
sprintf(realTime,"%d ",TimeData.month);
OLED_ShowString(56,0,realTime,16,1);
OLED_ShowChinese(72,0,10,16,1);//月
sprintf(realTime,"%d ",TimeData.day);
OLED_ShowString(88,0,realTime,16,1);
OLED_ShowChinese(104,0,11,16,1);//日
sprintf(realTime,"%d ",TimeData.hour);
OLED_ShowString(56,16,realTime,16,1);//时
OLED_ShowString(72,16,"-",16,1);
sprintf(realTime,"%d ",TimeData.minute);
OLED_ShowString(80,16,realTime,16,1);//分
OLED_ShowString(96,16,"-",16,1);
sprintf(realTime,"%d ",TimeData.second);
OLED_ShowString(104,16,realTime,16,1); //秒
OLED_ShowChinese(0,16,0,16,1);//星期
OLED_ShowChinese(16,16,1,16,1);
switch(TimeData.week)
{
case 1:
{
OLED_ShowChinese(32,16,2,16,1);
}break;
case 2:
{
OLED_ShowChinese(32,16,3,16,1);
}break;
case 3:
{
OLED_ShowChinese(32,16,4,16,1);
}break;
case 4:
{
OLED_ShowChinese(32,16,5,16,1);
}break;
case 5:
{
OLED_ShowChinese(32,16,6,16,1);
}break;
case 6:
{
OLED_ShowChinese(32,16,7,16,1);
}break;
case 7:
{
OLED_ShowChinese(32,16,8,16,1);
}
}
OLED_Refresh();
}
}
读取实时时间数据,初始化串口和屏幕,把时间数据打印到串口上以及显示到OLED上。
结果
串口打印时间:
OLED显示时间:
总结
以上是基于STM32驱动DS1302时钟模块的实验代码。在这个代码中,主要实现了DS1302模块的初始化,读取时间和日期以及星期设置显示,并给出了相应的函数实现。在实际使用中大家可以添加一些其他的功能,比如桌面电子时钟,定时闹铃(报警)等。