STM32/N32G455国民科技芯片驱动DS1302时钟---笔记

这次来分享一下DS1302时钟IC,之前听说过这个IC,但是一直没搞过,用了半天时间就明白了原理和驱动,说明还是很简单的。

注:首先来区分一下DS1302和RTC时钟有什么不同,为什么不直接用RTC呢?

RTC不是很精准

DS1302:用于对时间精度较严格的产品上

1.首先看下实物图长什么样

2.然后我们来看看原理图长啥样

2.1无上拉电阻的配置

2.2有上拉电阻就将端口配置成开漏输出就行

3.下面来看怎么配置代码

由于DS1302的DATA根据时序图,还要配成输入模式

所以还得写上区分

然后后面的代码就照抄就行,只要会IIC,SPI协议,这些一看就明白是什么意思啦,无非就是移位和最高/最低位判断,然后将DATA拉高或者拉低,换汤不换药,简简单单。

根据DS1302的特殊寄存器,假设现在是15秒,那么1302的寄存器里面存储的是0x15,而不是0x0F,也就是说十六进制的0xAB,表示一个十进制数,高四位A代表十位,低四位B代表个位
,但这毕竟是用16进制表示的数字,我们在单片机的代码里操作起来并不方便,我们需要转换为正儿八经的十进制

所以上面一大堆,可能看的很乱,来,我们现在来捋一捋

还是假设是15秒

好,我们来分析上面的也就是说十六进制的0xAB,表示一个十进制数,高四位A代表十位,低四位B代表个位这句话

0X15=0001 0101

高四位右移:0001 0101 >>4=0000 0001=1

第四位不动:0000 0101&0X0F

        0000 0101

 &                               ->  0000 0101 =5

        0000 1111

好,那么这不就是15秒吗?

那么就有了后面的代码

这样就非常的清晰了吧,有没有拍桌子,拍案叫绝的感觉了!

我将DS1302.C和DS1302.H的代码都复制到后面,核心重点就讲完了,毫无难度呀

DS1302.C

