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  100

const u8 Ds1302SendBuf[6] = {0x23, 0x11, 0x15, 0x13, 0x49, 0x00}; //2016

unsigned 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;//设置使用带宽50Mhz
    GPIO_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;//设置使用带宽50Mhz
    GPIO_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)    //1
      DS1302DAT_H;
  else
      DS1302DAT_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}; //2016
    WrCmd(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 

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于社会群体算法优化概率神经网络PNN的分类预测 - 附代码

基于社会群体算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于社会群体算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于社会群体优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

秋招算法高频算法笔试题

自己在秋招过程中遇到的算法笔试题&#xff0c;包含中大厂&#xff0c;都附解析&#xff01; 汽水瓶 如果汽水瓶数目为1或者0&#xff0c;那么一瓶都喝不到 如果汽水瓶数目为2或者3&#xff0c;那么只能喝到一瓶 如果为2&#xff0c;喝到一瓶后手里一个瓶子都没有了&#xff…

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

文章目录 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.…

NET8 BlazorAuto渲染模式

.NET8发布后&#xff0c;Blazor支持四种渲染方式 静态渲染&#xff0c;这种页面只可显示&#xff0c;不提供交互&#xff0c;可用于网页内容展示使用Blazor Server托管的通过Server交互方式使用WebAssembly托管的在浏览器端交互方式使用Auto自动交互方式&#xff0c;最初使用 …

嵌入式系统中相关的高质量开源项目

关于GitHub&#xff0c;可能很多人误以为这是互联网人的专属&#xff0c;其实并不是&#xff0c;那上面嵌入式相关的开源项目是有很多的。现分享一些高星开源项目&#xff08;像RT-Thread、AWTK等大家都熟知的就不介绍了&#xff09;&#xff1a;Avem 项目链接&#xff1a; ht…

【广州华锐互动VRAR】VR元宇宙技术在气象卫星知识科普中的应用

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;和元宇宙等技术正逐渐走进我们的生活。这些技术为我们提供了一个全新的互动平台&#xff0c;使我们能够以更加直观和生动的方式了解和学习各种知识。在气象天文领域&#xff0c;VR元宇宙技术的应用也日益显现…

TikTok与媒体素养:如何辨别虚假信息?

在当今数字时代&#xff0c;社交媒体平台如TikTok已经成为信息传播和社交互动的主要渠道之一。然而&#xff0c;随之而来的是虚假信息的泛滥&#xff0c;这对用户的媒体素养提出了严峻的挑战。本文将探讨TikTok平台上虚假信息的现象&#xff0c;以及如何提高媒体素养&#xff0…

python3:turtle绘图 .2023-11-18

绘制一个菱形:四边相等且都为200像素;四个内角两边各为60度,上下各为120度 import turtle #导入turtle #画笔默认绘制方向为水平向右 turtle.right(-30) #画笔绘制方向向左(逆时针)旋转30度. turtle.fd(200) #画笔沿绘制方向绘制200像素长度 turtle.right(60) #画笔绘制方向在…

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

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

毅速丨金属3D打印将为模具制造企业带来变革

金属3D打印技术的发展给模具制造带来了巨大的创新价值&#xff0c;包括重塑产品、重组制造、重构业务。 首先&#xff0c;3D打印技术可以大幅度缩短模具制造的生产周期&#xff0c;提高生产效率。传统的模具制造需要经过多个工序和加工过程&#xff0c;而3D打印技术通过打印完成…

基于JAYA算法优化概率神经网络PNN的分类预测 - 附代码

基于JAYA算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于JAYA算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于JAYA优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

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

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

计算机系统基础>流水线

某指令流水线由5段组成&#xff0c;各段所需要的时间如下图所示。 连续输入100条指令时的吞吐率为&#xff08; &#xff09;。 吞吐率&#xff1d;需要处理的任务数/处理这些任务所需要的时间。 如港口的年货物吞吐率&#xff0c;就是讲1年时间内&#xff0c;处理了多少个集…

[C/C++]数据结构 栈和队列()

一:栈 1.1 栈的概念及结构 栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作,进行数据插入和删除操作的一端称为栈顶,另一端称为栈底,栈中的数据元素遵守先进后出的原则. 压栈:栈的插入操作叫做进栈/压栈/入栈,将数据插入栈顶 出栈:栈的删除操作也叫出…

简朴博客系统测试报告

文章目录 一. 项目简介二. 测试概要三. 测试环境四. 测试执行概况及功能测试1. 手工测试1.1 手动测试用例编写1.2 执行的部分测试用例 2. 自动化测试Selenium2.1 编写测试用例2.2 自动化测试代码 3. 测试结果 五. 发现的问题 一. 项目简介 简朴博客系统是采用前后端分离的方式…

【广州华锐互动】自然灾害科普3D体验展厅:培养安全意识,共创美好未来

在人类历史的进程中&#xff0c;灾难始终是我们不可避免的挑战。地震、洪水、火灾等自然灾害无情地摧毁我们的家园&#xff0c;带走我们的亲人。然而&#xff0c;随着科技的进步&#xff0c;我们已经有了更多的手段来预防和应对这些灾难。在这个背景下&#xff0c;自然灾害科普…

均匀光源积分球的应用领域有哪些

均匀光源积分球的主要作用是收集光线&#xff0c;并将其用作一个散射光源或用于测量。它可以将光线经过积分球内部的均匀分布后射出&#xff0c;因此积分球也可以当作一个光强衰减器。同时&#xff0c;积分球可以实现均匀的朗伯体漫散射光源输出&#xff0c;整个输出口表面的亮…

整形数据和浮点型数据在内存中的存储差别

愿所有美好如期而遇 我们先来看代码&#xff0c;猜猜结果是什么呢&#xff1f; int main() {//以整型数据的方式存储int n 10;float* m (float*)&n;//以整型数据的方式读取printf("%d\n", n);//以浮点型数据的方式2读取printf("%f\n", *m);printf(&…

自学嵌入式,已经会用stm32做各种小东西了

自学嵌入式&#xff0c;已经会用stm32做各种小东西了 1、stm32 工程中&#xff0c;定义一个变量&#xff0c;记录复位次数&#xff0c;即复位一次变量加一。要求不许用备份寄存器和 flash 保存信息。本题只讨论不断电热启动情况&#xff0c;至于冷启动&#xff0c;不在此讨论。…

国科大数据挖掘期末复习——聚类分析

聚类分析 将物理或抽象对象的集合分组成为由类似的对象组成的多个类的过程被称为聚类。由聚类所生 成的簇是一组数据对象的集合&#xff0c;这些对象与同一个簇中的对象彼此相似&#xff0c;与其他簇中的对象相异。 聚类属于无监督学习&#xff08;unsupervised learning&…