[应用相关] DS1302读出的数值为FF是什么原因?

[复制链接]
3478|14
 楼主| hu9jj 发表于 2019-4-30 16:10 | 显示全部楼层 |阅读模式
pi, IO, gp, GPIO, se
DS1302日历模块读不出正确数据,读出的值全部是FF,通常会是什么原因,该如何检查呢?
MCU的引脚已经正常配置,DS1302的写操作时序也正常(见下图),读操作的时序尚未抓取到。
DS1302_10.jpg


    相关的代码如下:
  1. extern uint16_t year;              //年
  2. extern uint8_t mon,day,hour,minu,seco;//月日时分秒

  3. void DS1302_Config(void)           //引脚配置
  4. {
  5.     gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,GPIO_PIN_5);//CLK输出模式、弱上拉
  6.     gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_5);
  7.         gpio_bit_set(GPIOB, GPIO_PIN_5);
  8.        
  9.         gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,GPIO_PIN_3);//RST输出模式、弱上拉
  10.     gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_3);
  11.         gpio_bit_set(GPIOB, GPIO_PIN_3);
  12. }

  13. void DS1302_PortConfig(uint8_t dir)//DAT端口配置(根据需要配置成输出或输入模式)
  14. {
  15. //        GPIO_InitTypeDef GPIO_InitStruct;
  16.     if(dir == IO_OUT)
  17.         {
  18.         gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,GPIO_PIN_4);//输出模式、弱上拉
  19.         gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_4);
  20.         }
  21.         else
  22.         {
  23.         gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_4);   //输入模式
  24.         gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_4);
  25.         }
  26.         gpio_bit_set(GPIOB, GPIO_PIN_4);
  27. }



  28. /*****************************************************
  29. 函数功能:向1302写一个字节数据
  30. 入口参数:x
  31. ***************************************************/
  32. void Write1302(uint8_t dat)
  33. {
  34.         uint8_t i;
  35.         DATA_OUT;
  36.         SCLK_0;

  37.         delay_us(3);
  38.         for(i=0;i<8;i++)
  39.         {
  40.                 if(dat&0x01) DATA_1;
  41.                 else DATA_0;
  42.                 delay_us(4);
  43.                 SCLK_1;
  44.                 delay_us(4);
  45.                 SCLK_0;
  46.                 dat>>=1;
  47.         }


  48. }

  49. /*****************************************************
  50. 函数功能:根据命令字,向1302写一个字节数据
  51. 入口参数:Cmd,储存命令字;dat,储存待写的数据
  52. ***************************************************/
  53. void WriteSet1302(uint8_t Cmd,uint8_t dat)
  54. {
  55.         RST_0;
  56.         SCLK_0;
  57.         RST_1;
  58.         delay_us(4);
  59.         Write1302(Cmd);
  60.         Write1302(dat);
  61.         SCLK_1;
  62.         RST_0;

  63. }

  64. /*****************************************************
  65. 函数功能:从1302读一个字节数据
  66. 入口参数:x
  67. ***************************************************/
  68. uint8_t Read1302(void)
  69. {
  70.         uint8_t i,dat;
  71.         DATA_IN;      //
  72.         DATA_0;       //
  73.     delay_us(4);
  74.        
  75.         for(i=0;i<8;i++)
  76.         {
  77.                 dat>>=1;
  78.                 if(gpio_input_bit_get(GPIOB,GPIO_PIN_3) == SET)  //(DATA != 0)
  79.                         dat|=0x80;
  80.                 else
  81.                         dat&=0x7f;
  82.                 SCLK_1;
  83.                 delay_us(4);
  84.                 SCLK_0;
  85.                 delay_us(4);
  86.         }
  87.         DATA_OUT;      //
  88.         return dat;
  89. }

  90. /*****************************************************
  91. 函数功能:根据命令字,从1302读取一个字节数据
  92. 入口参数:Cmd
  93. ***************************************************/
  94. uint8_t ReadSet1302(uint8_t Cmd)
  95. {
  96.         uint8_t dat;
  97.         RST_0;
  98.         SCLK_0;
  99.         RST_1;
  100.         Write1302(Cmd);
  101.         dat=Read1302();
  102.         SCLK_1;
  103.         RST_0;
  104.         return dat;
  105. }

  106. /*****************************************************
  107. 函数功能: 1302进行初始化设置
  108. ***************************************************/
  109. void DS1302_Init(void)
  110. {

  111.         DATA_OUT;
  112.        
  113.         /*--------------------这是每次都初始化的语句-----------------*/
  114. /*
  115.         WriteSet1302(0x8E,0x00);                     //根据写状态寄存器命令字,写入不保护指令
  116.         WriteSet1302(0x80,((55/10)<<4|(55%10)));     //根据写秒寄存器命令字,写入秒的初始值
  117.         WriteSet1302(0x82,((11/10)<<4|(11%10)));     //根据写分寄存器命令字,写入分的初始值
  118.         WriteSet1302(0x84,((9/10)<<4|(9%10)));       //根据写小时寄存器命令字,写入小时的初始值
  119.         WriteSet1302(0x86,((6/10)<<4|(6%10)));       //根据写日寄存器命令字,写入日的初始值
  120.         WriteSet1302(0x88,((2/10)<<4|(2%10)));       //根据写月寄存器命令字,写入月的初始值
  121.         WriteSet1302(0x8c,((15/10)<<4|(15%10)));     //根据写年寄存器命令字,写入年的初始值
  122.         WriteSet1302(0x90,0xa5);                     //打开充电功能 选择2K电阻充电方式
  123.         WriteSet1302(0x8E,0x80);                     //根据写状态寄存器命令字,写入保护指令

  124. */
  125.         //如果不想每次都初始化时间,也就是掉电后还想让时钟继续走时的话 就用下面的语句        ,此时vcc1外接3v电池
  126.     uint8_t flag;
  127.         LCD_write_ASCII(0,4,"No");
  128.        
  129.     flag= ReadSet1302(0x81);
  130.     if(flag&0x80)                                //判断时钟芯片是否关闭
  131.     {
  132.         WriteSet1302(0x8E,0x00);                 //关闭写保护
  133.                WriteSet1302(0x80,((45/10)<<4|(45%10))); //写入秒初始值
  134.         WriteSet1302(0x82,((15/10)<<4|(15%10))); //写入分的初始值
  135.         WriteSet1302(0x84,((9/10)<<4|(9%10)));   //写入小时的初始值
  136.         WriteSet1302(0x86,((6/10)<<4|(6%10)));   //写入日的初始值
  137.         WriteSet1302(0x88,((5/10)<<4|(5%10)));   //写入月的初始值
  138.         WriteSet1302(0x8c,((19/10)<<4|(19%10))); //写入年的初始值
  139.         WriteSet1302(0x90,0xa5);                 //打开充电功能 5=一个二极管2K电阻,9=两个二极管2K电阻
  140.                                                  //             6=一个二极管4K电阻,a=两个二极管4K电阻
  141.                                                  //             7=一个二极管8K电阻,b=两个二极管8K电阻
  142.         WriteSet1302(0x8E,0x80);                             //打开写保护
  143.                 LCD_write_ASCII(0,4,"OK");
  144.     }

  145. }

  146. //向DS302写入时钟数据
  147. void DS1302_write_date(void)
  148. {
  149.         uint8_t temp;
  150.        
  151.         WriteSet1302(0x8E,0x00);                     //关闭写保护
  152.         WriteSet1302(0x80,0x80);                     //暂停时钟
  153.         WriteSet1302(0x90,0xa5);                         //涓流充电
  154.         temp = ((year%100)/10<<4|(year%10));
  155.         WriteSet1302(0x8C,temp);                     //年
  156.         temp = ((mon/10)<<4|(mon%10));
  157.         WriteSet1302(0x88,temp);                         //月
  158.         temp = ((day/10)<<4|(day%10));
  159.         WriteSet1302(0x86,temp);                     //日
  160.         temp = ((hour/10)<<4|(hour%10));
  161.         WriteSet1302(0x84,temp|0x80);                //时(24小时制式)
  162.         temp = ((minu/10)<<4|(minu%10));
  163.         WriteSet1302(0x82,temp);                     //分
  164.         WriteSet1302(0x80,0x00);                     //秒
  165. //        WriteSet1302(0x8A,0x01);                     //周
  166.         WriteSet1302(0x8E,0x80);                     //打开写保护     
  167. }

  168. //从DS302读出时钟数据
  169. void DS1302_read_date(void)  
  170. {
  171.     uint8_t temp;
  172.         temp = ReadSet1302(0x8D);                    //年 0x8D
  173.         year = 2000 + ((temp&0x70)>>4)*10 + (temp&0x0F);
  174.         temp = ReadSet1302(0x89);;                             //月 0x89
  175.         mon = ((temp&0x70)>>4)*10 + (temp&0x0F);
  176.         temp = ReadSet1302(0x87);                    //日 0x87
  177.         day = ((temp&0x70)>>4)*10 + (temp&0x0F);
  178.         temp = ReadSet1302(0x85);                             //时 0x85
  179.         hour = ((temp&0x70)>>4)*10 + (temp&0x0F);
  180.         temp = ReadSet1302(0x83);                         //分 0x83
  181.         minu = ((temp&0x70)>>4)*10 + (temp&0x0F);
  182.         temp = ReadSet1302(0x81)&0x7f;               //秒,屏蔽秒的第7位,避免超出59
  183.         seco = ((temp&0x70)>>4)*10 + (temp&0x0F);
  184. }





 楼主| hu9jj 发表于 2019-4-30 20:35 | 显示全部楼层
