OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3308|回复: 4

想做一个STM32F207用SD3088做RTC时钟芯片的

[复制链接]

22

主题

131

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2016-6-6
在线时间
49 小时
发表于 2016-8-19 18:32:20 | 显示全部楼层 |阅读模式
1金钱

晚上找到的一段51单片机的代码 ,我想要移植到STM32F207上,可是发现有点问题
//************************************************************
// 实时时钟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 个实时时钟数据 .

最佳答案

查看完整内容[请看2#楼]

ACK的那里应该最后把SDA拉高
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

22

主题

131

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2016-6-6
在线时间
49 小时
 楼主| 发表于 2016-8-19 18:32:21 | 显示全部楼层
ACK的那里应该最后把SDA拉高
回复

使用道具 举报

22

主题

131

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2016-6-6
在线时间
49 小时
 楼主| 发表于 2016-8-19 18:33:50 | 显示全部楼层

/*
*SD3088时钟芯片 读写
*文件 sd3088.h
*作者 于
*麦知 www.mazclub.com
*版本 v1.0
*/  
#include "sd3088.h"  
  #include "stm32f2xx.h"
//extern I2C_HandleTypeDef hi2c1;  
  #define                true                          1
#define         false                         0
Time Time_sd3088 = {0x55, 0x59, 0x14, 0x01, 0x12, 0x11, 0x14};  //初始化时间结构体变量(设置时间:2014年11月12日 14:59:55  星期一)  
//Time1 Time_sd3088   
uint8_t  rtc_data[8];       //通用数据缓存器  
uint8_t sram[8];        //通用数据缓存器  
uint8_t pdata;  
  
void read_rtc(void)  
{   
  // 读取时间  
                IIC_Start();  
     IIC_Send_Byte(0x65);
          //        if (!IIC_Wait_Ack()) {IIC_Stop();return 0;}
                        IIC_Wait_Ack();
                        Time_sd3088.second =IIC_Read_Byte(0);
                          IIC_Ack();
      Time_sd3088.minute = IIC_Read_Byte(0);
IIC_Ack();       
      Time_sd3088.hour = IIC_Read_Byte(0);
IIC_Ack();  
      Time_sd3088.week =IIC_Read_Byte(0);
IIC_Ack();  
      Time_sd3088.day = IIC_Read_Byte(0);
        IIC_Ack();
      Time_sd3088.month =IIC_Read_Byte(0);
        IIC_Ack();
      Time_sd3088.year =IIC_Read_Byte(0);
   IIC_Ack();       
            Time_sd3088.quantity = IIC_Read_Byte(0);
     IIC_NAck();       
                           // IIC_NAck();                //读时间完成,发送NoAck
               IIC_Stop();
        //return        true;
                        /*
      Time_sd3088.second = BCD2DEC(rtc_data[0] & 0x7f);  
      Time_sd3088.minute = BCD2DEC(rtc_data[1] & 0x7f);  
      Time_sd3088.hour = BCD2DEC(rtc_data[2] & 0x1f);  
      Time_sd3088.week = BCD2DEC(rtc_data[3] & 0x07);  
      Time_sd3088.day = BCD2DEC(rtc_data[4] & 0x3f);  
      Time_sd3088.month = BCD2DEC(rtc_data[5] & 0x1f);  
      Time_sd3088.year = BCD2DEC(rtc_data[6]);      
        Time_sd3088.quantity = BCD2DEC(rtc_data[7]);  
   
    */

}  
void send_rtc(void)
{   
        //写时间操作求一次对实时时间寄存器(00H~06H)依次写入,
                              //不可以单独对7个时间数据中的某一位进行写操作,否则可能会引起时间数据的错误进位.
            IIC_Start();  
     IIC_Send_Byte(0x64);        //要修改其中某一个数据 , 应一次性写入全部 7 个实时时钟数据.
  
  IIC_Send_Byte(0x00);
             IIC_Wait_Ack();
        IIC_Send_Byte(Time_sd3088.second);
IIC_Wait_Ack();
        IIC_Send_Byte(Time_sd3088.minute);
        IIC_Wait_Ack();
        IIC_Send_Byte(Time_sd3088.hour);
        IIC_Wait_Ack();
        IIC_Send_Byte(Time_sd3088.week);
        IIC_Wait_Ack();
        IIC_Send_Byte(Time_sd3088.day);
                IIC_Wait_Ack();
        IIC_Send_Byte(Time_sd3088.month);
        IIC_Wait_Ack();
        IIC_Send_Byte(Time_sd3088.year);
        IIC_Wait_Ack();
          IIC_Stop();
}


这个是我的写发送和接收时间的,i2c用的正点原子的
回复

使用道具 举报

22

主题

131

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2016-6-6
在线时间
49 小时
 楼主| 发表于 2016-8-19 18:35:02 | 显示全部楼层
谁能帮忙解答一下  !单步执行的时候发现读出来的年月日时分秒全是0 !
回复

使用道具 举报

22

主题

131

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2016-6-6
在线时间
49 小时
 楼主| 发表于 2016-8-19 20:43:37 | 显示全部楼层
用 的是STM32F207加SD3088
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-29 06:06

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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