查看: 1272|回复: 3

DS1302时钟库分享

[复制链接]

53

主题

55

帖子

430

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
430
发表于 2020-7-27 16:59:42 | 显示全部楼层 |阅读模式
大家好,最近发现IDE自身的库没有DS1302,因此依据网上的资料写了DS1302的库。这里将分享DS1302库的原理。

DS1302 是美国 DALLAS 公司推出的一种高性能、低功耗、带 RAM 的实时时钟电路, 它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能。且能自动对少于31天的月份日期进行调整,支持12小时制和24小时制。简而言之,利用DS1302时钟模块能帮助我们得到实时的时间。

首先创建新的库。利用Stduino IDE创建库还是很方便的。如下,点击菜单栏中的“库开发”,在下拉菜单栏中选择新建库:
m_a1905e719adbb40820eb51a209e5e565_r.png

接下来选择库开发的语言,这里我们选择C++。
2.png
之后输入我们创建的库的名称,建议名称简明扼要。我这里直接写的DS1302.h。(名称只能包含英文字母和数字)
3.png

点击确定后,IDE就自动生成了文件目录,还是很方便的。其中.cpp文件包含具体的功能实现代码、.h头文件包含库文件的预定义函数和变量,还包括库属性描述文件、关键词文件、示例文件。
ds1302——04.png 我们在左侧的文件树中,打开“libraries”文件夹,发现已经生成了DS1302相关的文件目录。
05.png

接下来我们来完善库的代码。



DS1302的内部寄存器构成如下:
ds1302时钟寄存器.png
首先,我们需要明确DS1302的操作顺序:
第一步,选择需要访问的存器(利用地址),并设置需要进行的操作(读/写 )。
第二步,访问相应时钟/日历寄存器或者RAM,并传出/传入数据。

而访问地址、传输数据通过命令字节来实现。
命令字节如下图所示。每次数据传输均由命令字节启动。
32命令字节构成.png
当需要读写时,最高位必须为逻辑1(即Bit 7),否则无法读写。Bit 6代表访问的内容是时钟和日历(逻辑0),还是RAM(逻辑1)。剩余的Bit 1到Bit 5指定要输入/输出的寄存器。最低位指定具体的操作(读:逻辑1;写:逻辑0)。始终从最低位(bit 0)开始输入命令字节。
具体而言,RAM命令与数据内容:
32-RAM命令字节.png
日历时钟寄存器命令与数据内容。
32日历寄存器命令与内容.png
因此,可以定义操作寄存器的地址:
  1. #define DS1302_SEC   0x80//秒寄存器地址
  2. #define DS1302_MIN   0x82//分寄存器地址
  3. #define DS1302_HR     0x84//时寄存器地址
  4. #define DS1302_DAY      0x86//日寄存器地址
  5. #define DS1302_MON    0x88//月寄存器地址
  6. #define DS1302_WEEK     0x8a//星期寄存器地址
  7. #define DS1302_YEAR     0x8c//年份寄存器地址
复制代码
以及整体的时间数据:
  1. typedef struct __TIME__
  2. {
  3.     unsigned char Second;
  4.     unsigned char Minute;
  5.     unsigned char Hour;
  6.     unsigned char Week;
  7.     unsigned char Day;
  8.     unsigned char Month;
  9.     unsigned char  Year;
  10. }TIME;    //定义时间类型
复制代码
因此我们需要用到的函数,包括读写操作,还需要定义字节操作的函数(初始只能读写比特)。
  1. extern void DS1302_Write(unsigned char ucAddr, unsigned char ucDa);//写操作,包括地址与写的数据(字节)两个参数
  2. extern unsigned char DS1302_Read(unsigned char ucAddr);//读操作

  3. extern void DS1302_InputByte(unsigned char dat);//字节传入
  4. extern unsigned char DS1302_OutputByte(void) ;//字节传出

  5. extern void DS1302_SetProtect(unsigned char flag) ;//设置位保护

  6. extern void DS1302_SetTime(unsigned char Address, unsigned char Value);//设置时间
  7. extern void DS1302_GetTime(TIME *Time);//获取时间

  8. extern void DS1302_Init(void);//初始化
