找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1639|回复: 16
打印 上一主题 下一主题
收起左侧

关于时钟芯片SD3078单片机驱动的问题 [已解决] 及解决方法

[复制链接]
回帖奖励 100 黑币 回复本帖可获得 5 黑币奖励! 每人限 2 次
跳转到指定楼层
楼主
最近在做手表,感觉大部分常见RTC要么太大,要么没内置晶振(误差大)
前几周找到了一款芯片,看上去还不错:

我就在某宝上买了2片,尝试驱动
这玩意老贵了,一片就要五块多
数据手册 SD3078.pdf (858.22 KB, 下载次数: 18)
我按照数据手册写的驱动:
  1. //SD3078.c
  2. //I2C功能O口:准双向
  3. #include "STC8H.h"
  4. #include "SD3078.h"
  5. #include "IIC.h"
  6. //#include "UART.c"

  7. #define RTC_READ 0x65
  8. #define RTC_WRITE 0x64

  9. void Rtc_Enable(){        
  10.         IIC_Start(); //发送起始命令
  11.         IIC_Send(RTC_WRITE); //发送设备地址+写命令
  12.         IIC_Ack();
  13.         IIC_Send(0x10); //发送地址
  14.         IIC_Ack();
  15.         IIC_Send(0x80); //发送数据
  16.         IIC_Ack();
  17.         IIC_Stop(); //发送停止命令

  18.         IIC_Start(); //发送起始命令
  19.         IIC_Send(RTC_WRITE); //发送设备地址+写命令
  20.         IIC_Ack();
  21.         IIC_Send(0x0F); //发送地址
  22.         IIC_Ack();
  23.         IIC_Send(0x84); //发送数据
  24.         IIC_Ack();
  25.         IIC_Stop();
  26. }        
  27. void Rtc_Disable(){        
  28.         IIC_Start(); //发送起始命令
  29.         IIC_Send(RTC_WRITE); //发送设备地址+写命令
  30.         IIC_Ack();
  31.         IIC_Send(0x0F); //发送地址
  32.         IIC_Ack();
  33.         IIC_Send(0x00);
  34.         IIC_Ack();
  35.         IIC_Send(0x00);
  36.         IIC_Ack();
  37.         IIC_Stop();
  38. }        

  39. void Rtc_Write_Time(unsigned char TIME_Set[],bit mode,bit A_P_M){//TIME_Set:秒分时周日月年  mode1:24h mode0:12h  IN:十进制数
  40.         
  41.         unsigned char i;
  42.         
  43.         for(i=0;i<7;i++){
  44.                 TIME_Set[i]=TIME_Set[i]/10*16+TIME_Set[i]%10;
  45.         }
  46.         if(mode)
  47.                 TIME_Set[2]|=0x80;
  48.         else{
  49.                 if(A_P_M)//AM
  50.                         TIME_Set[2]&=0x5f;
  51.                 else{//PM
  52.                         TIME_Set[2]&=0x7f;
  53.                         TIME_Set[2]|=0x20;
  54.                 }
  55.         }
  56.         IIC_Start(); //发送起始命令
  57.         IIC_Send(RTC_WRITE); //发送设备地址+写命令
  58.         IIC_Ack();
  59.         IIC_Send(0x00);
  60.         IIC_Ack();
  61.         for(i=0;i<7;i++){
  62.                 IIC_Send(TIME_Set[i]);
  63.                 IIC_Ack();
  64.         }
  65.         IIC_Stop();
  66.         
  67. }

  68. void Rtc_Read_Time(TIME_IN *TIME_Read){
  69.         IIC_Regulate(1);
  70.         IIC_Start();
  71.         IIC_Send(RTC_READ);
  72.         IIC_Ack();
  73.         TIME_Read -> second=IIC_Recv();
  74.         IIC_Send_Ack();
  75.         TIME_Read -> minute=IIC_Recv();
  76.         IIC_Send_Ack();
  77.         TIME_Read -> hour=IIC_Recv();
  78.         IIC_Send_Ack();
  79.         TIME_Read -> week=IIC_Recv();
  80.         IIC_Send_Ack();
  81.         TIME_Read -> date=IIC_Recv();
  82.         IIC_Send_Ack();
  83.         TIME_Read -> month=IIC_Recv();
  84.         IIC_Send_Ack();
  85.         TIME_Read -> year=IIC_Recv();
  86.         IIC_Send_Ack();
  87.         IIC_Stop();
  88. }

  89. void SD3078_Init(){
  90.         unsigned char r;
  91.         IIC_Regulate(1);
  92.         Rtc_Enable();//关写保护
  93.         IIC_Start();
  94.         IIC_Send(RTC_WRITE);
  95.         IIC_Ack();
  96.         IIC_Send(0x0F);
  97.         IIC_Ack();
  98.         IIC_Start();
  99.         IIC_Send(RTC_READ);
  100.         IIC_Ack();
  101.         r=IIC_Recv();
  102.         IIC_Send_Ack();
  103.         IIC_Stop();
  104.         if(r&0x01){//第一次上电
  105.                 Rtc_Write_Time(TIME_SET,1,0);
  106.         }
  107.         Rtc_Disable();//开写保护
  108. }

  109. void main(){
  110.         
  111.         unsigned char i, j, k;
  112.         
  113.          P0M0 = 0x00;
  114.    P0M1 = 0x00;
  115.    P1M0 = 0x00;
  116.    P1M1 = 0x00;
  117.    P2M0 = 0x00;
  118.    P2M1 = 0x00;
  119.    P3M0 = 0x00;
  120.    P3M1 = 0x00;
  121.    P4M0 = 0x00;
  122.    P4M1 = 0x00;
  123.    P5M0 = 0x00;
  124.    P5M1 = 0x00;
  125.         
  126.         IIC_Init();
  127.         SD3078_Init();
  128.         

  129.         while(1){
  130.                
  131.                 Rtc_Read_Time(&Sys_Time);
  132.                 if(Sys_Time.second==1)P0=0;else P0=1;
  133.                
  134.                 i = 13;
  135.         j = 45;
  136.         k = 214;
  137.         do
  138.         {
  139.                 do
  140.                 {
  141.                         while (--k);
  142.                 } while (--j);
  143.         } while (--i);
  144.         }

  145. }
