STM32/N32G455国民科技芯片驱动DS1302时钟---笔记
- 互联网
- 2025-08-12 09:54:02

这次来分享一下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注:以上笔记仅是个人学习笔记,若对你有帮忙那么最好不过,共勉!
STM32/N32G455国民科技芯片驱动DS1302时钟---笔记由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“STM32/N32G455国民科技芯片驱动DS1302时钟---笔记”