复制代码
数据传输可以通过命令字节来控制,但是需要遵循一定时序,从而保证数据有条不紊的传输。
数据传输时序如下图所示。
32-ds1302时序图.png
简而言之,需要遵循:
  • 数据传输前,需要设置RST为高电平,直到传输完毕,设置RST为低电平,结束传输。
    RST输入有两个作用。第一,打开控制逻辑(该部分允许访问地址/命令序列的移位寄存器。)第二,RST信号提供了终止单字节或者多字节数据传输的方法。
  • 数据开始传输前,在设置RST为高电平前,需将SCLK设置为低电平。
    时钟周期是下降沿跟着上升沿的序列。在时钟处于上升沿时数据才被传输,在时钟的下降沿时停止输出。因此当RST设置为高电平开始传送数据前,SCLK必须设置为低电平。
  • 如果RST输入为低电平,则所有的数据传输终止,并且IO引脚变为高阻抗状态,因此数据传输过程中,RST要一直置为1。
  • 传输完毕时,先把CLK置为高电平,确保无问题;再将RST置0,终止传输。
  • 上电时,RST必须为逻辑0,直到VCC> 2.0V。此时RST也必须被置为逻辑1状态时,SCLK为逻辑0。

因此,可以再添加一些高低电平设置的预定义:
  1. #define DS1302_RST 2     //RST复位线引脚
  2. #define DS1302_IO 3      //IO数据线引脚
  3. #define DS1302_CLK 4     //SCLK时钟线引脚


  4. #define DS1302_RST_0 digitalWrite(DS1302_RST,LOW)//复位置为低电平
  5. #define DS1302_RST_1 digitalWrite(DS1302_RST,HIGH)//复位置为高电平

  6. #define DS1302_IO_0 digitalWrite(DS1302_IO,LOW)//IO置为低电平
  7. #define DS1302_IO_1 digitalWrite(DS1302_IO,HIGH)//IO置为高电平

  8. #define DS1302_CLK_0 digitalWrite(DS1302_CLK,LOW)//时钟置为低电平
  9. #define DS1302_CLK_1 digitalWrite(DS1302_CLK,HIGH)//时钟置为高电平
