目录
一、介绍
二、模块原理
1.原理图
2.引脚描述
3.工作原理:读/写时序
4.寄存器地址/定义
三、程序设计
main.c文件
ds1302.h文件
ds1302.c文件
四、实验效果
五、资料获取
项目分享
一、介绍
DS1302是一款由达拉斯半导体(Dallas Semiconductor)公司生产的实时时钟(RTC)芯片,它能够为微控制器提供年、月、日、星期、时、分、秒的时间信息,并且可以通过简单的串行接口进行通信。DS1302 具有低功耗、备用电池接口和 RAM 存储等功能,广泛应用于需要时间记录的电子设备中。
以下是DS1302时钟模块的参数:
型号 | DS1302 |
工作电压 | 2.0~5.5V |
晶振 | 32.768MHz |
工作温度 | 0~70℃ |
备用电池型号 | CR2032 |
哔哩哔哩视频链接:
DS1302时钟模块(STM32)
(资料分享见文末)
二、模块原理
1.原理图
2.引脚描述
引脚名称 | 描述 |
VCC | 电源正极 |
GND | 电源负极 |
SCLK | 串行时钟线 |
I/O | 数据输入/输出 |
RST | 复位线 |
3.工作原理:读/写时序
DS1302通过三线串行接口与微控制器进行通信。微控制器可以通过设置RST引脚为高电平来使能DS1302,并通过SCLK引脚提供串行时钟信号,然后通过I/O引脚进行数据的读写操作。DS1302 的时钟和日历数据采用二进制编码的十进制(BCD码,即字节的高四位是数据的十位,字节的低四位是数据的个位)格式存储,这样方便读取和显示。
4.寄存器地址/定义
三、程序设计
使用STM32F103C8T6使用DS1302时钟模块显示当前实时时间。
DS1302_CE | PA5 |
DS1302_DATA | PA6 |
DS302_SCLK | PA7 |
OLED_SCL | PB11 |
OLED_SDA | PB10 |
main.c文件
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "ds1302.h"
#include "timer.h"
/*****************辰哥单片机设计******************
STM32
* 项目 : DS1302时钟模块实验
* 版本 : V1.0
* 日期 : 2024.10.3
* MCU : STM32F103C8T6
* 接口 : 参看ds1302.h
* BILIBILI : 辰哥单片机设计
* CSDN : 辰哥单片机设计
* 作者 : 辰哥
**********************BEGIN***********************/
char st[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();
OLED_Init(); //屏幕初始化
OLED_Clear();
while(1)
{
DS1302_read_realTime(); //读取此时时刻
sprintf(st,"%d ",TimeData.year);
OLED_ShowString(8,0,st,16,1);
OLED_ShowChinese(40,0,9,16,1);//年
sprintf(st,"%d ",TimeData.month);
OLED_ShowString(56,0,st,16,1);
OLED_ShowChinese(72,0,10,16,1);//月
sprintf(st,"%d ",TimeData.day);
OLED_ShowString(88,0,st,16,1);
OLED_ShowChinese(104,0,11,16,1);//日
sprintf(st,"%d ",TimeData.hour);
OLED_ShowString(48+8,16,st,16,1);
OLED_ShowString(48+8+16,16,"-",16,1);
sprintf(st,"%d ",TimeData.minute);
OLED_ShowString(48+8+16+8,16,st,16,1);
OLED_ShowString(48+8+16+16+8,16,"-",16,1);
sprintf(st,"%d ",TimeData.second);
OLED_ShowString(48+8+16+16+16,16,st,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();
}
}
ds1302.h文件
#ifndef __DS1302_H
#define __DS1302_H
#include "sys.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : DS1302时钟模块h文件
* 版本 : V1.0
* 日期 : 2024.10.3
* MCU : STM32F103C8T6
* 接口 : 见代码
* BILIBILI : 辰哥单片机设计
* CSDN : 辰哥单片机设计
* 作者 : 辰哥
**********************BEGIN***********************/
//---------------DS1302端口定义-----------------
/***************根据自己需求更改****************/
#define DS1302_CLK RCC_APB2Periph_GPIOA
#define DS1302_CE_PORT GPIOA
#define DS1302_CE_PIN GPIO_Pin_5
#define DS1302_DATA_PORT GPIOA
#define DS1302_DATA_PIN GPIO_Pin_6
#define DS1302_SCLK_PORT GPIOA
#define DS1302_SCLK_PIN GPIO_Pin_7
/*********************END**********************/
#define CE_L GPIO_ResetBits(DS1302_CE_PORT,DS1302_CE_PIN)//CE
#define CE_H GPIO_SetBits(DS1302_CE_PORT,DS1302_CE_PIN)
#define DATA_L GPIO_ResetBits(DS1302_SCLK_PORT,DS1302_DATA_PIN)//DATA
#define DATA_H GPIO_SetBits(DS1302_SCLK_PORT,DS1302_DATA_PIN)
#define SCLK_L GPIO_ResetBits(DS1302_DATA_PORT,DS1302_SCLK_PIN)//SCLK
#define SCLK_H GPIO_SetBits(DS1302_DATA_PORT,DS1302_SCLK_PIN)
struct TIMEData
{
u16 year;
u8 month;
u8 day;
u8 hour;
u8 minute;
u8 second;
u8 week;
};//创建TIMEData结构体方便存储时间日期数据
struct TIMERAM
{
u8 hour_kai;
u8 minute_kai;
u8 hour_guan;
u8 minute_guan;
u8 kai;
u8 guan;
};//创建TIMEData结构体方便存储时间日期数据
extern struct TIMERAM TimeRAM;
extern struct TIMEData TimeData;//全局变量
void DS1302_GPIO_Init(void);//ds1302端口初始化
void DS1302_write_onebyte(u8 data);//向ds1302发送一字节数据
void DS1302_wirte_rig(u8 address,u8 data);//向指定寄存器写一字节数据
u8 DS1302_read_rig(u8 address);//从指定寄存器读一字节数据
void DS1302_Init(void);//ds1302初始化函数
void DS1302_DATAOUT_init(void);//IO端口配置为输出
void DS1302_DATAINPUT_init(void);//IO端口配置为输入
void DS1302_read_time(void);//从ds1302读取实时时间(BCD码)
void DS1302_read_realTime(void);//将BCD码转化为十进制数据
void DS1302_wirteRAM(void);
void DS1302_readRAM(void);
#endif
ds1302.c文件
#include "ds1302.h"
#include "sys.h"
#include "delay.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : DS1302时钟模块c文件
* 版本 : V1.0
* 日期 : 2024.10.3
* MCU : STM32F103C8T6
* 接口 : 见代码
* BILIBILI : 辰哥单片机设计
* CSDN : 辰哥单片机设计
* 作者 : 辰哥
**********************BEGIN***********************/
struct TIMEData TimeData;
struct TIMERAM TimeRAM;
u8 read_time[7];
void DS1302_GPIO_Init(void)//CE,SCLK端口初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(DS1302_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = DS1302_SCLK_PIN; //CE
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(DS1302_SCLK_PORT, &GPIO_InitStructure);//初始化
GPIO_ResetBits(DS1302_SCLK_PORT,DS1302_SCLK_PIN);
GPIO_InitStructure.GPIO_Pin = DS1302_CE_PIN; //SCLK
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(DS1302_CE_PORT, &GPIO_InitStructure);//初始化
GPIO_ResetBits(DS1302_CE_PORT,DS1302_CE_PIN);
}
void DS1302_DATAOUT_init()//配置双向I/O端口为输出态
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(DS1302_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = DS1302_DATA_PIN; // DATA
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(DS1302_DATA_PORT, &GPIO_InitStructure);//初始化
GPIO_ResetBits(DS1302_DATA_PORT,DS1302_DATA_PIN);
}
void DS1302_DATAINPUT_init()//配置双向I/O端口为输入态
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(DS1302_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = DS1302_DATA_PIN; //DATA
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DS1302_DATA_PORT, &GPIO_InitStructure);//初始化
}
void DS1302_write_onebyte(u8 data)//向DS1302发送一字节数据
{
u8 count=0;
SCLK_L;
DS1302_DATAOUT_init();
for(count=0;count<8;count++)
{ SCLK_L;
if(data&0x01)
{DATA_H;}
else{DATA_L;}//先准备好数据再发送
SCLK_H;//拉高时钟线,发送数据
data>>=1;
}
}
void DS1302_wirte_rig(u8 address,u8 data)//向指定寄存器地址发送数据
{
u8 temp1=address;
u8 temp2=data;
CE_L;SCLK_L;delay_us(1);
CE_H;delay_us(3);
DS1302_write_onebyte(temp1);
DS1302_write_onebyte(temp2);
CE_L;SCLK_L;delay_us(3);
}
u8 DS1302_read_rig(u8 address)//从指定地址读取一字节数据
{
u8 temp3=address;
u8 count=0;
u8 return_data=0x00;
CE_L;SCLK_L;delay_us(3);
CE_H;delay_us(3);
DS1302_write_onebyte(temp3);
DS1302_DATAINPUT_init();//配置I/O口为输入
delay_us(3);
for(count=0;count<8;count++)
{
delay_us(3);//使电平持续一段时间
return_data>>=1;
SCLK_H;delay_us(5);//使高电平持续一段时间
SCLK_L;delay_us(30);//延时14us后再去读取电压,更加准确
if(GPIO_ReadInputDataBit(DS1302_DATA_PORT,DS1302_DATA_PIN))
{return_data=return_data|0x80;}
}
delay_us(2);
CE_L;DATA_L;
return return_data;
}
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,0x20);//hours20时
DS1302_wirte_rig(0x86,0x03);//date3日
DS1302_wirte_rig(0x88,0x10);//months10月
DS1302_wirte_rig(0x8a,0x04);//days星期四
DS1302_wirte_rig(0x8c,0x24);//year2024年
DS1302_wirte_rig(0x8e,0x80);//开启写保护
}
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);//读年
}
void DS1302_read_realTime(void)
{
DS1302_read_time(); //BCD码转换为10进制
TimeData.second=(read_time[0]>>4)*10+(read_time[0]&0x0f);
TimeData.minute=((read_time[1]>>4))*10+(read_time[1]&0x0f);
TimeData.hour=(read_time[2]>>4)*10+(read_time[2]&0x0f);
TimeData.day=(read_time[3]>>4)*10+(read_time[3]&0x0f);
TimeData.month=(read_time[4]>>4)*10+(read_time[4]&0x0f);
TimeData.week=read_time[5];
TimeData.year=(read_time[6]>>4)*10+(read_time[6]&0x0f)+2000;
}
void DS1302_wirteRAM(void)
{
DS1302_wirte_rig(0x8e,0x00);//关闭写保护
DS1302_wirte_rig(0xC0,TimeRAM.hour_kai);//开时
DS1302_wirte_rig(0xC2,TimeRAM.minute_kai);//开分
DS1302_wirte_rig(0xC4,TimeRAM.hour_guan);//关时
DS1302_wirte_rig(0xC6,TimeRAM.minute_guan);//关分
DS1302_wirte_rig(0xC8,TimeRAM.kai);//关分
DS1302_wirte_rig(0xCA,TimeRAM.guan);//关分
DS1302_wirte_rig(0x8e,0x80);//关闭写保护
}
void DS1302_readRAM(void)
{
TimeRAM.hour_kai=DS1302_read_rig(0xC1);//读秒
TimeRAM.minute_kai=DS1302_read_rig(0xC3);//读分
TimeRAM.hour_guan=DS1302_read_rig(0xC5);//读时
TimeRAM.minute_guan=DS1302_read_rig(0xC7);//读日
TimeRAM.kai=DS1302_read_rig(0xC9);//读日
TimeRAM.guan=DS1302_read_rig(0xCB);//读日
}