你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32F103——DS1302日期时间+串口打印

[复制链接]
STMCU小助手 发布时间:2022-8-22 17:03
最近终于又腾出时间写写学习笔记了,其实当时写是最好的,能对出的问题更深刻,现在呜呜呜。忘差不多了。主要的问题就是 STM32不像51 不需要设置输入输出模式,直接操作IO就行,但是STM32 得设置,就是因为对这个不了解 所以卡了一两天。STM32要根据不用应用状态设置不同的模式。

DS1302时钟模块相关介绍
基本介绍
概述

DS1302 可慢速充电实时时钟芯片包含实时时钟/日历和 31 字节的非易失性静态 RAM。它经过一个简
单的串行接口与微处理器通信。实时时钟/日历可对秒,分,时,日,周,月,和年进行计数,对于小于
31 天的月,月末的日期自动进行调整,还具有闰年校正的功能。时钟可以采用 24 小时格式或带 AM(上
午)/PM(下午)的 12 小时格式。31 字节的== RAM== 可以用来临时保存一些重要数据。使用同步串行通信,
简化了 DS1302 与微处理器的通信。与时钟/RAM 通信仅需3 根线:(1)RST(复位),(2)I/O(数据线)
和(3)SCLK(串行时钟)。数据可以以每次一个字节的单字节形式或多达 31 字节的多字节形式传输。DS1302
能在非常低的功耗下工作,消耗小于 1µW 的功率便能保存数据和时钟信息。

特点

76cea5d1d53047e99d893fbe136c3a24.png

各引脚功能

e28200489bb444479bb29c621bafa387.png

各引脚的功能:
Vcc1:主电源;Vcc2:备份电源。 当Vcc2>Vcc1+0.2V时,由Vcc2向DS1302供电,当Vcc2<Vcc1时,由Vcc1向DS1302供电。
SCLK: 串行时钟,输入,控制数据的输入与输出;
I/O: 三线接口时的双向数据线;
CE: 输入信号,在读和写的器件必须为高。该引脚有两个功能:1.开始控制字访问移位寄存器的控制逻辑;2.提供结束单字节或多字节数据传输的方法。

相关寄存器
有关日历、时间的寄存器共有12个,其中有7个寄存器(读时81H——8DH,写时80H——8CH==)存放的数据格式是BCD码形式。如图所示
de51566cf4bd45a7ba6bc90ac73d430f.png

小时寄存器
位7用于定义DS1302是采用12小时模式还是24小时模式。高:12小时模式。在12小时模式时,位5 为1时,表示PM。在24小时模式时,为5是第二个10小时位。

秒寄存器
的就位7定义为时钟暂停标志(CH)。1:时钟振荡器停止,DS1302进入低功耗状态,当该位置为0时,时钟开始运行。

控制寄存器
的位7是写保护位(WP),其他7位均置0,对时钟和RAM进行写操作时,WP必须为0,也就是关闭写保护,当WP为1时,就是只读模式。

DS1302相关的RAM地址
DS1302中附加31字节静态RAM的地址如下图

97e6104f2fdb44408dd6e44c322b52cd.png

DS1302的工作模式寄存器
所谓的突发模式(BURST模式)就是一次性传送多个字节的时钟信号和RAM数据。比如我可以一次性把时间和日期写入,也可以一次性的读出时间和日期。

c8536ddc7df545858b7bbd234ecdeed3.png

通过对 31(十进制)位地址寻址(地址/命令位于 1 至 5=逻辑 1),可以把时钟/日历或 RAM 寄存器规定为多字节方式。如前所述,位 6 规定时钟或 RAM 而位 0 规定读或写。在时钟\日历寄存器中的地址 9 至 31或 RAM 寄存器中的地址 31 不能存储数据。在多字节方式中读或写从地址 0 的位 0 开始。当以多字节方式写时钟寄存器时,必须按数据传送的次序写最先 8 个寄存器。意思就是写我们不是只有7个吗?时分秒、年月日、周一共七个 但是吧它得字节数为8 所有要写够8次。
但是,当以多字节方式写 RAM 时,为了传送数据不必写所有 31 个字节。不管是否写了全部 31 个字节,所写的每一个字节都将传送至 RAM。

e9b7875ff0c0441bbc25c2fafbdf48a4.png

DS1302充电寄存器
这个我没整过,全部复制手册的。哈哈