找到原因了,原来是读数据 的函数中引脚代码错了,现在可以正常取数了。结贴!
zhuomuniao110 发表于 2019-4-30 21:39 | 显示全部楼层
给力,分享一下正确的代码。
xinpian101 发表于 2019-4-30 21:51 | 显示全部楼层
工具可以
 楼主| hu9jj 发表于 2019-5-1 09:11 | 显示全部楼层
zhuomuniao110 发表于 2019-4-30 21:39
给力,分享一下正确的代码。

其实就是引脚的编号写错了,我的DAT 引脚接在PB4上,但我的代码却错写成PB3。以下是修改后的代码:

  1. /*****************************************************
  2. 函数功能:从1302读一个字节数据
  3. 入口参数:x
  4. ***************************************************/
  5. uint8_t Read1302(void)
  6. {
  7.         uint8_t i,dat;
  8.         DATA_IN;      //设置为输入
  9.         DATA_0;       //
  10.     delay_us(4);
  11.        
  12.         for(i=0;i<8;i++)
  13.         {
  14.                 dat>>=1;
  15.                 if(gpio_input_bit_get(GPIOB,GPIO_PIN_4) == SET)  //(DAT = 1)
  16.                         dat|=0x80;
  17.                 else
  18.                         dat&=0x7f;
  19.                 SCLK_1;
  20.                 delay_us(4);
  21.                 SCLK_0;
  22.                 delay_us(4);
  23.         }
  24.         DATA_OUT;      //
  25.         return dat;
  26. }
