STM32控制DS1302时钟模块获取实时时间

欢迎入群共同学习交流
时间记录:2024/4/30

一、知识点

原理图
(1)读写数据时序(伪SPI协议)
读写时序
1.1 读写时序默认电平均为SCLK线低电平,CE线低电平
1.2 写数据,CE线拉高为高电平,开始传输数据,然后准备数据在SCLK线的上升沿DS1302读取数据,发送8位控制命令后,发送8位数据(低位先发)
1.3 读数据,CE线拉高为高电平,开始传输数据,然后在SCLK低电平时准备数据,上升沿发送数据,发送8位控制命令后,下一个下降沿开始读取数据(低位先发,低位先读)
(2)读写命令及数据格式
命令及数据格式
2.1 READ和WRITE的命令即为发送和读取数据前需要先发送的对应8位控制命令
2.2 秒数据的BIT7位CH决定时钟的开启/关闭
2.3 小时数据的BIT7位决定是12小时显示还是24小时显示
2.4 WP位决定开启写保护还是取消写保护,写入0取消写保护,写入1打开写保护
(3)数据转换
3.1 DS1302读取的数据为BCD编码格式,需要转为10进制,写入时10进制数据需要转为BCD格式
3.2 BCD->10进制,BCD/1610+BCD%16
3.3 10进制->BCD,10进制/10
16+10进制%10

二、示例代码

(1)头文件

#ifndef __DS1302_H__
#define __DS1302_H__
#include "stm32f10x.h"typedef struct __DS1302TIME
{int year;int mon;int day;int hour;int min;int sec;int week;
}ds_time;void vDS1302_Init(void);
void vDS1302_SetTime(ds_time *sys_time);
void vDS1302_GetTime(ds_time *sys_time);#endif

(2)源文件

