打印
[N32G45x]

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

[复制链接]
194|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zljiu|  楼主 | 2024-2-4 16:15 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
这次来分享一下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

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

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_46323814/article/details/134477389

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

3319

帖子

3

粉丝