复制代码
.h文件
  1. #ifndef _SD3078_H_
  2. #define _SD3078_H_

  3. typedef struct{
  4.         unsigned char year;
  5.         unsigned char month;
  6.         unsigned char date;
  7.         unsigned char hour;
  8.         unsigned char minute;
  9.         unsigned char second;
  10.         unsigned char week;
  11. }TIME_IN;

  12. TIME_IN Sys_Time;

  13. unsigned char TIME_SET[7]={0,0,0,2,18,7,23};//秒分时周日月年



  14. #endif
复制代码
烧录后,单片机似乎死循环了(似乎是IIC通讯失败,但IIC的代码驱动其他器件是正常的),
排查了几天都不知原因
有哪位大神帮我改改吗
-----------------------------------------------------------------------------
7月25日:

跟着数据手册重写了一遍代码,经过一些微调,SD3078被驱动起来了!(激动)
我对比了一下上面的(有问题)代码,并结合微调时的经过,总结出了上方代码的问题:
1、读出的数据是BCD码,很重要!(不是十进制)
2、 24小时制时读出数据时要把最高位置零(&0x7f),否则读出数据是错误的···
3、IIC的应答要设定一个时间上限,超过上限就跳出循环,判非应答。(方便调试)
4、好像没有了···
另外,我用的单片机是STC8H8K64U,使用了硬件IIC,请问大佬们不加上拉电阻保险吗?
(我试着去除上拉电阻,结果单片机与SD3078通讯仍正常)

----------------------------------------------------完----------------------------------------------------


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:401564 发表于 2023-7-21 12:32 | 只看该作者
1,先验证IIC代码对不对,可能用24C01的IIC代码和功能来进行验证
2,先验证IIC从机地址对不对,先不管数据读写,先写一个验证代码,向从机发送地址,看一下有没有响应,可以用一个LED或者某个端口的电平来进行验证
3,如果单片机没有内置上拉电阻,你就得在时钟和数据端口上增加上拉电阻
回复

使用道具 举报

板凳
ID:639106 发表于 2023-7-21 12:56 | 只看该作者
Y_G_G 发表于 2023-7-21 12:32
1,先验证IIC代码对不对,可能用24C01的IIC代码和功能来进行验证
2,先验证IIC从机地址对不对,先不管数据读写 ...

单片机引脚设置为准双向输出,可以吗
回复

使用道具 举报

地板
ID:161164 发表于 2023-7-21 14:54 | 只看该作者
注意电平转换时间


回复

使用道具 举报

5#
ID:639106 发表于 2023-7-21 18:58 | 只看该作者
lkc8210 发表于 2023-7-21 14:54
注意电平转换时间

时序按照数据手册写的,为400k,我把它调到200k后也没反应
回复

使用道具 举报

6#
ID:401564 发表于 2023-7-21 22:05 | 只看该作者
gqzjl 发表于 2023-7-21 12:56
单片机引脚设置为准双向输出,可以吗

时钟和数据线必须要加10K的上拉电阻!!!!!
端口设置为标准双向模式,也就是传统的8051模式
回复

使用道具 举报

7#
ID:1085441 发表于 2023-7-21 22:08 | 只看该作者
gqzjl 发表于 2023-7-21 12:56
单片机引脚设置为准双向输出,可以吗

看手册是有上拉电阻的,你可以接个上拉电阻试试。
像DS1302的IO口必须接上拉电阻,准双向IO口不行。
回复

使用道具 举报

8#
ID:883308 发表于 2023-7-22 01:49 | 只看该作者
可以看看数据手册多试试
回复

使用道具 举报

9#
ID:639106 发表于 2023-7-22 12:03 | 只看该作者
设置成开漏输出,SDA接了上拉电阻后还是没反应
是我写的驱动有问题吗
回复

使用道具 举报

