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

【STM32G4 NUCLEO G431RB】+ DS1307日历模块终于驱动成功

[复制链接]
老牛洋车 发布时间:2019-9-16 22:32
    经过一周多时间坚持不懈地努力,DS1307日历模块终于成功驱动起来了,下面是测试过程的图片。
    显示年份和时间:
DS1307_I2C_10.jpg


    显示月日和时间:
DS1307_I2C_11.jpg


    细心的坛友可能会发现日不正确,显示为0日,而我设置是今天16号的日子,不知什么原因怎么会显示成0日,我初步排查了一遍,并没有找到原因,还需要继续排查。总体来说,DS1307算是基本驱动成功了,之所以花费了一周多的时间,主要是我过分相信从网上搜索到的代码,而没有认真地查阅数据手册,因此走了不少弯路。
    开始我移植的是从网上搜索到的DS1307驱动代码,其GPIO模拟I2C的读写操作似乎是延用DS1302的模式,低字节在前、高字节在后。但实际上DS1307与DS1302不同,是遵循I2C标准,高字节在前、低字节在后,结果可想而知,注定是不成功的,换句话说我是被这段代码误导了,不知这段代码的原作者是如何调试通过的。
    软件I2C屡试无果,我又尝试使用硬件I2C,开始用STM32CubeMX生成项目文件,然后将相应的代码复制到我的项目中,编译虽然通过了,但仍读不出数据,最后用逻辑分析仪抓取时序图,竟然相应的引脚无信号,显然是复制代码时遗漏了。
    接着我用范例中的I2C项目来测试,也许是原设置不符合DS1307的要求,驱动也失败了,从时序图上可以看出其在输出DS1307地址0xD0之前还输出了0xF0,看来是我对其读写函数的参数理解错了。

    折腾了一周多的时间,只好从基础开始,查阅DS1307的数据手册和I2C标准通讯协议,对照这些资料修改I2C的相关函数,并结合时序图来修改延时参数,最后终于成功地驱动了DS1307,下面是相关的时序图片。
    从DS1307读出秒数据:
DS1307_I2C_00.jpg


    写入器件地址时的时序:
DS1307_I2C_01.jpg


    经过本次测试,我对I2C通讯有了全面的了解,基本上掌握了I2C通讯的基本知识。

1 收藏 评论3 发布时间:2019-9-16 22:32

举报