复制代码
DS1302.h的基本内容写完啦,如下:
  1. /***********************************************************************
  2.   * @代码说明:DS1302的库函数
  3.   * @作者:admin
  4.   * @日期:2020/07/27
  5.   * @开发指导:wiki.stduino.com
  6.   ***********************************************************************/

  7. #ifndef __DS1302_H__
  8. #define __DS1302_H__
  9. #include "Stduino.h"




  10. //DS1302 IO设置
  11. #define DS1302_RST 2     //RST复位线引脚
  12. #define DS1302_IO 3      //IO数据线引脚
  13. #define DS1302_CLK 4     //SCLK时钟线引脚


  14. #define DS1302_RST_0 digitalWrite(DS1302_RST,LOW)//复位置为低电平
  15. #define DS1302_RST_1 digitalWrite(DS1302_RST,HIGH)//复位置为高电平

  16. #define DS1302_IO_0 digitalWrite(DS1302_IO,LOW)//IO置为低电平
  17. #define DS1302_IO_1 digitalWrite(DS1302_IO,HIGH)//IO置为高电平

  18. #define DS1302_CLK_0 digitalWrite(DS1302_CLK,LOW)//时钟置为低电平
  19. #define DS1302_CLK_1 digitalWrite(DS1302_CLK,HIGH)//时钟置为高电平


  20. //宏定义
  21. #define DS1302_SEC   0x80//秒寄存器地址
  22. #define DS1302_MIN   0x82//分寄存器地址
  23. #define DS1302_HR     0x84//时寄存器地址
  24. #define DS1302_DAY      0x86//日寄存器地址
  25. #define DS1302_MON    0x88//月寄存器地址
  26. #define DS1302_WEEK     0x8a//星期寄存器地址
  27. #define DS1302_YEAR     0x8c//年份寄存器地址


  28. typedef struct __TIME__
  29. {
  30.     unsigned char Second;
  31.     unsigned char Minute;
  32.     unsigned char Hour;
  33.     unsigned char Week;
  34.     unsigned char Day;
  35.     unsigned char Month;
  36.     unsigned char  Year;
  37. }TIME;    //定义时间类型




  38. extern void DS1302_Write(unsigned char ucAddr, unsigned char ucDa);//写操作,包括地址与写的数据(字节)两个参数
  39. extern unsigned char DS1302_Read(unsigned char ucAddr);//读操作

  40. extern void DS1302_InputByte(unsigned char dat);//字节传入
  41. extern unsigned char DS1302_OutputByte(void) ;//字节传出

  42. extern void DS1302_SetProtect(unsigned char flag) ;//设置位保护

  43. extern void DS1302_SetTime(unsigned char Address, unsigned char Value);//设置时间
  44. extern void DS1302_GetTime(TIME *Time);//获取时间

  45. extern void DS1302_Init(void);//初始化
  46. extern void DS1302_ON_OFF(bool FLAG_ON_OFF);//


  47. extern TIME DS1302Data;//用于储存时间数据的整体
  48. extern bool Flag_Time_Refresh;


  49. #endif
复制代码


接下来实现每个操作函数,这一部分在DS1302.cpp中完成。
首先是,字节输入与输出:
  1. //****************************************************
  2. //写入一字节:上升沿写入数据
  3. //****************************************************
  4. void DS1302_InputByte(unsigned char dat)   
  5. {
  6.     unsigned char i;

  7.     pinMode(DS1302_IO,OUTPUT);

  8.     for(i=0; i<8; i++)
  9.     {
  10.         if((dat & 0x01) == 1)
  11.         {
  12.             DS1302_IO_1;
  13.         }
  14.         else
  15.         {
  16.             DS1302_IO_0;
  17.         }
  18.          
  19.         
  20.         DS1302_CLK_0;               //低电平
  21.         
  22.         delayMicroseconds(2);
  23.         
  24.         DS1302_CLK_1;              //高电平,结合低电平,一次上升沿,写入数据
  25.         
  26.         delayMicroseconds(2);
  27.         dat >>= 1;
  28.     }
  29. }

  30. //****************************************************
  31. //读取一字节:下降沿读取数据
  32. //****************************************************
  33. unsigned char DS1302_OutputByte(void)   
  34. {
  35.     unsigned char i;
  36.     unsigned char dat;
  37.     pinMode(DS1302_IO,INPUT);
  38.     for(i=0; i<8; i++)
  39.     {
  40.         DS1302_CLK_1;                   //高电平
  41.         delayMicroseconds(2);
  42.         DS1302_CLK_0;                   //低电平,结合高电平,一次下降沿读出数据
  43.         delayMicroseconds(2);
  44.         dat >>= 1;                  
  45.         if( digitalRead(DS1302_IO) == HIGH )
  46.             dat |= 0x80;                //或运算,最高位置1
  47.         else
  48.             dat &= 0x7F;                //与运算,最高位清0      
  49.     }
  50.     return(dat);
  51. }
