打印
[STM32F1]

SD3078问题

[复制链接]
538|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zwll|  楼主 | 2022-2-19 14:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
有人用过SD3078 IC做实时时钟吗?我这写了个程序,IIC读不到应答ACK,不知道是什么原因?求大神指教,有STM32F10x的例程就更好了,万分感谢!

使用特权

评论回复
沙发
dingy| | 2022-2-19 14:10 | 只看该作者
没有呢;
模拟IIC好了;
为啥不选DS1302呢

使用特权

评论回复
板凳
renyaq| | 2022-2-19 14:12 | 只看该作者
51的程序有,要不要

使用特权

评论回复
地板
heweibig| | 2022-2-19 14:14 | 只看该作者


//************************************************************

// 实时时钟SD30XX读写C51演示程序

// AT89S52   11.0592MHz

// E-mail:   FAE@whwave.com.cn

// TEL:                 0755-83114387

// Last update:                   2014/11/14

//************************************************************



#pragma code

#include <reg51.h>

#include <intrins.h>



#define                RTC_Address                        0x64                //RTC器件地址

#define                IDcode                                0x72                //8字节ID号起始地址

#define                Bat_bit8                        0x1A                //电量最高位寄存器地址

#define                Bat_Low8                        0x1B                //电量低八位寄存器地址



#define                true                          1

#define         false                         0



//*********变量及IO口定义*********

typedef unsigned char uchar;

typedef unsigned int uint;



sbit        SDA=P3^4;                 

sbit        SCL=P3^5;               



uchar        Batbit8,Batlow7;        //电池电量寄存器值

uint          Bat;                        //电池电量值

uchar        Sram[8];                //通用数据缓存器

uchar        data1[8];                //通用数据缓存器

typedef        struct

{

        uchar         second;

        uchar        minute;

        uchar        hour;

        uchar        week;

        uchar        day;

        uchar        month;

        uchar        year;

}S_Time;        



S_Time  RTC={0x55,0x59,0x14,0x01,0x12,0x11,0x14};        //初始化时间结构体变量(设置时间:2014年11月12日 14:59:55  星期一)

//           55秒 59分 14时 周一 10日 11月 14年

/********SD30XX函数名********/

uchar I2CReadOneByte(uchar DeviceAddress,uchar add);//读一字节

bit I2CWriteOneByte(uchar DeviceAddress,uchar add, uchar date);//写一字节

uchar I2CReadSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps);//连续读

uchar I2CWriteSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps);//连续写

bit I2CWriteDate(S_Time        SetRTC);//写时间        

bit I2CReadDate(S_Time        *psRTC);//读时间

bit        WriteTimeOn(void);//写允许

bit        WriteTimeOff(void);//写禁止

void Delay(uint nn);



/*********I2C延时4us***********/

void I2CWait(void)//4us

{        

        _nop_();_nop_();_nop_();_nop_();//AT89S52一个nop是1us

}



/********开启SD30XX的I2C总线********/

bit I2CStart(void)

{

        SDA=1;

        SCL=1;

        I2CWait();

        if(!SDA)return false;        //SDA线为低电平则总线忙,退出

        SDA=0;

        I2CWait();

        while(SDA)return false;        //SDA线为高电平则总线出错,退出

        SCL=0;

        I2CWait();

        return true;

}



/********关闭SD30XX的I2C总线*******/

void I2CStop(void)

{

        SDA=0;

        SCL=0;

        I2CWait();

        SCL=1;

        I2CWait();

        SDA=1;

}



/*********发送 ACK*********/

void I2CAck(void)

{        

        SDA=0;

        SCL=0;

        I2CWait();

        SCL=1;

        I2CWait();

        SCL=0;

}



/*********发送NO ACK*********/

void I2CNoAck(void)

{        

        SDA=1;

        SCL=0;

        I2CWait();

        SCL=1;

        I2CWait();

        SCL=0;

}



/*********读取ACK信号*********/

bit I2CWaitAck(void)          //返回为:1=有ACK,0=无ACK

{

        SCL=0;

        SDA=1;                //设置SDA为输入(其它类型的单片机需要配置IO输入输出寄存器)

        I2CWait();

        SCL=1;

        I2CWait();

        while(SDA)

        {

                SCL=0;

                return false;

        }

        SCL=0;

        return true;

}



