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

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

[复制链接]
hujjj 发布时间: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 收藏 评论2 发布时间:2019-9-16 22:32

举报

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

    今天又在3.3V电压下测试了DS1307模块,可以正常读出数据,证明DS1307可以在低于4.5V的电压下工作,至于会不会影响正常计时,还有利于继续测试。

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

官网相关资源

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