复制代码
读/写操作:
  1. //****************************************************
  2. //写操作函数 Addr: DS1302地址, Data: 要写的数据
  3. //读写操作,都需要RST置高电平,在这之前,CLK需要为低电平
  4. //****************************************************
  5. void DS1302_Write(unsigned char Addr, unsigned char Data)
  6. {
  7.     DS1302_RST_0;               
  8.     delayMicroseconds(2);
  9.     DS1302_CLK_0;                       //CLK置为低电平
  10.     delayMicroseconds(2);
  11.     DS1302_RST_1;                       //RST置1
  12.     delayMicroseconds(2);
  13.     DS1302_InputByte(Addr);             // 访问地址
  14.     DS1302_InputByte(Data);             // 写1字节数据
  15.     DS1302_CLK_1;                       // 将时钟电平置于高电平状态 ,处于已知状态
  16.     delayMicroseconds(2);
  17.     DS1302_RST_0;                       //RST置0,终止传输
  18.     delayMicroseconds(2);
  19. }

  20. //****************************************************
  21. //读操作函数:包括读取数据的地址,时序同上
  22. //****************************************************
  23. unsigned char DS1302_Read(unsigned char Addr)
  24. {
  25.     unsigned char Data;
  26.     DS1302_RST_0;
  27.     delayMicroseconds(2);
  28.     DS1302_CLK_0;
  29.     delayMicroseconds(2);
  30.     DS1302_RST_1;
  31.     delayMicroseconds(2);
  32.     DS1302_InputByte(Addr|0x01);        // 地址,命令
  33.     ucData = DS1302_OutputByte();         // 读1Byte数据
  34.     DS1302_CLK_1;
  35.     delayMicroseconds(2);
  36.     DS1302_RST_0;
  37.     delayMicroseconds(2);
  38.     return(Data);
  39. }

复制代码
写保护函数:
控制寄存器(CONTROL,上图左边第八个,地址为0x8E),定义位7是写保护位。前七个位(位0 – 6)被强制为0,并且在读取时始终为0。在对时钟或RAM进行任何写操作之前,位7必须为0。当高电平时,写保护位可防止对其他任何寄存器的写操作。初始开机状态并未定义,因此,在尝试写入设备之前,控制寄存器最高位置0。
  1. //****************************************************
  2. //写保护:
  3. //****************************************************
  4. void DS1302_SetProtect(unsigned char flag)      
  5. {
  6.     if(flag)
  7.         DS1302_Write(0x8E,0x80);            //保护,此时无法对其他寄存器写数据
  8.     else
  9.         DS1302_Write(0x8E,0x00);            //不保护,此时可对其他寄存器写数据
  10. }
复制代码
时钟停止标志:秒寄存器(sec)的bit 7定义为时钟停止标志。当该位置1时,时钟振荡器停止工作,DS1302进入低功耗待机模式,电流消耗小于100纳安。当该位写入逻辑0时,时钟将启动工作。利用该位来关闭振荡器。
  1. //****************************************************
  2. //DS1302振荡器停止
  3. //****************************************************
  4. void DS1302_HALT(bool FLAG_ON)
  5. {
  6.     unsigned char Second;
  7.     Second = DS1302_Read(DS1302_SEC);
  8.     if(FLAG_ON == 0)
  9.         DS1302_Write(DS1302_SEC,Second | 0x80);              //停止振荡
  10.     else
  11.         DS1302_Write(DS1302_SEC,Second & 0x7f);              //开启振荡
  12. }
复制代码
在此基础上,我们可以检查时钟是否在振荡,在开始的时候,需要保证时钟正在正常工作因此,需要检验秒寄存器的最高位HALT标志状态。如果处于停止,则需要启动,如果在运行就不需要管。
  1. //****************************************************
  2. //初始化:检查HALT标志
  3. //****************************************************
  4. void DS1302_Init(void)
  5. {
  6.     unsigned char Second;

  7.     pinMode(DS1302_RST,OUTPUT);
  8.     pinMode(DS1302_IO,OUTPUT);
  9.     pinMode(DS1302_CLK,OUTPUT);

  10.     Second = DS1302_Read(DS1302_SEC);
  11.     if(Second&0x80)      
  12.         DS1302_SetTime(DS1302_SEC,Second & 0x7f);    //开启振荡   
  13. }