#include "ds1302.h"/*** 模块引脚宏定义*/
#define DS1302_SCLK_PORT GPIOA
#define DS1302_SCLK_PIN GPIO_Pin_10
#define DS1302_DAT_PORT GPIOA
#define DS1302_DAT_PIN GPIO_Pin_11
#define DS1302_RST_PORT GPIOA
#define DS1302_RST_PIN GPIO_Pin_12/*** 获取设置时间命令宏定义*/
#define READ_SEC 0x81
#define WRITE_SEC 0x80
#define READ_MIN 0x83
#define WRITE_MIN 0x82
#define READ_HOUR 0x85
#define WRITE_HOUR 0x84
#define READ_DAY 0x87
#define WRITE_DAY 0x86
#define READ_MON 0x89
#define WRITE_MON 0x88
#define READ_WEEK 0x8B
#define WRITE_WEEK 0x8A
#define READ_YEAR 0x8D
#define WRITE_YEAR 0x8C
#define ENABLE_WRITE 0x00
#define DISABLE_WRITE 0x80/*** 枚举定义*/
enum __LINEMODE
{INPUT_MODE = 0,OUTPUT_MODE
};/*** 函数声明*/
static void vDatLineMode(u8 mode);
static void vWriteRam(u8 addr, u8 data);
static u8 vReadRam(u8 addr);/*** 初始化函数定义*/
void vDS1302_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = DS1302_SCLK_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_SCLK_PORT, &GPIO_InitStruct);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);GPIO_InitStruct.GPIO_Pin = DS1302_RST_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_RST_PORT, &GPIO_InitStruct);GPIO_ResetBits(DS1302_RST_PORT, DS1302_RST_PIN);
}/*** 数据引脚切换输入输出模式*/
static void vDatLineMode(u8 mode)
{GPIO_InitTypeDef GPIO_InitStruct;if (mode == INPUT_MODE){GPIO_InitStruct.GPIO_Pin = DS1302_DAT_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_DAT_PORT, &GPIO_InitStruct);}else if (mode == OUTPUT_MODE){GPIO_InitStruct.GPIO_Pin = DS1302_DAT_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_DAT_PORT, &GPIO_InitStruct);}
}/*** 写入数据*/
static void vWriteRam(u8 addr, u8 data)
{vDatLineMode(OUTPUT_MODE);GPIO_SetBits(DS1302_RST_PORT, DS1302_RST_PIN); // 开始传输数据for (u8 i = 0; i < 8; i++) // 传输控制字节{GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN); // 低电平准备数据if (addr & 0x01)                                   // 低位先发GPIO_SetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);elseGPIO_ResetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN); // 上升沿发送数据addr >>= 1;}for (u8 i = 0; i < 8; i++) // 传输数据字节{GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);if (data & 0x01)GPIO_SetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);elseGPIO_ResetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);data >>= 1;}// 传输完毕,恢复取消传输数据状态GPIO_ResetBits(DS1302_RST_PORT, DS1302_RST_PIN);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);
}/*** 读取数据*/
static u8 vReadRam(u8 addr)
{vDatLineMode(OUTPUT_MODE);GPIO_SetBits(DS1302_RST_PORT, DS1302_RST_PIN);u8 retData = 0x00;for (u8 i = 0; i < 8; i++) // 传输控制字节{GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN); // 低电平准备数据if (addr & 0x01)                                   // 低位先发GPIO_SetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);elseGPIO_ResetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);addr >>= 1;}vDatLineMode(INPUT_MODE);for (u8 i = 0; i < 8; i++){retData >>= 1;GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);if (GPIO_ReadInputDataBit(DS1302_DAT_PORT, DS1302_DAT_PIN))retData |= 0x80;GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);}GPIO_ResetBits(DS1302_RST_PORT, DS1302_RST_PIN);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);return (retData & 0x7F); // 最高位是一些标志位可清零不获取
}void vDS1302_SetTime(ds_time *sys_time)
{vWriteRam(0x8E, ENABLE_WRITE); // 关闭写保护sys_time->year = sys_time->year - 2000;vWriteRam(WRITE_YEAR, ((sys_time->year / 10 * 16) + (sys_time->year % 10)));vWriteRam(WRITE_MON, ((sys_time->mon / 10 * 16) + (sys_time->mon % 10)));vWriteRam(WRITE_DAY, ((sys_time->day / 10 * 16) + (sys_time->day % 10)));vWriteRam(WRITE_HOUR, ((sys_time->hour / 10 * 16) + (sys_time->hour % 10)));vWriteRam(WRITE_MIN, ((sys_time->min / 10 * 16) + (sys_time->min % 10)));vWriteRam(WRITE_SEC, ((sys_time->sec / 10 * 16) + (sys_time->sec % 10)));vWriteRam(WRITE_WEEK, ((sys_time->week / 10 * 16) + (sys_time->week % 10)));vWriteRam(0x8E, DISABLE_WRITE); // 开启写保护
}void vDS1302_GetTime(ds_time *sys_time)
{u8 tempDat = 0x00;tempDat = vReadRam(READ_YEAR);sys_time->year = (tempDat / 16 * 10) + (tempDat % 16) + 2000;tempDat = vReadRam(READ_MON);sys_time->mon = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_DAY);sys_time->day = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_HOUR);sys_time->hour = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_MIN);sys_time->min = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_SEC);sys_time->sec = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_WEEK);sys_time->week = (tempDat / 16 * 10) + (tempDat % 16);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3015636.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

CANoe测试报告格式转换

CANoe测试报告使用工具Vector CANoe Test Report Viewer进行格式转换 一、 Test Report Viewer format转换为PDF格式 使用工具Vector CANoe Test Report Viewer打开*.vtestreport文件,点击File | Export | Export PDF,可以将测试报告转为PDF格式。 二、Test Report Viewe…

想做视频号小店,为何不建议开通个体店?开店步骤+做店思路如下