这个寄存器控制 DS1302 的慢速充电特性。图 4 的简化电路表示慢速充电器的基本组成。慢速充电选择(TCS)位(位 4-7)控制慢速充电器的选择。为了防止偶然的因素使之工作,只有 1010 模式才能使慢
速充电器工作,所有其它的模式将禁止慢速充电器。DS1302 上电时,慢速充电器被禁止。二极管选择(DS)位(位 2-3)选择是一个二极管还是两个二极管连接在 Vcc2 与 Vcc1 之间。如果 DS 为 01,那么选择一个二极管;如果 DS 为 10,则选择两个二极管。如果 DS 为 00 或 11,那么充电器被禁止,与 TCS 无关。RS 位(位0-1)选择连接在 Vcc2 与 Vcc1 之间的电阻。电阻选择(RS)位选择的电阻如下:

c47c6de3f56b41b385c60285dd2120f9.png

如果 RS 为 00,充电器被禁止,与 TCS 无关。
二极管和电阻的选择用户根据电池和超容量电容充电所需的最大电流决定。最大充电电流可以如下列
所说明的那样进行计算。假定 5V 系统电源加到 Vcc2 而超容量电容接至 Vcc1。再假设慢速充电器工作时在Vcc2 和 Vcc1 之间接有一个二极管和电阻 R1。因而最大电流可计算如下:
Imax =(5.0V-二极管压降)/R1
=(5.0V-0.7V)/2kΩ
= 2.2mA
显而易见,当超容量电容充电时,Vcc2 和 Vcc1 之间的电压减少,因而充电电流将会减小。

时序图
我们首先得给DS1302时钟模块写入时间和日期,然后呢这个时钟会自己走,我们之后只需要读取时间和日期即可。我们直接看时序图 编写代码

c00fe46055664d1e8df0b470fbcade87.png

单字节写时序
数据输入

跟随在输入写命令字节的 8 个 SCLK 周期之后,在下 8 个 SCLK 周期的上升沿输入数据。如果有额外的SCLK 周期,它们将被忽略。输入从位 0 开始。

8e051ec92c9d43eab5bed3d945f45b77.png

98aea29ff006494f894633461dbb789e.png

上面时序图是前8位是地址,后8位是数据。
我们根据上面的时序图 来编写 单字节写的一个函数
根据上面的编写一些代码

  1. /******************************************************************
  2. 描述: DS1302 写一字节 函数
  3. *******************************************************************/
  4. void ds1302_write_byte(uint8_t addr_or_data)
  5. {
  6.         uint8_t i;
  7.         DS1302_SET_OUT;                //DS1302设置成输出模式(推挽输出)
  8.         for(i=0;i<8;i++)
  9.         {
  10.                 if(addr_or_data & 0x01)                //从低位开始传输
  11.                 {
  12.                         DS1302_DAT_HIGH;                //DAT引脚拉高电平
  13.                 }
  14.                 else
  15.                 {
  16.                         DS1302_DAT_LOW;                        //DAT引脚拉低电平
  17.                 }
  18.                 addr_or_data >>= 1;                //右移一位 为下一位写做准备
  19.                 DS1302_CLK_HIGH;                //拉高时钟表示已经发送 让对方读
  20.                 DS1302_CLK_LOW;                        //拉低时钟准备继续放新的数据位
  21.         }
  22. }

  23. /******************************************************************
  24. 描述: DS1302 写命令 函数
  25. *******************************************************************/
  26. void ds1302_write_cmd(uint8_t addr,uint8_t dat)
  27. {
  28.         DS1302_RST_LOW;                //RST拉低
  29.         DS1302_CLK_LOW;                //时钟SCLK也拉低
  30.         DS1302_RST_HIGH;        //准备开始写
  31.         ds1302_write_byte(addr);        //写入要写的地址
  32.         ds1302_write_byte(dat);                //写入地址的数据
  33.         DS1302_RST_LOW;                //关闭 表示结束        
  34. }
复制代码

725548f6b855431780b6faefc1153cfb.png

看上面的图,比如我想写入时 为18点 时的写寄存器是84H 数据就是18点 但是DS1302存储格式为 BCD 码那就是 0x18。
那写入 时 为18点 的代码则是:

  1. ds1302_write_cmd(0x84,0x18); //设置当前 时  为 18点