10#
ID:384109 发表于 2023-7-22 13:04 | 只看该作者
看代码,P0需要至少1分钟才会有变化,测试时间够长吗
回复

使用道具 举报

11#
ID:639106 发表于 2023-7-22 14:07 | 只看该作者
够长,把if判断的值改成<20也一样要疯了
回复

使用道具 举报

12#
ID:401564 发表于 2023-7-22 17:13 | 只看该作者
gqzjl 发表于 2023-7-22 12:03
设置成开漏输出,SDA接了上拉电阻后还是没反应
是我写的驱动有问题吗

已经告诉你了,你上传的代码中,你的端口设置是对的,就不要再去找端口的毛病了
SDA和SCL都要加上拉10K电阻!!!!!!!
IIC可以驱动其它的IIC器件也不一定是对的!!!!!
为什么要叫你用24c01,这个器件是标准的IIC,不支持高速IIC的,在它上面运行正常了,在SD3078就能正常了
不要duang!duang!duang!先写一堆几千行的代码,然后就进行验证,那么多代码,问题出在哪里你都不一定知道

"先验证IIC从机地址对不对,先不管数据读写,先写一个验证代码,向从机发送地址,看一下有没有响应,可以用一个LED或者某个端口的电平来进行验证"
1,什么其它的代码都不要,只要端口设置和IIC写入一个字节函数,外加一个延时函数,延时可以设定为1秒2,P0^1=0;//LED这个端口先灭灯
3,写入从机地址   0x64
4,等待IIC从机应答,如果不应答就是死循环
5,P0^1 = 1;//

while(1);
6,烧录验证,不要仿真!!!!!!!!!

以上6步,从P.01端口的电平信号就可以知道从机是否能响应主机的IIC信号了
低电平:说明从机没有应答
高电平:说明从机已经应答,写字节的IIC代码是对的

再不行,把你的所有代码,原理图上传
还是不行,那就放弃吧

评分

参与人数 1黑币 +5 收起 理由
gqzjl + 5 赞一个!

查看全部评分

回复

使用道具 举报

13#
ID:639106 发表于 2023-7-22 17:35 | 只看该作者
Y_G_G 发表于 2023-7-22 17:13
已经告诉你了,你上传的代码中,你的端口设置是对的,就不要再去找端口的毛病了
SDA和SCL都要加上拉10K电阻 ...

好的,我试试
回复

使用道具 举报

14#
ID:821429 发表于 2023-7-23 16:42 | 只看该作者
if(Sys_Time.second==1)P0=0;else P0=1;    恰好能读到1吗?如果0秒后延时,2秒时才把时间读回来,是不是就没有反应了?这个看你的延时多长时间,按照12MHz1T估算你的延时,应该还是很多时候能进入的,但是也容易出现非预期的情况。
这条语句的第二个问题,如果延时不影响,当且仅当second==1时点亮/熄灭,也就是60秒钟点亮/灭1秒,这个是你预期的效果?我觉得不确定能不能看清楚这个闪烁
关于调试的方法,你是怎么感觉进入死循环的,是测试出来的吗?如果不是必须定位,找到出错点,因为不能在线调试,可以注释现在点亮指示灯的位置,在你觉得可疑的程序后面点亮指示灯,如果能点亮继续找前面的程序。

评分

参与人数 1黑币 +5 收起 理由
gqzjl + 5

查看全部评分

回复

使用道具 举报

15#
ID:584814 发表于 2023-7-24 11:13 | 只看该作者
先找个任意的IIC器件,调试成功后再上这个东东。
目前,标准的IIC驱动是通用的,RTC也就是读写而已,没多复杂,好像3231和1307的通用。
实验证明很多器件用STC准双向I/O无需加上拉什么的也可以用。
也可以找厂家要DEMO,国产可参考“国芯”,说明书写的是理想也可能是现实。
包括记得有些厂家宣传可以免费给样片,然而联系过结果呵呵呵。
如果自己玩且对体积没要求的话用8025的,几毛钱的货就非常好用。
还有就是,目前常见的8025、3231又大又蠢,甚至还有更过的内置了电池,这个小体积的有“核心技术”了 ?
建议仔细查一遍,厂家不给例程自己还调不过就过了罢。

评分

参与人数 1黑币 +5 收起 理由
gqzjl + 5 赞一个!

查看全部评分

回复

使用道具 举报

16#
ID:639106 发表于 2023-7-25 19:07 | 只看该作者
liixaofei5 发表于 2023-7-23 16:42
if(Sys_Time.second==1)P0=0;else P0=1;    恰好能读到1吗?如果0秒后延时,2秒时才把时间读回来,是不是就 ...

谢谢指导,问题解决了
回复

使用道具 举报

17#
ID:639106 发表于 2023-7-25 19:09 | 只看该作者
man1234567 发表于 2023-7-24 11:13
先找个任意的IIC器件,调试成功后再上这个东东。
目前,标准的IIC驱动是通用的,RTC也就是读写而已,没多 ...

谢谢指导,之前写的程序确实有忽疏
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表