/************MCU向SD30XX发送一个字节*************/

void I2CSendByte(uchar demand) //数据从高位到低位//

{

        uchar i=8;                       

                                         

        

        while(i--)

        {

                SCL=0;

                _nop_();

                SDA=(bit)(demand&0x80);

                demand<<=1;

                I2CWait();

                SCL=1;

                I2CWait();

        }

        SCL=0;

}



/*********MCU从SD30XX读入一字节*********/

uchar I2CReceiveByte(void)      //数据从高位到低位//

{

        uchar i=8;

        uchar ddata=0;

        SDA=1;                        //设置SDA为输入(其它类型的单片机需要配置IO输入输出寄存器)

        while(i--)

        {

                ddata<<=1;      //数据从高位开始读取

                SCL=0;

                I2CWait();

                SCL=1;

                I2CWait();        //从高位开始 ddata|=SDA;ddata<<=1

                if(SDA)

                {

                        ddata|=0x01;

                }

        }

        SCL=0;

        return ddata;

}



/******I2C写一个字节******/

bit I2CWriteOneByte(uchar DeviceAddress,uchar add, uchar date)

{               

        if(!I2CStart())return false;

        I2CSendByte(DeviceAddress);      

        I2CWaitAck();   

        I2CSendByte(add);                //设置写地址      

        I2CWaitAck();        

        I2CSendByte(date);                //写数据

        I2CWaitAck();        

        I2CStop();

        return        true;

}



/******I2C读一个字节程序******/

uchar I2CReadOneByte(uchar DeviceAddress,uchar add)

{               

        uchar dat;

        if(!I2CStart())return false;

        I2CSendByte(DeviceAddress);      

        if(!I2CWaitAck()){I2CStop(); return false;}

          I2CSendByte(add);                //设置要读的地址

        I2CWaitAck();

        I2CStart();        

         I2CSendByte(DeviceAddress+1);        

        I2CWaitAck();        

        dat=I2CReceiveByte();                //读数据

        I2CNoAck();

        I2CStop();

        return  dat;

}



/******写SD30XX允许程序******/

bit WriteTimeOn(void)

{               

        if(!I2CWriteOneByte(RTC_Address,0x10,0x80))return false;

        I2CWriteOneByte(RTC_Address,0x0f,0xff);

        return        true;

}



/******写SD30XX禁止程序******/

bit WriteTimeOff(void)

{               

        if(!I2CWriteOneByte(RTC_Address,0x0f,0x7b))return false;

        I2CWriteOneByte(RTC_Address,0x10,0);

        return        true;

}



/******读SD30XX实时数据寄存器******/

bit I2CReadDate(S_Time        *psRTC)

{

        

        if(!I2CStart())return false;

        I2CSendByte(RTC_Address+1);

            if(!I2CWaitAck()){I2CStop(); return false;}

        psRTC->second=I2CReceiveByte();

        I2CAck();

        psRTC->minute=I2CReceiveByte();

        I2CAck();

        psRTC->hour=I2CReceiveByte();

        I2CAck();

        psRTC->week=I2CReceiveByte();

        I2CAck();

        psRTC->day=I2CReceiveByte();

        I2CAck();

        psRTC->month=I2CReceiveByte();

        I2CAck();

        psRTC->year=I2CReceiveByte();

        I2CNoAck();                //读时间完成,发送NoAck

        I2CStop();

        return        true;

}



/******写SD30XX实时数据寄存器******/

bit I2CWriteDate(S_Time        SetRTC)        //写时间操作要求一次对实时时间寄存器(00H~06H)依次写入,