复制代码

单字节读时序


5da229964b8e48a194da76b3da989361.png

61da1aba861e425f8069e219866184bc.png

  1. /******************************************************************
  2. 描述: DS1302 读一字节 函数
  3. *******************************************************************/
  4. uint8_t ds1302_read_byte(void)
  5. {
  6.         uint8_t i;
  7.         uint8_t dat = 0;//用于存放读取到的数据
  8.         DS1302_SET_IN;        //这里DAT引脚要设置输入模式了(上拉输入) 浮空输入我试过也可以
  9.         for(i=0;i<8;i++)
  10.         {
  11.                 dat >>= 1;                //左移一次 低位开始 共有效左移7次
  12.                 if( GPIO_ReadInputDataBit(DS1302_DAT_PORT, DS1302_DAT_PIN) == SET)
  13.                 {
  14.                         dat = dat | 0x80;
  15.                 }
  16. //                else
  17. //                {
  18. //                        dat = dat & 0x7f;
  19. //                }
  20.                 DS1302_CLK_HIGH;        //时钟拉高
  21.                 DS1302_CLK_LOW;                //时钟拉低 准备判断下一位数据
  22.         }
  23.         return dat;        //返回读取到的数据
  24. }
  25. /*DS1302读取数据函数*/
  26. unsigned char ds1302_read_data(unsigned char addr)
  27. {
  28.         unsigned char data; //用于存放接收的数据
  29.         RST = 0; //RST拉低
  30.         SCLK = 0; //时钟SCLK也拉低
  31.         RST = 1; //准备开始写        
  32.         ds1302_write_byte(addr);         //写入要读取的地址
  33.         data = ds1302_read_byte(data); //读取地址的数据
  34.         RST = 0;//关闭 表示结束
  35.         
  36.         return data;        //返回读取到的数据
  37. }
  38. /******************************************************************
  39. 描述: DS1302 读数据 函数
  40. 参数: addr:要读取数据的地址
  41. *******************************************************************/
  42. uint8_t ds1302_read_data(uint8_t addr)
  43. {
  44.         uint8_t dat = 0;                //用于存放读取到的数据
  45.         DS1302_RST_LOW;                        //RST拉低
  46.         DS1302_CLK_LOW;                        //CLK拉高
  47.         DS1302_RST_HIGH;                //RST拉高 开始
  48.         ds1302_write_byte(addr);        //先写要读取的数据的地址
  49.         dat = ds1302_read_byte();        //然后进行读取数据
  50.         DS1302_RST_LOW;                        //RST拉低 结束
  51.         return dat;        //返回读取到的数据
  52. }
复制代码

我们想读取时 里面时间 看看现在是几点 时 读寄存器是85H

  1. time = ds1302_read_data(0x85);
  2. /*time就是当前小时数据啦*/
复制代码

bf2e73291c4844a89ca3cc0cf299e274.png

写保护寄存器
当我们进行写的时候 比如写入当前的小时时间 当前的秒啊 啥的 就必须 WP位为0

例如:设置DS1302当前的小时为 12点 那么BCD码就是 0X12

  1. /*在写入之前 我们必须要让 WP这位 置 0  
  2.   也就是关闭写保护 寄存器0X8E*/
  3. ds1302_write_cmd(0X8E,0X00);        //关闭写保护

  4. /*设置DS1302时间*/
  5. ds1302_write_cmd(0X84,0x12);        //设置当前小时为 12点

  6. /*那我们再设置完DS1302时间我们一般就 WP 位置1
  7.   开始写保护(只读模式)防止错改时间*/
  8. ds1302_write_cmd(0X8E,0X80);        //开启写保护(只读模式)  
复制代码

写保护寄存器的位 7 是写保护位。开始 7 位(位 0-6)置为零,在读操作时总是读出零。在对时钟或
功能 字节数 脉冲数
CLOCK 8 72
RAM 31 256
DS1302
RAM 进行写操作之前,位 7 必须为零。当它为高电平时,写保护位禁止对任何其它寄存器进行写操作。

时钟/日历多字节(Burst)方式
所谓的突发模式(BURST模式)就是一次性传送多个字节的时钟信号和RAM数据。比如我可以一次性把时间和日期写入,也可以一次性的读出时间和日期。
这里没写。。。。。略过0.0