幸福小强 发表于 2019-5-2 21:25 | 显示全部楼层
很标准的例子。
 楼主| hu9jj 发表于 2019-5-3 10:41 | 显示全部楼层

是的,原例程是STM32HAL库的,我移植到GD32E23x,第一次使用,也不知道是没写进去还是没读出来,通过逻辑分析仪抓取时序图,发现写时序正常,读时序出问题,最后排查到是读DAT时引脚标错了,更正过来就顺利读出数据了。
henangongda123 发表于 2019-5-3 11:03 | 显示全部楼层
1302误差比较大,建议你用我玩的那款IC,实测误差真的很小
 楼主| hu9jj 发表于 2019-5-4 09:12 | 显示全部楼层
henangongda123 发表于 2019-5-3 11:03
1302误差比较大,建议你用我玩的那款IC,实测误差真的很小

让我使劲猜猜您玩的是哪款IC
henangongda123 发表于 2019-5-6 10:56 | 显示全部楼层
hu9jj 发表于 2019-5-4 09:12
让我使劲猜猜您玩的是哪款IC

被系统删了

评论

哦,也许涉嫌广告推销吧。  发表于 2019-5-6 14:31
hanzhen654 发表于 2019-5-6 18:24 | 显示全部楼层
检查引脚 是否连接正确
hanzhen654 发表于 2019-5-6 18:24 | 显示全部楼层
然后就是底层的时序是否按照芯片手册来编写的
 楼主| hu9jj 发表于 2019-5-6 21:31 | 显示全部楼层
hanzhen654 发表于 2019-5-6 18:24
检查引脚 是否连接正确

正是引脚编号写错了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:Microchip
简介:让我们来为您提供帮助。我们可提供各种资源来帮助您解决一切问题。是否需要与我们的客户支持团队联系?您可以通过电话、在线聊天功能或电子邮件与他们联系。

151

主题

1063

帖子

11

粉丝
快速回复 在线客服 返回列表 返回顶部