#include "DS1302.h"
#include "main.h"TIME Time_Hex,Time_Dec,Time_Set;#define DS1302DELAY  100const u8 Ds1302SendBuf[6] = {0x23, 0x11, 0x15, 0x13, 0x49, 0x00}; //2016unsigned char  Month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};void INPUT_SDA()
{RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA ,ENABLE);	GPIO_InitType GPIO_InitStructure;GPIO_InitStructure.Pin =  GPIO_PIN_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置使用带宽50MhzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //输入模式GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}void OUTPUT_SDA()
{RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA ,ENABLE);	GPIO_InitType GPIO_InitStructure;GPIO_InitStructure.Pin =  GPIO_PIN_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置使用带宽50MhzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //输出模式GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}void uDelay(unsigned int count)
{unsigned int j;for(j=0;j<count;j++) ;	
}void SendDat_1302(u8 Dat)
{ u8 i;u8 cTmp;for(i=0;i<8;i++){ cTmp=Dat&LSB; //数据端等于tmp数据的末位值if(cTmp)    //1DS1302DAT_H;elseDS1302DAT_L; Dat>>=1;uDelay(DS1302DELAY);DS1302CLK_H;uDelay(DS1302DELAY);DS1302CLK_L;uDelay(DS1302DELAY);}
}/*写入1个或者多个字节,第1个参数是相关命令
#define WrMulti     0xbe //写入多个字节的指令代码
#define WrSingle    0x84 //写入单个字节的指令代码
第2个参数是待写入的值
第3个参数是待写入数组的指针
*/ 
void WriteByte_1302(u8 CmdDat,u8 Num,u8 *pSend)
{ u8 i=0;DS1302RST_L;uDelay(DS1302DELAY);	DS1302RST_H;SendDat_1302(CmdDat);for(i=0;i<Num;i++){ SendDat_1302(*(pSend+i));}DS1302RST_L;
}
/*读出字节,第一个参数是命令
#define RdMulti  0xbf //读出多个字节的指令代码
第2个参数是读出的字节数,第3个是指收数据数组指针
*/
void RecByte_1302(u8 CmdDat,u8 Num,u8 *pRec)
{ u8 i,j,tmp=0,cTmp;DS1302RST_L;//复位引脚为低电平uDelay(DS1302DELAY);DS1302CLK_L;uDelay(DS1302DELAY);DS1302RST_H;SendDat_1302(CmdDat); //发送命令INPUT_SDA();uDelay(DS1302DELAY);for(i=0;i<Num;i++){ for(j=0;j<8;j++){ tmp>>=1;cTmp=DS1302DAT_READ;if(cTmp)tmp|=0x80;DS1302CLK_H;uDelay(DS1302DELAY);DS1302CLK_L;       uDelay(DS1302DELAY);}*(pRec+i)=tmp;}uDelay(DS1302DELAY);OUTPUT_SDA();DS1302RST_L;//复位引脚为低电平
}
/*
当写保护寄存器的最高位为0时,允许数据写入寄存器。
写保护寄存器可以通过命令字节8E、8F来规定禁止写入/读出。写保护位不能在多字节传送模式下写入。
当写保护寄存器的最高位为1时,禁止数据写入寄存器。
时钟停止位操作:当把秒寄存器的第7位时钟停止位设置为0时起动时钟开始
当把秒寄存器的第7位时钟停止位设置为1时,时钟振荡器停止。根据传入的参数决定相关命令,
第一个参数:命令字,第2个参数:写入的数据
写允许命令;8EH,00H
写禁止命令;8EH,80H
振荡器允许命令;80H,00H
振荡器禁止命令;80H,80H
*/
void WrCmd(u8 CmdDat,u8 CmdWord)
{ u8* CmdBuf;CmdBuf=&CmdWord;WriteByte_1302(CmdDat,1,CmdBuf);
}void DS1302_Init(void)
{
//DS1302====================WrCmd(0x80, 0x00); //?????WrCmd(0x8C, Ds1302SendBuf[0]);WrCmd(0x88, Ds1302SendBuf[1]);WrCmd(0x86, Ds1302SendBuf[2]);//const u8 Ds1302SendBuf[6] = {0x23, 0x11, 0x15, 0x13, 0x49, 0x00}; //2016WrCmd(0x84, Ds1302SendBuf[3]);WrCmd(0x82, Ds1302SendBuf[4]);WrCmd(0x80, Ds1302SendBuf[5]);WrCmd(0x8e, 0x80);	
}void Save_TimeDate(void)
{WrCmd(WrEnDisCmd, WrEnDat); WrCmd(0x80, 0x00); WrCmd(0x8C, Time_Hex.year);WrCmd(0x88, Time_Hex.month);WrCmd(0x86, Time_Hex.day);WrCmd(0x84, Time_Hex.hour);WrCmd(0x82, Time_Hex.minute);WrCmd(0x80, Time_Hex.second);WrCmd(0x8e, 0x80);
}void Get_Time(void)
{WrCmd(0x8F,0x00);RecByte_1302(0x8D,1,(u8*)&Time_Hex.year);RecByte_1302(0x89,1,(u8*)&Time_Hex.month);RecByte_1302(0x87,1,(u8*)&Time_Hex.day);RecByte_1302(0x85,1,(u8*)&Time_Hex.hour);RecByte_1302(0x83,1,(u8*)&Time_Hex.minute);	RecByte_1302(0x81,1,(u8*)&Time_Hex.second);Time_Dec.year = (Time_Hex.year>>4)*10 + (Time_Hex.year&0x0f); 	Time_Dec.month = (Time_Hex.month>>4)*10 + (Time_Hex.month&0x0f);Time_Dec.day = (Time_Hex.day>>4)*10 + (Time_Hex.day&0x0f);Time_Dec.hour = (Time_Hex.hour>>4)*10 + (Time_Hex.hour&0x0f);Time_Dec.minute = (Time_Hex.minute>>4)*10 + (Time_Hex.minute&0x0f);Time_Dec.second = (Time_Hex.second>>4)*10 + (Time_Hex.second&0x0f);	
}void Check_date(void)
{		Time_Dec.year   = Time_Set.year; 	Time_Dec.month  = Time_Set.month;Time_Dec.day    = Time_Set.day;Time_Dec.hour   = Time_Set.hour;Time_Dec.minute = Time_Set.minute;Time_Dec.second = Time_Set.second;if(Time_Dec.month < 1)  Time_Dec.month = 1;if(Time_Dec.month > 12) Time_Dec.month = 12;if(Time_Dec.day < 1)    Time_Dec.day = 1;if(Time_Dec.day> 31)     Time_Dec.day= 31;if(Time_Dec.hour  > 23) Time_Dec.hour= 23;		 if(Time_Dec.minute  > 59) Time_Dec.minute  = 59;	if(Time_Dec.second > 60) Time_Dec.second = 0;if(Time_Dec.minute > 60) Time_Dec.minute = 0;if(Time_Dec.hour > 60) Time_Dec.hour = 0;  	if(Time_Dec.year > 99)  Time_Dec.year = 99;Month[2] = 28;if((Time_Dec.year % 4 == 0 && Time_Dec.year % 100 != 0) || (Time_Dec.year % 400 == 0) )Month[2] = 29;    if(Time_Dec.day > Month[Time_Dec.month])    Time_Dec.day = Month[Time_Dec.month];	Time_Hex.year = 		((Time_Dec.year/10)<<4) 		| (Time_Dec.year%10);Time_Hex.month = 		((Time_Dec.month/10)<<4) 		| (Time_Dec.month%10);Time_Hex.day = 			((Time_Dec.day/10)<<4) 			| (Time_Dec.day%10);Time_Hex.hour = 		((Time_Dec.hour/10)<<4) 		| (Time_Dec.hour%10);Time_Hex.minute = 	((Time_Dec.minute/10)<<4) 	| (Time_Dec.minute%10);Time_Hex.second = 	((Time_Dec.second/10)<<4) 	| (Time_Dec.second%10);
}

DS1302.H

#ifndef __DS1302_H
#define __DS1302_H#include "main.h"#define  u8 unsigned char typedef struct 
{unsigned char year  	;unsigned char month 	;unsigned char day   	;unsigned char hour  	;unsigned char minute 	;unsigned char second 	;
} TIME;#define DS1302CLK_H  		GPIO_SetBits(GPIOA,GPIO_PIN_6)
#define DS1302CLK_L  		GPIO_ResetBits(GPIOA,GPIO_PIN_6)#define DS1302DAT_H  		GPIO_SetBits(GPIOA,  GPIO_PIN_7)
#define DS1302DAT_L  		GPIO_ResetBits(GPIOA,GPIO_PIN_7)
#define DS1302DAT_READ  GPIO_ReadInputDataBit(GPIOA,  GPIO_PIN_7)#define DS1302RST_H  		GPIO_SetBits(GPIOC,  GPIO_PIN_4)
#define DS1302RST_L  		GPIO_ResetBits(GPIOC,GPIO_PIN_4)#define WrEnDisCmd  0x8e  //写允许/禁止指令代码
#define WrEnDat     0x00 //写允许数据
#define WrDisDat    0x80 //写禁止数据
#define OscEnDisCmd 0x80 //振荡器允许/禁止指令代码
#define OscEnDat    0x00 //振荡器允许数据
#define OscDisDat   0x80 //振荡器禁止数据
#define WrMulti     0xbe //写入多个字节的指令代码
#define WrSingle    0x84 //写入单个字节的指令代码
#define RdMulti     0xbf //读出多个字节的指令代码
#define RamMulti_W 	0xFE //写入RAM多个字节的指令代码
#define RamMulti_R 	0xFf //读出多个RAM字节的指令代码#define LSB         0x01 void WrCmd(u8 CmdDat,u8  CmdWord);
void WriteByte_1302(u8 CmdDat,u8 Num,u8 *pSend);
void RecByte_1302(u8 CmdDat,u8 Num,u8 *pRec);
void ReCmd(u8 CmdDat,u8 CmdWord);
void DS1302_Init(void);
void Get_Time(void);
void Save_TimeDate(void);
void Check_date(void);
#endif 

注:以上笔记仅是个人学习笔记,若对你有帮忙那么最好不过,共勉!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

asp.net心理健康管理系统VS开发sqlserver数据库web结构c#编程计算机网页项目

一、源码特点 asp.net 心理健康管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 系统视频链接 https://www.bilibili.com/video/BV19w411H7P4/ 二、功能介绍 本系统使用Microsoft Visual Studio…

【ISP图像处理】Demosaic去马赛克概念介绍以及相关方法整理

1. 基本定义 使用彩色滤光器阵列(CFA)的数码相机需要一个去马赛克程序来形成完整的RGB图像。一般的相机传感器都是采用彩色滤光片阵列(CFA)放置在光感测单元上&#xff0c;在每个像素处仅捕获三种原色成分中的一种。 去马赛克方法主要关注于复原非常规区域&#xff0c;比如边缘…

【数据结构】树与二叉树(十九):树的存储结构——左儿子右兄弟链接结构(树、森林与二叉树的转化)

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语 5.2 二叉树5.3 树5.3.1 树的存储结构1. 理论基础2. 典型实例3. Father链接结构4. 儿子链表链接结构5. 左儿子右兄弟链接结构a. 定义树节点b. 创建树节点c. 使用左儿子右兄弟链接结构将树转化为二叉树d.…

【限时免费】20天拿下华为OD笔试之 【前缀和】2023B-最大子矩阵和【欧弟算法】全网注释最详细分类最全的华为OD真题题解

文章目录 题目描述与示例题目描述输入描述输出描述示例输入输出说明 解题思路如何表示一个子矩阵暴力解法二维前缀和优化二维前缀和矩阵的构建 代码解法一&#xff1a;二维前缀和PythonJavaC时空复杂度 解法二&#xff1a;暴力解法&#xff08;不推荐&#xff09;PythonJavaC时…

解析:什么是生成式AI?与其他类型的AI有何不同?

原创 | 文 BFT机器人 快速浏览一下头条新闻&#xff0c;你会发现生成式AI似乎无处不在。事实上&#xff0c;一些新闻标题甚至可能是通过生成式AI编写的&#xff0c;例如OpenAI旗下的ChatGPT&#xff0c;这个聊天机器人已经展现出了生成看起来像人类所写文本的惊人能力。 当人们…

Ubuntu18.04安装Loam保姆级教程

系统环境&#xff1a;Ubuntu18.04.6 LTS 1.Loam的安装前要求&#xff1a; 1.1 ROS安装&#xff1a;参考我的另一篇博客 Ubuntu18.04安装ROS-melodic保姆级教程_灬杨三岁灬的博客-CSDN博客还是那句话&#xff0c;有时候加了这行也不好使&#xff0c;我是疯狂试了20次&#xf…

用script去做前端html表格分页/排序

前言: 掘弃掉与后端交互做分页和互导,有利有弊吧; 在小数据的时候,如果不停来回朝服务端发送请求,会造成堵塞.于是,放弃了之前的前后端ajax方式去请求分页表格,使用script去弄一个,降低服务器的压力; 整体思路图: 代码构造: {% extends "order_header_same.html" …

stm32入门建议跳过固件库去学习hal库吗?

stm32入门建议跳过固件库去学习hal库吗? 如果要以单片机作为以后的工作方向&#xff0c;建议还是深入了解一下单片机的原理与机制&#xff0c;比如串口收发的时候&#xff0c;内部的寄存器是怎么工作的&#xff0c;中断又是怎么工作的&#xff0c;然后我们又是怎么进行中断处…

uniapp优化h5项目-摇树优化,gzip压缩和删除console.log

1.摇树优化 勾选摇树优化,打包删除死代码 2.gzip压缩和删除console.log 安装插件webpack和compression-webpack-plugin webpack插件 npm install webpack4.46.0 --save-devcompression-webpack-plugin插件 npm install compression-webpack-plugin6.1.1 --save-devconst Com…

代码随想录算法训练营第25天|216.组合总和III 17.电话号码的字母组合

JAVA代码编写 216. 组合总和III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k …

【观察】华为:数智世界“一触即达”,应对数智化转型“千变万化”

毫无疑问&#xff0c;数智化既是这个时代前进所趋&#xff0c;也是国家战略所指&#xff0c;更是所有企业未来发展进程中达成的高度共识。 但也要看到&#xff0c;由于大量新兴技术的出现&#xff0c;技术热点不停的轮转&#xff0c;加上市场环境的快速变化&#xff0c;让数智化…

数据结构--栈与队列

目录 前言 1.栈 1.1栈的概念及结构 1.2接口函数 1.3函数实现 1.4如何使用 2.队列 2.1队列的概念及结构 2.2接口函数 2.3函数实现 2.4如何使用 前言 前面我们已经学习了顺序表和链表&#xff0c;今天我们来学习栈与队列&#xff0c;这两种结构也属于线性表&#xff0c;实…

顺序表(数据结构与算法)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

从0开始学习JavaScript--JavaScript 流程控制

JavaScript中的流程控制结构是编写结构化、可读性强的代码的关键。本文将深入研究JavaScript中的流程控制&#xff0c;包括条件语句、循环结构、跳转语句等&#xff0c;并通过丰富的示例代码来更全面地了解和运用这些概念。 条件语句 条件语句用于基于不同的条件执行不同的代…

架构开发与优化咨询和实施服务

服务概述 得益于硬件平台算力的提升&#xff0c;汽车电子电气架构的集成度逐渐提高&#xff0c;从单体ECU、到功能域集成控制器、到区域集成控制器&#xff0c;多域融合成为了目前行业中软件工程的重要工作内容。同时&#xff0c;在传统控制器C代码开发的基础上&#xff0c;C、…

C#中.NET 7.0 Windows窗体应用通过EF访问新建数据库

目录 一、 操作步骤 二、编写EF模型和数据库上下文 三、移植&#xff08;Migrations&#xff09;数据库 四、编写应用程序 五、生成效果 前文已经说过.NET Framework4.8 控制台应用通过EF访问已经建立的和新建的数据库。 前文已经说过.NET 6.0 控制台应用通过EF访问…

μC/OS-II---事件标志组管理1(os_flag.c)

目录 事件标志组创建事件标志组删除事件标志组获取/等待 当任务要与多个事件同步时&#xff0c;就要使用事件标志组。一个事件标志就是一个二值信号&#xff0c;事件标志组是若干二值信号的组合。使用事件标志组同步任务分为独立性同步和关联性同步。 事件标志组创建 flags&a…

MySql分区

一、什么是分区 MySQL分区是一种数据库设计和管理技术&#xff0c;它允许你将表分割成独立的、具有特定规则的存储单元。每个分区可以独立地进行管理&#xff0c;包括备份、恢复和优化。分区的主要目的是提高查询性能、简化维护以及实现数据的更有效管理。 以下是MySQL分区的…

IDEA 集成 Docker 插件一键部署 SpringBoot 应用

目录 前言IDEA 安装 Docker 插件配置 Docker 远程服务器编写 DockerFileSpringBoot 项目部署配置SpringBoot 项目部署结语 前言 随着容器化技术的崛起&#xff0c;Docker成为了现代软件开发的关键工具。在Java开发中&#xff0c;Spring Boot是一款备受青睐的框架&#xff0c;然…

PCL 半径滤波剔除噪点(二)

目录 一、算法原理二、注意事项三、代码实现一、算法原理 PCL半径滤波是删除在输入的点云一定范围内没有达到足够多领域的所有数据点。通俗的讲:就是以一个点p给定一个范围r,领域点要求的个数为m,r若在这个点的r范围内部的个数大于m则保留,小于m则删除。因此,使用该算法时…