BCD转十进制和十进制转BCD
由于DS1302是以BCD码存放的,那么如果我们读出来为了方便查看我这里是转十进制。
写入的时候 先十进制转BCD 再写入
读出的时候 先BCD转十进制 再运用
这样我们就可以一直是十进制啦。

十进制转BCD
比如 12 转成 BCD 也就是 0X12了对吧。
那么其实就是 取出十位 1 然后放到高4位 然后取出个位 2 放到低4位
就是十六进制 0X12 代码如下

  1. /******************************************************************
  2. 描述: 十进制 转 BCD 函数 例如 12 转成 0X12
  3. 参数: dec:需要转换的十进制数据 转换的个数
  4. *******************************************************************/
  5. void dec_to_bcd(uint8_t *dec,uint8_t times)
  6. {
  7.         uint8_t i;
  8.         for(i=0;i<times;i++)
  9.         {
  10.                 dec<i> = ((dec<i>/10)<<4) | (dec<i>%10);
  11.         }
  12. }

  13. /********************运用*************************/
  14. //日期和时间定义22年5月27日14点22分0秒周五                  
  15. uint8_t ds1302_time[8] = {22,5,27,14,22,00,2};//年 月 日 时 分 秒 周

  16. /*写入先转成BCD在写入*/
  17. dec_to_bcd(ds1302_time,7);        //将时间十进制转成BCD格式 一共7个
  18. </i></i></i>
复制代码

BCD转十进制
  1. /******************************************************************
  2. 描述: BCD 转 十进制 函数 例如 0X24 转成 24
  3. 参数: dec:需要转换的BCD数据 转换的个数
  4. *******************************************************************/
  5. void bcd_to_dec(uint8_t *bcd,uint8_t times)
  6. {
  7.         uint8_t i;
  8.         for(i=0;i<times;i++)
  9.         {
  10.                 bcd = ((bcd>>4)*10) + (bcd&0x0f);
  11.         }
  12. }

  13. /********************运用*************************/
  14. uint8_t hour;        //存放小时
  15. hour = ds1302_read_data(0X85);        //读取小时
  16. bcd_to_dec(&hour ,1);                        //将BCD码转成十进制 转1个
复制代码

代码
部分代码呈现