3个回答
老牛洋车 回答时间:2019-9-17 09:28:47
经过排查,日不正确的原因找到了,原来是在写入时将星期与日的次序相反了,现在日期时钟数据完全正确了。下面是DS1307的驱动代码:

  1. #include "main.h"
  2. #include "I2C.h"
  3. #include "ds1307.h"

  4. extern uint16_t year;              //年
  5. extern uint8_t week,month,day,hour,minute,second,DS_Buff[8];//月日时分秒


  6. /******************************************************************************************
  7. * 函数名称: DS1307_Read()
  8. * 功能说明: 从DS1307地址addr开始获取size个字节的数据,获取的数据存储在全局变量DS_Buff中
  9. * 输    入: uint8_t addr        获取数据从addr开始
  10. *                        uint8_t size        要获取的数据个数(1~8)
  11. * 输    出: ui08    0=RET_OK 成功从DS1307获取数据  1=RET_ERR 从DS1307获取数据过程中出现错误
  12. ******************************************************************************************/
  13. uint8_t DS1307_Read(uint8_t addr,uint8_t size)
  14. {
  15.     uint8_t i = 0;

  16.     SI2C_Start();                   //产生起始信号
  17.     SI2C_Send(DS1307_ADDR);         //发送DS1307芯片地址及读写位,0表示写
  18.     if(1 == SI2CIsAck())            //检测DS1307是否有响应
  19.     {
  20.         SI2C_Stop();                //产生停止信号
  21.                 return 2;
  22.     }
  23.     SI2C_Send(addr);                //发送读取数据的起始地址
  24.     if(1 == SI2CIsAck())            //检测DS1307是否有响应
  25.     {
  26.         SI2C_Stop();                    //产生停止信号
  27.         return 3;
  28.     }

  29.     SI2C_Start();                   //产生Repeated Start
  30.     SI2C_Send(DS1307_ADDR|1);       //发送DS1307芯片地址及读写位,1表示读
  31.     if(1 == SI2CIsAck())            //检测DS1307是否有响应
  32.     {
  33.         SI2C_Stop();                //产生停止信号
  34.         return 4;
  35.     }

  36.     for(i=0;size>0;i++,size--)                //从addr处读取size个字节的数据
  37.     {
  38.         DS_Buff[i] = SI2C_Receive();
  39.         SI2CDoAck();
  40.     }

  41.     SI2C_Receive();                 //DS1307要求必须使用NOAck来结束数据读取
  42.     SI2CNoAck();                    //DS1307要求必须使用NOAck来结束数据读取

  43.     SI2C_Stop();                    //产生停止信号
  44.         return 0;
  45. }


  46. /**********************************************************************************************
  47. * 函数名称:        DS1307_Write()
  48. * 功能说明: 向DS1307地址addr开始写入size个字节的数据,将要写入的数据存储在全局变量DS_Buff中
  49. * 输    入: uint8_t addr        数据被写入从addr开始的地址处
  50. *                        uint8_t size        要设置的数据个数(1~8)
  51. * 输    出: uint8_t                0=RET_OK 成功向DS1307设置数据  1=RET_ERR 向DS1307设置数据过程中出现错误
  52. **********************************************************************************************/
  53. uint8_t DS1307_Write(uint8_t addr,uint8_t size)
  54. {
  55.     uint8_t i = 0;

  56.     SI2C_Start();                   //产生起始信号
  57.     SI2C_Send(DS1307_ADDR|0);       //发送DS1307芯片地址及读写位,0表示写
  58.     if(1 == SI2CIsAck())            //检测DS1307是否有响应
  59.     {
  60.         SI2C_Stop();                //产生停止信号
  61.         return 1;
  62.         }

  63.     SI2C_Send(addr);                //发送数据要写入的地址
  64.     if(1 == SI2CIsAck())            //检测DS1307是否有响应
  65.     {
  66.         SI2C_Stop();                //产生停止信号
  67.         return 2;
  68.     }

  69.     for(i=0;size>0;i++,size--)
  70.     {
  71.         SI2C_Send(DS_Buff[i]);
  72.         if(1 == SI2CIsAck())        //检测DS1307是否有响应
  73.         {
  74.             SI2C_Stop();            //产生停止信号
  75.             return 3;
  76.         }
  77.     }

  78.     SI2C_Stop();                    //产生停止信号
  79.     return 0;
  80. }


  81. /******************************************************************************************
  82. * 函数名称:        DS1307_Init()
  83. * 功能说明: 用当前日期(yesr,month,day,hour,minute)初始化DS1307
  84. * 输    入: 无
  85. * 输    出: uint8_t        0=RET_OK 初始化成功        1=RET_ERR 初始化出错
  86. ******************************************************************************************/
  87. uint8_t DS1307_Init(void)
  88. {
  89.     uint8_t temp;

  90.         temp = DS1307_Read(0,1);
  91.        
  92.         if(temp>127){

  93.         year = 2019;
  94.                 month = 9;
  95.                 day = 17;
  96.                 week = 2;
  97.                 hour = 9;
  98.                 minute = 1;
  99.                
  100.         DS_Buff[0] = 0;                  //秒
  101.         temp = ((minute/10)<<4|(minute%10));
  102.         DS_Buff[1] = temp;               //分
  103.         temp = ((hour/10)<<4|(hour%10));
  104.         DS_Buff[2] = temp;               //时

  105.         DS_Buff[3] = week;               //星期

  106.         temp = ((day/10)<<4|(day%10));
  107.         DS_Buff[4] = temp;               //日
  108.         temp = ((month/10)<<4|(month%10));
  109.             DS_Buff[5] = temp;               //月
  110.         temp = ((year%100)/10<<4|(year%10));
  111.         DS_Buff[6] = temp;               //年
  112.        
  113.         DS_Buff[7] = 32;                 //0010 0000 = 允许按1Hz输出方波

  114.         return DS1307_Write(0,8);
  115. //        return DS1307_I2C_Write(0,8);
  116.     }
  117.         else
  118.                 return 4;
  119. }

  120. /******************************************************************************************
  121. * 函数名称:        DS1307_Config()
  122. * 功能说明: 配置DS1307_OUT中断引脚
  123. * 输    入: 无
  124. * 输    出: 无
  125. ******************************************************************************************/
  126. void DS1307_Config(void)
  127. {
  128.     GPIO_InitTypeDef GPIO_InitStruct;

  129.     GPIO_InitStruct.Pin = DS_OUT;
  130.     GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  131.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  132.     HAL_GPIO_Init(DS_PORT, &GPIO_InitStruct);
  133.        
  134.         SI2C_Config();                       //配置I2C
  135. }


  136. /******************************************************************************************
  137. * 函数名称:        DS1307_read_date()
  138. * 功能说明: 读取DS1307日期时间数据
  139. * 输    入: 无
  140. * 输    出: 无
  141. ******************************************************************************************/
  142. void DS1307_read_date(void)
  143. {
  144.     DS1307_Read(0,7);                                      //读取前7个字节数据
  145. //    DS1307_I2C_Read(0,7);                                    //读取前7个字节数据
  146.     second = ((DS_Buff[0]&0x70)>>4)*10 + (DS_Buff[0]&0x0F);//秒,屏蔽秒的第7位的标志
  147.         minute = ((DS_Buff[1]&0x70)>>4)*10 + (DS_Buff[1]&0x0F);//分(取低7位)
  148.         hour = ((DS_Buff[2]&0x10)>>4)*10 + (DS_Buff[2]&0x0F);  //时(取低5位)
  149.         week = (DS_Buff[3]&0x07);                              //周(取低3位)
  150.     day = ((DS_Buff[4]&0x30)>>4)*10 + (DS_Buff[4]&0x0F);   //日(取低6位)
  151.     month = ((DS_Buff[5]&0x10)>>4)*10 + (DS_Buff[5]&0x0F); //月(取低5位)
  152.         year = 2000 + (DS_Buff[6]>>4)*10 + (DS_Buff[6]&0x0F);  //年

  153. }


  154. /******************************************************************************************
  155. * 函数名称:        DS1307_write_date()
  156. * 功能说明: 读取DS1307日期时间数据
  157. * 输    入: 无
  158. * 输    出: 无
  159. ******************************************************************************************/
  160. void DS1307_write_date(void)
  161. {
  162.     uint8_t temp;
  163.        
  164.     DS_Buff[0] = 0;                      //秒
  165.     temp = ((minute/10)<<4|(minute%10));
  166.     DS_Buff[1] = temp;                   //分
  167.     temp = ((hour/10)<<4|(hour%10));
  168.     DS_Buff[2] = temp;                   //时

  169.     DS_Buff[3] = week;                   //星期
  170.     temp = ((day/10)<<4|(day%10));
  171.     DS_Buff[4] = temp;                   //日
  172.     temp = ((month/10)<<4|(month%10));
  173.     DS_Buff[5] = temp;                   //月
  174.     temp = ((year%100)/10<<4|(year%10));
  175.     DS_Buff[6] = temp;                   //年
  176.        
  177.     DS1307_Write(0,7);                   //写入前7个字节数据
  178. //    DS1307_I2C_Write(0,7);               //写入前7个字节数据
  179. }