复制代码
因此,整个DS1302.cpp的代码如下:
  1. #include "DS1302.h"
  2. /***********************************************************************
  3.   * @代码说明:本代码内容用于快速使用DS1302
  4.   * @作者:Astilbe
  5.   * @日期:2020/07/26
  6.   * @开发指导:wiki.stduino.com
  7.   ***********************************************************************/
  8. /* Includes ------------------------------------------------------------------*/
  9. //例如:#include "stm32f10x_abc.h"
  10. /*上面不用动,开始你的表演 ------------------------------------------------------------------*/
  11. #include "DS1302.h"

  12. TIME DS1302Data;
  13. bool Flag_Time_Refresh = 1;

  14. //****************************************************
  15. //写入一字节:上升沿写入数据
  16. //****************************************************
  17. void DS1302_InputByte(unsigned char dat)   
  18. {
  19.     unsigned char i;

  20.     pinMode(DS1302_IO,OUTPUT);

  21.     for(i=0; i<8; i++)
  22.     {
  23.         if((dat & 0x01) == 1)
  24.         {
  25.             DS1302_IO_1;
  26.         }
  27.         else
  28.         {
  29.             DS1302_IO_0;
  30.         }
  31.          
  32.         
  33.         DS1302_CLK_0;               //低电平
  34.         
  35.         delayMicroseconds(2);
  36.         
  37.         DS1302_CLK_1;              //高电平,结合低电平,一次上升沿,写入数据
  38.         
  39.         delayMicroseconds(2);
  40.         dat >>= 1;
  41.     }
  42. }

  43. //****************************************************
  44. //读取一字节:下降沿读取数据
  45. //****************************************************
  46. unsigned char DS1302_OutputByte(void)   
  47. {
  48.     unsigned char i;
  49.     unsigned char dat;
  50.     pinMode(DS1302_IO,INPUT);
  51.     for(i=0; i<8; i++)
  52.     {
  53.         DS1302_CLK_1;                   //高电平
  54.         delayMicroseconds(2);
  55.         DS1302_CLK_0;                   //低电平,结合高电平,一次下降沿读出数据
  56.         delayMicroseconds(2);
  57.         dat >>= 1;                  
  58.         if( digitalRead(DS1302_IO) == HIGH )
  59.             dat |= 0x80;                //或运算,最高位置1
  60.         else
  61.             dat &= 0x7F;                //与运算,最高位清0      
  62.     }
  63.     return(dat);
  64. }
复制代码















回复

使用道具 举报

53

主题

55

帖子

430

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
430
 楼主| 发表于 2020-7-27 20:52:28 | 显示全部楼层