ds1302.c
  1. #include "ds1302.h"

  2. //日期和 时间 定义                   年 月 日 时 分 秒 周
  3. uint8_t ds1302_time[8] = {22,4,19,14,22,00,0X02};

  4. /******************************************************************
  5. 描述: DS1302 DAT设置成输入模式 函数
  6. *******************************************************************/
  7. void ds1302_set_input_mode(void)
  8. {
  9.         GPIO_InitTypeDef DS1302_Struction;                                //定义结构体成员
  10.         RCC_APB2PeriphClockCmd(DS1302_DAT_RCC, ENABLE);        //打开时钟
  11.         
  12.         DS1302_Struction.GPIO_Pin  = DS1302_DAT_PIN;                //引脚
  13.         DS1302_Struction.GPIO_Mode = GPIO_Mode_IPU;                        //上拉输入 或者 浮空输入 GPIO_Mode_IN_FLOATING 都可以
  14.                
  15.         GPIO_Init(DS1302_DAT_PORT,&DS1302_Struction);                //对成员进行初始化        
  16. }


  17. /******************************************************************
  18. 描述: DS1302 DAT设置成输出模式 函数
  19. *******************************************************************/
  20. void ds1302_set_output_mode(void)
  21. {
  22.         GPIO_InitTypeDef DS1302_Struction;                                //定义结构体成员
  23.         RCC_APB2PeriphClockCmd(DS1302_DAT_RCC, ENABLE);        //打开时钟
  24.         
  25.         DS1302_Struction.GPIO_Pin  = DS1302_DAT_PIN;                //引脚
  26.         DS1302_Struction.GPIO_Mode = GPIO_Mode_Out_PP;                //推挽输出
  27.         DS1302_Struction.GPIO_Speed = GPIO_Speed_50MHz;                //速率        

  28.         GPIO_Init(DS1302_DAT_PORT,&DS1302_Struction);                //对成员进行初始化        
  29. }


  30. /******************************************************************
  31. 描述: DS1302 配置 函数
  32. *******************************************************************/
  33. void ds1302_config(void)
  34. {
  35.         GPIO_InitTypeDef DS1302_Struction;                                //定义结构体成员

  36.         RCC_APB2PeriphClockCmd(DS1302_CLK_RCC, ENABLE);        //打开时钟
  37.         RCC_APB2PeriphClockCmd(DS1302_DAT_RCC, ENABLE);        //打开时钟
  38.         RCC_APB2PeriphClockCmd(DS1302_RST_RCC, ENABLE);        //打开时钟

  39.         //DS1302 CLK
  40.         DS1302_Struction.GPIO_Pin  = DS1302_CLK_PIN;                //引脚
  41.         DS1302_Struction.GPIO_Mode = GPIO_Mode_Out_PP;                //推挽输出        
  42.         DS1302_Struction.GPIO_Speed = GPIO_Speed_50MHz;         //50MHz
  43.         GPIO_Init(DS1302_CLK_PORT,&DS1302_Struction);                //对成员进行初始化               
  44.         //DS1302 DAT
  45.         DS1302_Struction.GPIO_Pin  = DS1302_DAT_PIN;                //引脚
  46.         DS1302_Struction.GPIO_Mode = GPIO_Mode_Out_PP;                //推挽输出        
  47.         DS1302_Struction.GPIO_Speed = GPIO_Speed_50MHz;         //50MHz
  48.         GPIO_Init(DS1302_DAT_PORT,&DS1302_Struction);                //对成员进行初始化        
  49.         //DS1302 RST
  50.         DS1302_Struction.GPIO_Pin  = DS1302_RST_PIN;                //引脚
  51.         DS1302_Struction.GPIO_Mode = GPIO_Mode_Out_PP;                //推挽输出        
  52.         DS1302_Struction.GPIO_Speed = GPIO_Speed_50MHz;         //50MHz
  53.         GPIO_Init(DS1302_RST_PORT,&DS1302_Struction);                //对成员进行初始化        

  54. }
  55. /******************************************************************
  56. 描述: DS1302 写一字节 函数
  57. *******************************************************************/
  58. void ds1302_write_byte(uint8_t addr_or_data)
  59. {
  60.         uint8_t i;
  61.         DS1302_SET_OUT;
  62.         for(i=0;i<8;i++)
  63.         {
  64.                 if(addr_or_data & 0x01)                //从低位开始传输
  65.                 {
  66.                         DS1302_DAT_HIGH;
  67.                 }
  68.                 else
  69.                 {
  70.                         DS1302_DAT_LOW;
  71.                 }
  72.                 addr_or_data >>= 1;                //右移一位
  73.                 DS1302_CLK_HIGH;                //拉高时钟表示已经发送
  74.                 DS1302_CLK_LOW;                        //拉低时钟准备继续放新的数据位
  75.         }
  76. }

  77. /******************************************************************
  78. 描述: DS1302 写命令 函数
  79. *******************************************************************/
  80. void ds1302_write_cmd(uint8_t addr,uint8_t dat)
  81. {
  82.         DS1302_RST_LOW;
  83.         DS1302_CLK_LOW;
  84.         DS1302_RST_HIGH;
  85.         ds1302_write_byte(addr);
  86.         ds1302_write_byte(dat);
  87.         DS1302_RST_LOW;
  88. }

  89. /******************************************************************
  90. 描述: DS1302 读一字节 函数
  91. *******************************************************************/
  92. uint8_t ds1302_read_byte(void)
  93. {
  94.         uint8_t i;
  95.         uint8_t dat = 0;
  96.         DS1302_SET_IN;
  97.         for(i=0;i<8;i++)
  98.         {
  99.                 dat >>= 1;                //左移一次 低位开始 共有效左移7次
  100.                 if( GPIO_ReadInputDataBit(DS1302_DAT_PORT, DS1302_DAT_PIN) == SET)
  101.                 {
  102.                         dat = dat | 0x80;
  103.                 }
  104. //                else
  105. //                {
  106. //                        dat = dat & 0x7f;
  107. //                }
  108.                 DS1302_CLK_HIGH;
  109.                 DS1302_CLK_LOW;
  110.         }
  111.         return dat;
  112. }


  113. /******************************************************************
  114. 描述: DS1302 读数据 函数
  115. *******************************************************************/
  116. uint8_t ds1302_read_data(uint8_t addr)
  117. {
  118.         uint8_t dat = 0;
  119.         DS1302_RST_LOW;
  120.         DS1302_CLK_LOW;
  121.         DS1302_RST_HIGH;
  122.         ds1302_write_byte(addr);
  123.         dat = ds1302_read_byte();
  124.         DS1302_RST_LOW;
  125.         return dat;
  126. }

  127. /******************************************************************
  128. 描述: BCD 转 十进制 函数 例如 0X24 转成 24
  129. *******************************************************************/
  130. void bcd_to_dec(uint8_t *bcd,uint8_t times)
  131. {
  132.         uint8_t i;
  133.         for(i=0;i<times;i++)
  134.         {
  135.                 bcd = ((bcd>>4)*10) + (bcd&0x0f);
  136.         }
  137. }

  138. /******************************************************************
  139. 描述: 十进制 转 BCD 函数 例如 12 转成 0X12
  140. *******************************************************************/
  141. void dec_to_bcd(uint8_t *dec,uint8_t times)
  142. {
  143.         uint8_t i;
  144.         for(i=0;i<times;i++)
  145.         {
  146.                 dec = ((dec/10)<<4) | (dec%10);
  147.         }
  148. }




  149. /******************************************************************
  150. 描述: DS1302 初始化 日期和时间 函数
  151. *******************************************************************/
  152. void ds1302_init(void)
  153. {
  154.         ds1302_config();        //引脚配置

  155.         dec_to_bcd(ds1302_time,7);        //十进制转BCD码
  156.         ds1302_write_cmd(DS1302_WRITE_PROTECT,0x00); //关闭写保护        
  157.         
  158.         ds1302_write_cmd(DS1302_WRITE_YEAR,        ds1302_time[0]);        //年
  159.         ds1302_write_cmd(DS1302_WRITE_MONTH,ds1302_time[1]);        //月
  160.         ds1302_write_cmd(DS1302_WRITE_DAY,        ds1302_time[2]);          //日
  161.         ds1302_write_cmd(DS1302_WRITE_HOUR,        ds1302_time[3]);           //时
  162.         ds1302_write_cmd(DS1302_WRITE_MINUTE,ds1302_time[4]);         //分
  163.         ds1302_write_cmd(DS1302_WRITE_SECOND,ds1302_time[5]);          //秒
  164.         ds1302_write_cmd(DS1302_WRITE_WEEK,        ds1302_time[6]);          //周        

  165.         ds1302_write_cmd(DS1302_WRITE_PROTECT,0x80); //开启写保护        
  166. }

  167. /******************************************************************
  168. 描述: DS1302 读取 日期和时间 函数
  169. *******************************************************************/
  170. void ds1302_read(void)
  171. {
  172.         ds1302_time[0] = ds1302_read_data(DS1302_READ_YEAR);  //读取年
  173.         ds1302_time[1] = ds1302_read_data(DS1302_READ_MONTH); //读取月
  174.         ds1302_time[2] = ds1302_read_data(DS1302_READ_DAY);   //读取日
  175.         ds1302_time[3] = ds1302_read_data(DS1302_READ_HOUR);  //读取时
  176.         ds1302_time[4] = ds1302_read_data(DS1302_READ_MINUTE);//读取分
  177.         ds1302_time[5] = ds1302_read_data(DS1302_READ_SECOND);//读取秒
  178.         ds1302_time[6] = ds1302_read_data(DS1302_READ_WEEK);  //读取周

  179.         bcd_to_dec(ds1302_time,7);        //BCD码转成十进制
  180. }