{                               //不可以单独对7个时间数据中的某一位进行写操作,否则可能会引起时间数据的错误进位.

                                //要修改其中某一个数据 , 应一次性写入全部 7 个实时时钟数据.

        S_Time         *psRTC;

            psRTC=&SetRTC;

        WriteTimeOn();                                //使能,开锁

        if(!I2CStart())return false;

        I2CSendByte(RTC_Address);

        if(!I2CWaitAck()){I2CStop(); return false;}

        I2CSendByte(0x00);                        //设置写起始地址      

        I2CWaitAck();        

        I2CSendByte(psRTC->second);                //second     

        I2CWaitAck();        

        I2CSendByte(psRTC->minute);                //minute      

        I2CWaitAck();        

        I2CSendByte(psRTC->hour|0x80);                //hour ,同时设置小时寄存器最高位(0:为12小时制,1:为24小时制)

        I2CWaitAck();        

        I2CSendByte(psRTC->week);                //week      

        I2CWaitAck();        

        I2CSendByte(psRTC->day);                //day      

        I2CWaitAck();        

        I2CSendByte(psRTC->month);                //month      

        I2CWaitAck();        

        I2CSendByte(psRTC->year);                //year      

        I2CWaitAck();        

        I2CStop();

        

        WriteTimeOff();                                //使能,关锁

        return        true;

}





/******设置SD30XX报警中断演示程序演示******/

void WriteALARM(void)                                //设置报警时间:2015年2月14日 8:00

{                                                //只有设置未来的时间才有效

        WriteTimeOn();

        I2CWriteOneByte(RTC_Address,0x09,0x08);        //8时

        I2CWriteOneByte(RTC_Address,0x0b,0x14);        //14日

        I2CWriteOneByte(RTC_Address,0x0c,0x02);        //02月

        I2CWriteOneByte(RTC_Address,0x0d,0x15);        //15年

        I2CWriteOneByte(RTC_Address,0x0e,0x74);        //设置报警允许(使能年、月、日、小时报警)

        I2CWriteOneByte(RTC_Address,0x10,0x92);        //设置INT中断选通(INTS1,INTS0),及报警中断总允许位(INTAE)

        WriteTimeOff();

}



/******关闭SD30XX报警中断程序******/

void ClrALARM(void)                                //关闭报警中断

{

        WriteTimeOn();

        I2CWriteOneByte(RTC_Address,0x10,0x90);

        WriteTimeOff();

}

/******设置SD30XX倒计时中断演示******/

void SetDjs(void)                                //设置倒计时中断

{

        WriteTimeOn();

        I2CWriteOneByte(RTC_Address,0x10,0x0f);//先清倒计时中断总允许位(INTDE)

        I2CWriteOneByte(RTC_Address,0x10,0xf4);//设置周期性中断(IM=1)INT中断选通(INTS1,INTS0),配置倒计时中断总允许位(INTDE)

        I2CWriteOneByte(RTC_Address,0x11,0x30);//选择定时器频率源(TDS1、TDS0)为1/60HZ

        I2CWriteOneByte(RTC_Address,0x13,0x05);//倒计时初值寄存器,设置8位倒计时计数初值(5min)

        WriteTimeOff();

}



/******关闭SD30XX倒计时中断程序******/

void ClrDjs(void)         

{

        WriteTimeOn();

        I2CWriteOneByte(RTC_Address,0x10,0xf0);

        WriteTimeOff();

}

/******设置SD30XX频率中断演示******/

void SetFrq(void)                                       

{

        WriteTimeOn();

        I2CWriteOneByte(RTC_Address,0x10,0xa1);        //选通频率中断(INTS1,INTS0),设置频率中断总允许位(INTFE)

        I2CWriteOneByte(RTC_Address,0x11,0x09);        //设置2Hz频率中断

        WriteTimeOff();

}

/******关闭SD30XX频率中断******/

void ClrFrq(void)         

{

        WriteTimeOn();

        I2CWriteOneByte(RTC_Address,0x10,0xa0);

        WriteTimeOff();

}

//|************I2C连续读多个字节************|

uchar I2CReadSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps)

{

        uchar        i;

        if(!I2CStart())return false;

        I2CSendByte(DeviceAddress);      

        if(!I2CWaitAck()){I2CStop(); return false;}

          I2CSendByte(Address);                        //设置要读的地址

        I2CWaitAck();

        I2CStart();        

         I2CSendByte(DeviceAddress+1);

        I2CWaitAck();

        for(i=0;i<length-1;i++,ps++)

        {

                *ps=I2CReceiveByte();                //读数据

                I2CAck();

        }

        *ps=I2CReceiveByte();        

        I2CNoAck();

        I2CStop();

        return        true;

}



//|******************I2C连续写多个字节******************|

uchar I2CWriteSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps)

