DS1302实时时钟模块详解:从原理到代码实现
创作时间:
作者:
@小白创作中心
DS1302实时时钟模块详解:从原理到代码实现
引用
CSDN
1.
https://blog.csdn.net/qq_45217381/article/details/146173925
DS1302是一种常用的实时时钟模块,广泛应用于各种嵌入式系统中。本文将详细介绍DS1302的使用方法,包括其功能简介、引脚说明以及具体的程序设计,帮助读者快速掌握DS1302的使用技巧。
一、DS1302简介
我们首先来简单介绍一下DS1302,首先DS1302具有实时时钟的功能,DS1302能够精确记录当前的时间,包括秒、分钟、小时、日期、月份以及年份,并支持闰年的自动调整。
除了实时时钟功能外,DS1302还具备数据保存功能,DS1302内置有31字节静态RAM用于数据备份,即使外部供电中断也能依靠后备电池保持数据不丢失。
DS1302采用简单的三线SPI兼容串行接口进行通讯,仅需三条信号线即可完成全部操作命令传输及与MCU的数据交互。DS1302使用一跟数据线实现双向数据传输,类似于我们之前介绍过的DS18B20和DHT11。
这里插一小段,在使用DS1302之前不知道大家有没有使用过STM32的RTC功能,对于像一些STM32F103ZET6这种核心板上有这个3V电池的板子来说,用起来还是比较友好的,但是像我们平时用的STM32F103C8T6这种比较小巧的核心板来讲,没有这个3V电池,如果使用到RTC功能,想要做到断电能够继续计时的话需要给单片机的VBAT引脚接上3V电池供电。
二、引脚介绍
DS1302总共有五个引脚
引脚 | 功能 |
|---|---|
VCC | 电源引脚,接3.3V/5V |
CLK | 时钟引脚 |
DAT | 数据线,与MCU实现双向数据交互 |
RST | 复位引脚,可以理解成类似片选 |
三、程序设计
3.1 DAT引脚处理
DAT引脚由于需要完成MCU和DS1302的双向数据传输,所以在不同情况下需要配置成不同的状态,我们这里封装一个函数来方便处理,当然也可以使用宏定义函数来实现
/*
*==============================================================================
*函数名称:Drv_Ds1302_DatIoCtrl
*函数功能:DS1302 DAT引脚控制
*输入参数:state:状态(0输入/1输出)
*返回值:无
*备 注:无
*==============================================================================
*/
void Drv_Ds1302_DatIoCtrl (u8 state)
{
// 结构体定义
GPIO_InitTypeDef GPIO_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd (DS1302_DAT_CLK, ENABLE);
if (state)
{
// 配置结构体
GPIO_InitStructure.GPIO_Pin = DS1302_DAT_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(DS1302_DAT_PORT, &GPIO_InitStructure);
}
else
{
// 配置结构体
GPIO_InitStructure.GPIO_Pin = DS1302_DAT_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DS1302_DAT_PORT, &GPIO_InitStructure);
}
}
3.2 DS1302读写寄存器
/*
*==============================================================================
*函数名称:Med_Ds1302_WriteByte
*函数功能:DS1302写入寄存器
*输入参数:
*返回值:无
*备 注:无
*==============================================================================
*/
void Med_Ds1302_WriteByte (u8 addr,u8 data)
{
u8 i;
RST = 0; // 关闭数据传输
CLK = 0; // 拉低时钟
RST = 1; // 启动数据传输
Drv_Ds1302_DatIoCtrl(1); // DAT引脚设置成输出模式
addr = addr & 0xFE; // 最低位置零,寄存器0位为0时写,为1时读
// 写入目标地址
for(i = 0;i < 8;i ++)
{
if (addr & 0x01)
DAT = 1;
else
DAT = 0;
CLK = 1; // 时钟上升沿写入数据
CLK = 0;
addr = addr >> 1;
}
// 写入数据
for (i = 0;i < 8;i ++)
{
if(data & 0x01)
DAT = 1;
else
DAT = 0;
CLK = 1; // 时钟上升沿写入数据
CLK = 0;
data = data >> 1;
}
CLK = 1; // 将时钟电平置于高电平状态
RST = 0; // 关闭数据传输
}
/*
*==============================================================================
*函数名称:Med_Ds1302_ReadByte
*函数功能:DS1302读取寄存器
*输入参数:
*返回值:无
*备 注:无
*==============================================================================
*/
u8 Med_Ds1302_ReadByte (u8 addr)
{
u8 i,data;
RST = 0; // 关闭数据传输
CLK = 0; // 拉低时钟
RST = 1; // 启动数据传输
Drv_Ds1302_DatIoCtrl(1); // DAT引脚设置成输出模式
addr = addr | 0x01; // 最低位置高,寄存器0位为0时写,为1时读
// 写入目标地址
for(i = 0;i < 8;i ++)
{
if (addr & 0x01)
DAT = 1;
else
DAT = 0;
CLK = 1; // 时钟上升沿写入数据
CLK = 0;
addr = addr >> 1;
}
// 从DS1302读出数据
Drv_Ds1302_DatIoCtrl(0); // DAT引脚设置为输入模式
for(i = 0;i < 8;i ++)
{
data = data >> 1;
if (DS1302_DAT_IN())
data |= 0x80;
else
data &= 0x7F;
CLK = 1; // 时钟上升沿写入数据
CLK = 0;
}
CLK = 1; // 将时钟电平置于高电平状态
RST = 0; // 关闭数据传输
return data;
}
3.3 DS1302设置时间
/*
*==============================================================================
*函数名称:Med_Ds1302_SetTime
*函数功能:DS1302设置时间
*输入参数:writeTime:要设置的时间
*返回值:无
*备 注:无
*==============================================================================
*/
void Med_Ds1302_SetTime (uint8_t *targetTime)
{
Med_Ds1302_WriteByte(DS1302_CONTROL_ADDR,0x00); // 关闭写入
Med_Ds1302_WriteByte(DS1302_SEC_ADDR,0x80); // 暂停时钟
// Med_Ds1302_WriteByte(DS1302_CHARGER_ADDR,0xa9); // 涓流充电
Med_Ds1302_WriteByte(DS1302_YEAR_ADDR,targetTime[1]); // 年
Med_Ds1302_WriteByte(DS1302_MONTH_ADDR,targetTime[2]); // 月
Med_Ds1302_WriteByte(DS1302_DAY_ADDR,targetTime[3]); // 日
Med_Ds1302_WriteByte(DS1302_HOUR_ADDR,targetTime[4]); // 时
Med_Ds1302_WriteByte(DS1302_MIN_ADDR,targetTime[5]); // 分
Med_Ds1302_WriteByte(DS1302_SEC_ADDR,targetTime[6]); // 秒
Med_Ds1302_WriteByte(DS1302_WEEK_ADDR,targetTime[7]); // 周
Med_Ds1302_WriteByte(DS1302_CHARGER_ADDR,0xA5); // 打开充电功能 选择2K电阻充电方式
Med_Ds1302_WriteByte(DS1302_CONTROL_ADDR,0x80); // 打开写入
}
3.4 DS1302获取当前时间
/*
*==============================================================================
*函数名称:Med_Ds1302_GetTime
*函数功能:DS1302获取时间
*输入参数:writeTime:要设置的时间
*返回值:无
*备 注:无
*==============================================================================
*/
void Med_Ds1302_GetTime (DS1302TimeStruct *timeData)
{
u8 readtime[8]; // 当前时间
readtime[1] = Med_Ds1302_ReadByte(DS1302_YEAR_ADDR); // 年
readtime[2] = Med_Ds1302_ReadByte(DS1302_MONTH_ADDR); // 月
readtime[3] = Med_Ds1302_ReadByte(DS1302_DAY_ADDR); // 日
readtime[4] = Med_Ds1302_ReadByte(DS1302_HOUR_ADDR); // 时
readtime[5] = Med_Ds1302_ReadByte(DS1302_MIN_ADDR); // 分
readtime[6] = (Med_Ds1302_ReadByte(DS1302_SEC_ADDR)) & 0x7f; // 秒,屏蔽秒的第7位,避免超出59
readtime[7] = Med_Ds1302_ReadByte(DS1302_WEEK_ADDR); // 周
timeData -> year = (readtime[0] >> 4) * 1000 + (readtime[0] & 0x0F) * 100 + (readtime[1] >> 4) * 10 + (readtime[1] & 0x0F); // 计算年份
timeData -> month = (readtime[2] >> 4) * 10 + (readtime[2] & 0x0F); // 计算月份
timeData -> day = (readtime[3] >> 4) * 10 + (readtime[3] & 0x0F); // 计算日期
timeData -> hour = (readtime[4] >> 4) * 10 + (readtime[4] & 0x0F); // 计算小时
timeData -> minute = (readtime[5] >> 4) * 10 + (readtime[5] & 0x0F); // 计算分钟
timeData -> second = (readtime[6] >> 4) * 10 + (readtime[6] & 0x0F); // 计算秒钟
timeData -> week = (readtime[7] & 0x0F); // 计算星期
}
热门推荐
探秘蛇蟠岛:从海盗传奇到海岛度假胜地
胃穿孔在饮食上应该注意哪些?
中老年男性眉毛变长的四个原因及长寿秘诀
眼睛疼是什么病?导致眼部疼痛的原因及治疗方法解析
新年到!教你用“集字法”写出高颜值春联
左眼胀痛伴左侧头痛怎么缓解
立春祭句芒:千年仪式的现代传承
柠檬酸在食品添加剂的应用
克氏综合征男性不育新突破!北大团队Nature发文!
梦见自己捡到钱是什么意思
郁金香花束花语:不同颜色的寓意与应用场景
一觉醒来眼睛肿了,不是“上火”还能是什么?
大专生逆袭奇安信:高薪转行的秘诀大揭秘!
云计算培训:转行高薪行业的金钥匙
掌握软件测试技能,轻松拿高薪!
跟着春晚游武汉:22个宝藏打卡点,玩转江城春节
老人跌倒怎么办?这些硬核知识须掌握!
小学数学路程问题:从基础概念到解题技巧
小学数学路程问题解题技巧全攻略
一道小学奥数题揭示的数学与物理思维差异
左氧氟沙星:你真的用对了吗?
盐酸左氧氟沙星片的正确储存方法
服用左氧氟沙星期间,这些“雷区”千万别碰!
关于备孕及妊娠妇女饮用咖啡和可乐的可行性!
孕妇喝了一罐可乐要紧吗
干花生米怎么快速煮烂
成都西站到成都东站:最新交通指南
高德地图带你玩转成都双站攻略
安德烈·德尤:从健体冠军到古典健美选手的转型之路
CAD技术和VR如何重塑未来建筑?