复制代码

ds1302.h

  1. #ifndef __DS1302_H
  2. #define __DS1302_H
  3. #include "stm32f10x.h"

  4. #define DS1302_CLK_RCC                RCC_APB2Periph_GPIOB                //时钟
  5. #define DS1302_CLK_PORT                GPIOB                                                //端口
  6. #define DS1302_CLK_PIN                GPIO_Pin_13                                        //引脚

  7. #define DS1302_DAT_RCC                RCC_APB2Periph_GPIOB                //时钟
  8. #define DS1302_DAT_PORT                GPIOB                                                //端口
  9. #define DS1302_DAT_PIN                GPIO_Pin_14                                        //引脚

  10. #define DS1302_RST_RCC                RCC_APB2Periph_GPIOB                //时钟
  11. #define DS1302_RST_PORT                GPIOB                                                //端口
  12. #define DS1302_RST_PIN                GPIO_Pin_15                                        //引脚


  13. #define DS1302_CLK_HIGH                GPIO_SetBits(DS1302_CLK_PORT, DS1302_CLK_PIN)                        //引脚输出高电平
  14. #define DS1302_CLK_LOW                GPIO_ResetBits(DS1302_CLK_PORT, DS1302_CLK_PIN)                        //引脚输出低电平

  15. #define DS1302_DAT_HIGH                GPIO_SetBits(DS1302_DAT_PORT, DS1302_DAT_PIN)                        //引脚输出高电平
  16. #define DS1302_DAT_LOW                GPIO_ResetBits(DS1302_DAT_PORT, DS1302_DAT_PIN)                        //引脚输出低电平

  17. #define DS1302_RST_HIGH                GPIO_SetBits(DS1302_RST_PORT, DS1302_RST_PIN)                        //引脚输出高电平
  18. #define DS1302_RST_LOW                GPIO_ResetBits(DS1302_RST_PORT, DS1302_RST_PIN)                        //引脚输出低电平

  19. #define DS1302_SET_IN                ds1302_set_input_mode()                                                        //设置输入模式
  20. #define DS1302_SET_OUT                 ds1302_set_output_mode()                                                //设置输出模式               


  21. /*读相关寄存器地址*/
  22. #define DS1302_READ_SECOND         0X81           //秒
  23. #define DS1302_READ_MINUTE         0X83        //分
  24. #define DS1302_READ_HOUR           0X85        //时
  25. #define DS1302_READ_DAY                0X87        //日
  26. #define DS1302_READ_MONTH         0X89        //月
  27. #define DS1302_READ_WEEK         0X8B        //周
  28. #define DS1302_READ_YEAR         0X8D        //年
  29. //#define DS1302_READ_TIME         0XBF        //读取全部时间

  30. /*写相关寄存器地址*/
  31. #define DS1302_WRITE_SECOND 0X80           //秒
  32. #define DS1302_WRITE_MINUTE 0X82        //分
  33. #define DS1302_WRITE_HOUR   0X84        //时
  34. #define DS1302_WRITE_DAY        0X86        //日
  35. #define DS1302_WRITE_MONTH         0X88        //月
  36. #define DS1302_WRITE_WEEK         0X8A        //周
  37. #define DS1302_WRITE_YEAR         0X8C        //年
  38. #define DS1302_WRITE_PROTECT 0X8E        //保护
  39. //#define DS1302_WRITE_TIME         0XBE         //写全部时间


  40. extern uint8_t ds1302_time[8];        //存放日期和时间

  41. void ds1302_write_byte(uint8_t addr_or_data);                        //DS1302 写一字节 函数
  42. void ds1302_write_cmd(uint8_t addr,uint8_t dat);                //DS1302 写命令          函数
  43. uint8_t ds1302_read_byte(void);                                                        //DS1302 读一字节 函数
  44. uint8_t ds1302_read_data(uint8_t addr);                                        //DS1302 写一字节 函数
  45. void bcd_to_dec(uint8_t *bcd,uint8_t times);                        //BCD 转 十进制 函数
  46. void dec_to_bcd(uint8_t *dec,uint8_t times);                        //十进制 转 BCD 函数
  47. void ds1302_init(void);                                                                        //DS1302 初始化日期和时间 函数
  48. void ds1302_read(void);                                                                        //DS1302 读取  日期和时间 函数

  49. #endif