我是王路飞。 如果你想在视频号开通店铺的话&#xff0c;那么一定不要使用个体执照开通个体店&#xff1f; 这是为什么呢&#xff1f; 原因很简单&#xff0c;视频号个体店是无法入驻优选联盟的&#xff0c;只能企业店可以入驻。 因为现阶段视频号小店的自然流量很少&#…

18、ESP32 ESP-NOW 点对点通信

ESP-NOW 是乐鑫自主研发的无连接通信协议&#xff0c;具有短数据包传输功能。该协议使多个设备能够以简单的方式相互通信。 ESP-NOW 功能 ESP-NOW 支持以下功能&#xff1a; 加密和未加密的单播通信;混合加密和未加密的对等设备;最多可携带 250 字节 的有效载荷;发送回调功能…

C 语言文件输入/输出(I/O)函数大全

C 语言文件输入/输出&#xff08;I/O&#xff09;函数大全 1. fopen() 函数2. fclose() 函数3. fread() 函数4. fwrite() 函数5. fseek() 函数6. ftell() 函数7. rewind() 函数8. feof() 函数9. ferror() 函数10. clearerr() 函数 &#x1f60a; C 语言文件输入/输出&#xf…

从互联网医院源码到搭建:开发视频问诊小程序的技术解析

如今&#xff0c;视频问诊小程序作为医疗服务的一种新形式&#xff0c;正逐渐受到人们的关注和青睐。今天&#xff0c;小编将为您详解视频问诊小程序的开发流程。 一、背景介绍 互联网医院源码是视频问诊小程序开发的基础&#xff0c;它提供了一套完整的医疗服务系统框架&…

shpfile转GeoJSON;控制shp转GeoJSON的精度;如何获取GeoJSON;GeoJSON是什么有什么用;GeoJSON结构详解(带数据示例)

目录 一、GeoJSON是什么 二、GeoJSON的结构组成 2.1、点&#xff08;Point&#xff09;数据示例 2.2、线&#xff08;LineString&#xff09;数据示例 2.3、面&#xff08;Polygon&#xff09;数据示例 2.4、特征&#xff08;Feature&#xff09;数据示例 2.5、特征集合&…

谷歌推广和seo收录是一回事吗?

那自然不是一回事&#xff0c;谷歌推广一般指的是谷歌的广告服务&#xff0c;通过购买广告位&#xff0c;以便用户在谷歌搜索特定关键词时显示您的广告&#xff0c;这种方式通常基于点击收费&#xff0c;意味着您只有在有人点击您的广告时才需要支付费用。谷歌推广可以让您的网…

【系统分析师】系统分析部分

文章目录 1、系统分析概述2、详细调查2.1 为什么要做详细调查&#xff1f;2.2 详细调查的原则2.3 详细调查的内容2.4 详细调查的方法 3、现有系统分析3.1 获得系统的物理模型3.2 抽象出现有系统的逻辑模型3.3 建立新系统的逻辑模型3.4 建立新系统的物理模型 4、组织结构分析4.1…

如何选择适合的美国站群服务器:经济实惠而可靠的选择

如何选择适合的美国站群服务器&#xff1a;经济实惠而可靠的选择 在今天的数字化时代&#xff0c;选择适合的服务器对于个人网站或企业来说至关重要。一台性能稳定、价格实惠的美国站群服务器能够为您的网站提供所需的支持&#xff0c;但在选择之前&#xff0c;有一些关键因素…

项目计划书(Word原件)

项目开发计划包括项目描述、项目组织、成本预算、人力资源估算、设备资源计划、沟通计划、采购计划、风险计划、项目过程定义及项目的进度安排和里程碑、质量计划、数据管理计划、度量和分析计划、监控计划和培训计划等。 软件资料清单列表部分文档&#xff1a; 工作安排任务书…

Google Play开发者账号为什么会被封?如何解决关联账号问题?