{

        uchar        i;

        if(!WriteTimeOn())return false;

        if(!I2CStart())return false;

        I2CSendByte(DeviceAddress);      //器件地址

        if(!I2CWaitAck()){I2CStop(); return false;}

          I2CSendByte(Address);                //设置起始地址

        I2CWaitAck();

        for(i=0;i<length;i++)

        {

                I2CSendByte(*(ps++));               

                I2CAck();                                       

        }

        I2CStop();

        WriteTimeOff();

        return        true;

}



/*********延时子程序*********/

void Delay2_5ms()      //延时2.5ms

{

        uchar        i=255;

        while(i--);

}



void Delayms(uchar n)

{

        while(n--)

                Delay2_5ms();

}

//////*****主程序演示*****//////

void main()

{



        I2CWriteDate(RTC);        //设置时间演示

//        WriteALARM();            //设置报警中断时间演示

//        SetDjs();                         //设置倒计时中断演示

        SetFrq();                        //设置频率中断演示

        

        I2CReadSerial(RTC_Address,IDcode,8,Sram);                //读内部8字节ID号

        I2CWriteSerial(RTC_Address,0x30,8,Sram);                //把内部8字节的ID号写入用户通用存储器的0x30-0x37地址

        

        I2CReadSerial(RTC_Address,0x30,8,data1);                //读从用户RAM寄存器把先前存入的ID号读出来(0x30-0x37地址)

        Batbit8=I2CReadOneByte(RTC_Address,Bat_bit8);                //读SD30XX的电池电量最高位

        Batlow7=I2CReadOneByte(RTC_Address,Bat_Low8);                //读SD30XX的电池电量低八位

        Bat=(Batbit8>>7)*255+Batlow7;                                //计算电池电量值演示。如Bat=285则表示2.85V



    while(1)

        {

                 I2CReadDate(&RTC);                //读时间演示

                Delayms(100);                        //延时250ms,1s读4次

            }



}

//特别提醒:当写实时时间数据时 (00H~06H), 不可以单独 对 7 个时间数据中的某一位进行写操作 ,

//否则可能会引起时间数据的错误进位 , 所以要修改其中某一个数据 , 应一次性写入全部 7 个实时时钟数据 .

使用特权

评论回复
5
zhanghqi| | 2022-2-19 14:17 | 只看该作者
一会儿给你找找32的

使用特权

评论回复
6
juventus9554| | 2022-2-19 14:21 | 只看该作者
//************************************************************

// 实时时钟SD30XX读写STM8参考程序

// MCU: STM8S103F3

// Last update:              2017/7/19

//************************************************************



#include "stm8s103f3p.h"



#define uchar unsigned char

#define SCL_H  PC_ODR |= 0X08

#define SDA_H  PA_ODR |= 0X08

#define SCL_L  PC_ODR &= 0XF7

#define SDA_L  PA_ODR &= 0XF7

#define SDAM  ((PA_IDR & 0X08) >> 3)

#define SET_SCL_OUT()    {PC_DDR |= 0X08; PC_CR1 |= 0X08; PC_CR2 &= 0XF7;}//scl选择管脚为PC3

#define SET_SDA_OUT()    {PA_DDR |= 0X08; PA_CR1 |= 0X08; PA_CR2 &= 0XF7;}//sda选择管脚为PA3

#define SET_SDA_IN()     {PA_DDR &= 0XF7; PA_CR1 &= 0XF7; PA_CR2 &= 0XF7;}//浮空输入



uchar s_data[7] = {0};



void GPIO_I2c_Master_Init(void)

{

  I2C_CR1 &= 0xFE;      

  SET_SCL_OUT();    //PC3 输出;推挽;2MHz时钟;

  SET_SDA_OUT();    //PA3 输出;推挽;2MHz时钟;

}



void Delay_5us(void)

{

  uchar i = 10;    //fcpu 16MHz



  for (; i > 0; i--);

}



void I2C_Start(void)//起始信号

{

  SDA_H;                    

  SCL_H;                    

  Delay_5us();               

  SDA_L;                  

  Delay_5us();               

  SCL_L;                    

}



void I2C_Stop(void)//结束信号

{

  SDA_L;                  

  SCL_H;                  

  Delay_5us();               

  SDA_H;                  

  Delay_5us();               

}