接下来把.cpp和.h等四个文件都完善好,点击保存了。随后手写example.ino,编译~~~
  1. #include <DS1302.h>

  2. unsigned char Alarm_Hour=6;          // 闹钟小时设置
  3. unsigned char Alarm_Minute=30;        // 闹钟分钟设置
  4. bool Always=false;                 //是否不间断地输出时间到串口(每隔 1 秒)

  5. void setup()
  6. {

  7.   DS1302_Init();
  8.   Serial.begin(9600);
  9.   Serial.println("欢迎使用!");  
  10.   DS1302_GetTime(&DS1302Data);
  11.   Show_RTCC();
  12.   Serial.println("输入 "help" 获得帮助");
  13. }



  14.   Serial.print(DS1302Data.Hour);
  15.   Serial.print(':');
  16.   Serial.print(DS1302Data.Minute);
  17.   Serial.print(':');
  18.   Serial.println(DS1302Data.Second);
  19. }

  20. // 获取串口输入
  21. void Scan_Input()
  22. {
  23.   String comdata="";
  24.   while (Serial.available() > 0)  
  25.     {
  26.      comdata += char(Serial.read());
  27.      delay(2);
  28.     }
  29.    
  30.     if(comdata.length()==20 && comdata.startsWith("set"))
  31.     {
  32.       Set_Time(comdata);
  33.     }
  34.     else if(comdata=="show")
  35.     {
  36.       Serial.println("The Time Now Is:");
  37.       Show_RTCC();
  38.     }
  39.     else if(comdata=="help")
  40.     {
  41.       help();
  42.     }
  43.     else if(comdata.length()==11 && comdata.endsWith("hours"))
  44.     {
  45.       Set_HourSystem(comdata);
  46.     }
  47. }

  48. //帮助内容
  49. void help()
  50. {
  51.   Serial.println("************************************* HELP *****************************************");
  52.   Serial.println("Type "set YY MM DD WEEK HH MM" To Set The Time!");
  53.   Serial.println("Such As Type "set 08 08 08 1 12 00" To Set The Time As 2008-8-8 Monday 12:00");
  54.   Serial.println("Type "show" To Display The Time Now!");
  55.   Serial.println("Type "set 24hours" or "set 12hours" To Change The Hour System");
  56.   Serial.println("************************************* HELP *****************************************");
  57. }

  58. void loop()
  59. {
  60.   Scan_Input();
  61.   DS1302_GetTime(&DS1302Data);        //获取当前RTCC值
  62.   
  63. }
复制代码


回复

使用道具 举报

53

主题

55

帖子

430

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
430
 楼主| 发表于 2020-7-28 22:28:47 | 显示全部楼层
随后,在把用来介绍的keywords.txt和属性说明完善即可。最后就是将内容分享至Stduino平台,进行共享啦~~~~第一步,先上传我们的文件:
从此处找到文件所在位置,打开库所在文件夹:
01.png
随后把文件推送到gitee中。

第二步,关联gitee库
先从网页导航栏找到库函数分享:
02.png
随后,在新页面中选择库分享,在新界面中注册:
03.png
填写相关信息:
04.png
点击提交即可。

欢迎大家分享库文件,丰富Stduino生态~~~


回复

使用道具 举报

0

主题

2

帖子

24

积分

新手上路

Rank: 1

积分
24
发表于 2021-7-25 19:03:55 | 显示全部楼层
很棒,感谢分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

热门推荐

今天在文涛老大的帮助下我的stm32zet6终于把simlpefoc库跑起...
今天在文涛老大的帮助下我
[md]首先本身是刚刚从MDK转到arduino过来的新人,只因为要完开源的simplefoc,期间由
Stduino UNO mini与7线oled显示屏实现Message Box
Stduino UNO mini与7线ole
[md]手头上有块7线的Oled显示屏一直想用stm32驱动下,正好现在通过Stduino UNO mini和
DS1302时钟库分享
DS1302时钟库分享
大家好,最近发现IDE自身的库没有DS1302,因此依据网上的资料写了DS1302的库。这里将
如何实现stm32arduino在官方ide里的tools中的usb设置?
如何实现stm32arduino在官
[md]在官方ide里添加了stm32官方arduino库之后会有tool选项,这个会影响有usb的库的条
stm32 小蓝板快速点亮一颗LED灯(一),无需刷Bootloader
stm32 小蓝板快速点亮一颗
关键词:stm32 小蓝板 STM32F103C8T6 Stduino IDE Stduino Nano 点亮一颗LED灯 通过St
下载库并打开示例教程Arduino框架
下载库并打开示例教程Ardu
[md]注意是Arduino框架!Arduino框架!Arduino框架下! 在对应项目工作空间安装库后,如
37种传感器(五)热敏电阻模块+Stduino Nano&UNO
37种传感器(五)热敏电阻
Stduino Uno/Nano-37种传感器(五)热敏电阻模块 关键词:51 stm32 arduino stduino
©2001-2018  Stduino官网  Powered by©Discuz!   ( 皖ICP备17011998号 )
快速回复 返回顶部 返回列表