复制代码


  1. #ifndef DS1307_H
  2. #define DS1307_H

  3. #include "stm32g4xx.h"

  4. /*************************** 宏定义 *****************************/
  5. #define DS1307_ADDR                0xD0                        //DS1307器件的IIC地址固定为11010000

  6. #define DS_OUT     GPIO_PIN_6                   //定义接收DS1307_OUT信号引脚及端口
  7. #define DS_PORT    GPIOB

  8. /***************************函数声明*****************************/
  9. uint8_t DS1307_Read(uint8_t addr,uint8_t size); //读数据
  10. uint8_t DS1307_Write(uint8_t addr,uint8_t size);//写数据
  11. uint8_t DS1307_Init(void);                      //用当前日期(yesr,month,day,hour,minute)初始化
  12. void DS1307_Config(void);                       //配置中断引脚及I2C
  13. void DS1307_read_date(void);                    //读取日期时间数据
  14. void DS1307_write_date(void);                   //写入日期时间数据

  15. #endif
复制代码
老牛洋车 回答时间:2019-9-17 08:57:20
    昨晚网络有点不畅,这张照片反复上传均不成功。这是使用硬件I2C的时序图,可以看出开始输出了0xF0的地址,之后才是DS1307器件地址0xD0,也应该是我没有找到正确的函数所致。
I2CWriteAddrss_4.jpg

    今天又在3.3V电压下测试了DS1307模块,可以正常读出数据,证明DS1307可以在低于4.5V的电压下工作,至于会不会影响正常计时,还有利于继续测试。
tmrs 回答时间:2020-11-3 16:29:47
不错不错

所属标签

相似分享

官网相关资源

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