void I2C_SendACK(uchar ack)//应答或者非应答信号

{

  if (ack == 0)

  {

    SDA_L;

  }

  else

  {

    SDA_H;

  }

  SCL_H;                  

  Delay_5us();  

  

  SCL_L;                    

  Delay_5us();     

}



uchar I2C_SendByte(uchar sendDAT)//发送字节

{

  uchar i = 0;

  uchar revack = 0;



  for (i= 0 ; i< 8; i++)         

  {

    SCL_L;               

    Delay_5us();  

  

    if (sendDAT & 0x80)  

    {

      SDA_H;

    }

    else  

    {      

      SDA_L;

    }

    sendDAT <<=  1;

    SCL_H;               

    Delay_5us();     

  }

  SCL_L;               

  Delay_5us();  

  SET_SDA_IN();

  SCL_H;   

  _asm("nop");

  _asm("nop");

  revack = (uchar)SDAM;

  Delay_5us();   

  SCL_L;   

  SET_SDA_OUT();

  Delay_5us();  



  return revack;

}



uchar I2C_RecvByte(void)//接收字节

{

  uchar i = 0;

  uchar revDAT = 0;

  

  SDA_H;  

  SET_SDA_IN();

  for (i = 0; i < 8; i++)         

  {

     revDAT <<= 1;      

     SCL_H;

     _asm("nop");

     _asm("nop");

     if (SDAM)

     {

        revDAT |= 0x01;

     }

     else

     {

        revDAT &= 0xfe;

     }



     Delay_5us();

     SCL_L;               

     Delay_5us();  

  }   

  SET_SDA_OUT();

  

  return revDAT;

}



void WriteOn(void)//打开写保护

{

  I2C_Start();

  I2C_SendByte(0x64);

  I2C_SendByte(0x10);

  I2C_SendByte(0x80);

  I2C_Stop();

  

  I2C_Start();

  I2C_SendByte(0x64);

  I2C_SendByte(0x0f);

  I2C_SendByte(0x84);

  I2C_Stop();

}



void WriteOff(void)//关闭写保护

{

  I2C_Start();

  I2C_SendByte(0x64);

  I2C_SendByte(0x10);

  I2C_SendByte(0x00);

  I2C_Stop();

  

  I2C_Start();

  I2C_SendByte(0x64);

  I2C_SendByte(0x0f);

  I2C_SendByte(0x00);

  I2C_Stop();

}



void read_time_from_sd30xx(void)//从sd30xx读时间

{

  uchar n = 0;



  I2C_Start();

  if (I2C_SendByte(0x65))

  {

    I2C_Stop();



    return;

  }

  for (n = 0; n < 7; n++)

  {

    s_data[n] = I2C_RecvByte();

    if (n == 6)

    {

      I2C_SendACK(1);

    }

    I2C_SendACK(0);

  }

  I2C_Stop();

}







void write_time_to_sd30xx(void)//写时间到sd30xx

{

  uchar n = 0;



  WriteOn();

  

  I2C_Start();

  I2C_SendByte(0x64);

  I2C_SendByte(0x00);

  for (n = 0; n < 7; n++)

  {

    I2C_SendByte(s_data[n]);

  }

  I2C_Stop();

  

  WriteOff();

}

使用特权

评论回复
7
zwll|  楼主 | 2022-2-19 14:23 | 只看该作者
谢谢!谢谢!真是太感谢了!

使用特权

评论回复
8
juventus9554| | 2022-2-19 14:27 | 只看该作者
请教楼上各位,这个芯片稳定不稳定啊

使用特权

评论回复
9
renyaq| | 2022-2-19 14:29 | 只看该作者
有谁弄过STM32F030R8T6的的PCF8563实时时钟芯片的求分享代码

使用特权

评论回复
10
dengdc| | 2022-2-19 14:31 | 只看该作者
用过PCF8563,还不错,比较好用

使用特权

评论回复
11
renyaq| | 2022-2-19 14:34 | 只看该作者
我现在是不明白 如何去调整时间?谁有这方面的历程可以参考下

使用特权

评论回复
12
zwll|  楼主 | 2022-2-19 14:38 | 只看该作者

其实还是不大明白,我再琢磨琢磨吧,多谢了哈先

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

885

主题

11314

帖子

5

粉丝