Google Play是Google提供的一个应用商店&#xff0c;用户可以在其中下载并安装Android设备上的应用程序、电影、音乐、电子图书等。Google Play是Android平台上较大的应用市场&#xff0c;包含了数百万个应用程序和游戏。但是谷歌对于上架应用的审核越趋严格&#xff0c;开发者…

AGV无人叉车 | 我们为什么要投资“智慧生产”

AGV 作为一种智能工业车辆机器人&#xff0c;无人叉车充分融合叉车技术和AGV技术&#xff0c;近年来在仓储物流领域的应用逐步扩大。在传统叉车厂商、传统AGV厂商、物流集成商及仓储机器人企业等各方力量推动下&#xff0c;无人叉车市场在竞合中快速发展&#xff0c;并促使无人…

经典面试题---环形链表

1. 环形链表1. - 力扣&#xff08;LeetCode&#xff09; 要解决这道题&#xff0c;我们首先要挖掘出带环的链表与不带环的链表之间的差别。 以此&#xff0c;才能设计出算法来体现这种差别并判断。 二者最突出的不同&#xff0c;就是不带环的链表有尾结点&#xff0c;也就是说…

顺序表经典算法OJ题-- 力扣27,88

题1&#xff1a; 移除元素 题2&#xff1a; 合并两个有序数组 一&#xff1a;题目链接&#xff1a;. - 力扣&#xff08;LetCode&#xff09; 作答&#xff1a; 二&#xff1a;题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 作答&#xff1a; 感谢观看&am…

速看!这次主食冻干评测极可能被商家恶意举报~VE、希喂、PR真实测评

我发现还是有不少铲屎官局限于“进口最高贵”&#xff0c;盲目的迷信进口产品。看到进口粮就盲买&#xff0c;甚至过分的贬低国产品牌&#xff0c;将国产粮贴上“不靠谱”“不合格”等标签。 最近&#xff0c;我针对主食冻干的国内、国际标准&#xff0c;相关规范文件&#xf…

windows安装ElasticSearch以及踩坑

1.下载 elasticsearch地址&#xff1a;Past Releases of Elastic Stack Software | Elastichttps://www.elastic.co/cn/downloads/past-releases#elasticsearch IK分析器地址&#xff1a;infinilabs/analysis-ik: &#x1f68c; The IK Analysis plugin integrates Lucene IK…

c++ 线程交叉场景试验

1.需求 1.处理一个列表的数据&#xff0c;要求按照列表的数据处理10个数据 2.可以使用多线程处理&#xff0c;但是针对每个线程&#xff0c;1~10的处理顺序不能变。 3.每个数据的处理必须原子&#xff0c;即只有一个线程可以针对某个数据进行处理&#xff0c;但是10个数据是可…

保姆级教程:从 0 到 1 将项目发布到 Maven 中央仓库【2024年5月】

前言 大家好&#xff0c;我叫阿杆&#xff0c;不叫阿轩 最近写了一个参数校验组件&#xff0c;名字叫 spel-validator&#xff0c;是基于 javax.validation 的一个扩展&#xff0c;目的是简化参数校验。 我把项目开源到了GitHub https://github.com/stick-i/spel-validator …

视频号小店是普通人的机会吗?看完你就明白了!

大家好&#xff0c;我是电商小V 视频号小店是普通人的机会吗&#xff1f;我可以很确定的说&#xff1a;视频号小店就是普通人的机会&#xff0c;并且是很大的机会&#xff0c; 首先就是视频号小店这个项目还没有自然流量的入口&#xff0c;是一个还没有完全开放私域电商的平台&…

HNU-人工智能-实验4-基于Resnet的分类器

前言 本实验是自选实验&#xff0c;可以在给定范围内选择。 我刚刚提交了实验报告&#xff0c;暂时不准备放出我自己的实验报告&#xff0c;大概在截止提交之后我再放。 之所以这么着急写blog&#xff0c;是想便利还没做实验的同学。 如果选择的也是这个“毒蘑菇识别”的分类器…