复制代码

usart.c
  1. /* 配置串口1 优先级 函数 */
  2. static void NVIC_USART1_configuration(void)
  3. {
  4.         NVIC_InitTypeDef NVIC_initStruction;
  5.         
  6.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);                                //组
  7.         NVIC_initStruction.NVIC_IRQChannel = USART1_IRQn;                        //串口1中断
  8.         NVIC_initStruction.NVIC_IRQChannelPreemptionPriority = 0;   //主优先级
  9.         NVIC_initStruction.NVIC_IRQChannelSubPriority = 0;                        //次优先级
  10.         NVIC_initStruction.NVIC_IRQChannelCmd = ENABLE;                                //使能
  11.         NVIC_Init(&NVIC_initStruction);
  12. }

  13. /* 配置串口1 函数*/
  14. void usart1_init(uint32_t baudRate)
  15. {
  16.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        //打开GPIOA时钟
  17.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);        //打开串口1时钟
  18.         
  19.         GPIO_InitTypeDef GPIO_initStruction;
  20.         USART_InitTypeDef USART_initStruction;

  21.         /*配置GPIOA  TX */
  22.         GPIO_initStruction.GPIO_Pin = USART1_TX;                 // TX
  23.         GPIO_initStruction.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  24.         GPIO_initStruction.GPIO_Speed = GPIO_Speed_50MHz;
  25.         GPIO_Init(GPIOA, &GPIO_initStruction);
  26.         
  27.         /*配置GPIOA RX */
  28.         GPIO_initStruction.GPIO_Pin = USART1_RX;                 // RX
  29.         GPIO_initStruction.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  30.         GPIO_Init(GPIOA, &GPIO_initStruction);
  31.         
  32.         /*配置USART1 TX和RX */
  33.         USART_initStruction.USART_BaudRate = baudRate;        //波特率
  34.         USART_initStruction.USART_WordLength = USART_WordLength_8b; //8位有效数据位
  35.         USART_initStruction.USART_StopBits = USART_StopBits_1;        //1个停止位
  36.         USART_initStruction.USART_Parity = USART_Parity_No;                //无奇偶校验位
  37.         USART_initStruction.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不硬件控制流
  38.         USART_initStruction.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送 和 接收
  39.         USART_Init(USART1, &USART_initStruction);
  40.         
  41.         NVIC_USART1_configuration();        //串口1中断优先级配置
  42.         USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中断
  43.         USART_Cmd(USART1, ENABLE); //使能串口1
  44. }



  45. /*重定向C库函数printf到串口*/
  46. int fputc(int ch, FILE *f)
  47. {
  48.         USART_SendData(USART1, (uint8_t)ch);; //发送一字节到串口
  49.         while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送寄存器为空 证明发送完
  50.         
  51.         return ch;
  52. }

  53. /*重定向C库函数 scanf到串口*/
  54. int fgetc(FILE *f)
  55. {
  56.         while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); //如果读数据寄存器非空
  57.         return (int)USART_ReceiveData(USART1);
  58. }
复制代码

usart.h
  1. #ifndef __USART_H
  2. #define __USART_H
  3. #include "stm32f10x.h"
  4. #include "stdio.h"

  5. #define USART1_TX        GPIO_Pin_9
  6. #define USART1_RX        GPIO_Pin_10

  7. void usart1_init(uint32_t baudRate);


  8. #endif
复制代码

main.c
  1. #include "stm32f10x.h"
  2. #include "delay.h"
  3. #include "ds1302.h"
  4. #include "usart.h"
  5. int  main()
  6. {
  7.         ds1302_init();                        //DS1302初始化
  8.         usart1_init(115200);        //串口1初始化
  9.         while(1)
  10.         {
  11.                 ds1302_read();        //读取日期和时间
  12.                 printf("20%d年%d月%d日 %d时%d分%d秒 星期%d\r\n",ds1302_time[0],ds1302_time[1],ds1302_time[2],ds1302_time[3],ds1302_time[4],ds1302_time[5],ds1302_time[6]);
  13.                 delay_ms(500);
  14.         }  
  15. }
复制代码

项目展示
运行结果


2a78dba27df844cabd3d8001f4da8ba8.png

总结和注意事项
一:以前玩51比较多,STM32玩得少,主要的区别是STM32有多个模式,不同场景需要切换不同模式来进行。比如这里的DS1302 CLK 和 RST 这种直接一直推挽输出没问题,但是DAT引脚则不行了,咱们去拉低拉高是推挽输出,但是到我们读取这个DAT电平则需要设置成上拉输入。(浮空貌似也行)不像51不用考虑 直接操作。
二:如果你发现采取样不准,请检查是否把DS1302的 VCC接到STM32的5V引脚。
三:重定向printf(); 如果你发现并没有输出数据。那么请查看一下你是否勾选了(如下图)

10ebe94ea469452cafd95eccecbbf0d3.png

学了51 其实上手32不难,反正我觉得还可以,就是配置啥的麻烦了一丢丢主要是IO的模式

————————————————
转载:皮卡丘吉尔



收藏 1 评论0 发布时间:2022-8-22 17:03

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版