DS1307 RTC模块使用

主要特性

DS1307是Maxim的串行、I2C实时时钟芯片。主要特性有:

  • 工作电压:主电源电压4.5~5.5V,电池电压2.0~3.5V

  • 功耗:电池供电、备份模式时<500nA

  • 接口:I2C,最大速率100kbps

  • 可编程方波输出

  • 电源自动切换、失效检测

  • 内置56字节大小、支持电池备份的RAM

  • 封装:8-Pin SO/PDIP

管脚定义

  • X1、X2: 接32.768kHz晶体,要求晶体负载电容12.5pF

  • Vcc:主电源,范围4.5~5.5V。当需要对DS1307读写时,需要接Vcc。

  • VBAT:接电池,范围2.0~3.5V。

  • GND:地

  • SDA、SCL:I2C接口数据线、时钟线。

  • SQW/OUT:方波输出脚、通过写寄存器来使能。

注意事项

  • DS1307的工作电压为4.5V-5.5V供电。

  • I2C总线控制DS1307,用GPIO模拟I2C时序即可。

  • 时间配置:直接把时间值写入0x00~0x06的时间寄存器。

  • 时间读取:直接读取0x00~0x06的时间寄存器即可。

  • 读取时间时发现未走时可能是00h 地址的寄存器第7 位为1,此位为1则芯片未开始工作,即时钟未走时,记得首次上电时把该位清零。

  • 首次上电设置时间后不必每次上电都再次初始化一下时间,停电后有备用电池,此时不必重写时间单元。

#include "global.h"
#include "drv_ds1307.h"
 
#define I2C_CLK_PORT        GPIOB
#define I2C_CLK_PIN         GPIO_PIN_4
 
#define I2C_SDA_PORT        GPIOB
#define I2C_SDA_PIN         GPIO_PIN_5
 
#define SCL_High()        GPIO_Init(I2C_CLK_PORT, I2C_CLK_PIN, GPIO_MODE_OUT_PP_HIGH_SLOW) 
#define SCL_Low()         GPIO_Init(I2C_CLK_PORT, I2C_CLK_PIN, GPIO_MODE_OUT_PP_LOW_SLOW)  
#define SDA_High()        GPIO_Init(I2C_SDA_PORT, I2C_SDA_PIN, GPIO_MODE_OUT_PP_HIGH_SLOW) 
#define SDA_Low()         GPIO_Init(I2C_SDA_PORT, I2C_SDA_PIN, GPIO_MODE_OUT_PP_LOW_SLOW) 
#define SDAM()           (GPIO_ReadInputData(I2C_SDA_PORT) & 0x20) ?1:0
#define SET_SCL_OUT()    GPIO_Init(I2C_CLK_PORT, I2C_CLK_PIN, GPIO_MODE_OUT_PP_HIGH_SLOW)
#define SET_SDA_OUT()    GPIO_Init(I2C_SDA_PORT, I2C_SDA_PIN, GPIO_MODE_OUT_PP_HIGH_SLOW)
#define SET_SDA_IN()     GPIO_Init(GPIOA, GPIO_PIN_0, GPIO_MODE_IN_PU_NO_IT)
 
extern uint8_t Ds1307_WriteByte(uint8_t WriteAddr,uint8_t WriteData);
extern uint8_t Ds1307_ReadByte(uint8_t ReadAddr);
extern void Ds1307_WriteData();
extern void Ds1307_ReadData();
extern void Init_Timer();
extern void Write_Time();
 
uint8_t g_u8ReadData[8];
 
/*******************************************************************************
//  Function:     I2C_Int
//  Description: 模拟I2C 与ds1307端口初始化
//  Param:        
//  Return:       
*******************************************************************************/
static void I2C_Int(void)
{
   SET_SDA_OUT();  
   SET_SCL_OUT();
}
 
/*******************************************************************************
//  Function:     Delay_5us
//  Description:  微妙级延时函数   延时时间约为16us
//  Param:        
//  Return:       fcpu 16MHz 时
*******************************************************************************/
static void Delay_5us(void)
{
   uint8_t i;                 
   for (i=5; i>0; i--);
}
 
/*******************************************************************************
//  Function:     I2C_Start
//  Description:  I2C 开始传输信号  当SCL 为高时  SDA由高变低
//  Param:        
//  Return:      
*******************************************************************************/
static void I2C_Start(void)
{
    // SDA 1->0 while SCL High
    SDA_High();                   
    SCL_High();                    
    Delay_5us(); 
    
    SDA_Low();                   
    Delay_5us(); 
    
    SCL_Low();                    
}
 
/*******************************************************************************
//  Function:     I2C_Stop
//  Description:  I2C 停止传输信号  当SCL 为高时  SDA由低变高
//  Param:        
//  Return:      
*******************************************************************************/
static void I2C_Stop(void)
{
    // SDA 0->1 while SCL High
    SDA_Low();                   
    SCL_High();                   
    Delay_5us();     
    
    SDA_High();                   
    Delay_5us();               
}
 
/*******************************************************************************
//  Function:     I2C_SendACK
//  Description:  主机向从机发送应答信号
//  Param:   应答信号 1:表示SDA高电平(无应答) 0:SDA低电平(有应答)
//  Return:      
*******************************************************************************/
static void I2C_SendACK(uint8_t ack)
{
    if(ack == 0)
    {
      SDA_Low(); 
    }  
    else
    {
      SDA_High(); 
    }
            
    SCL_High();                   
    Delay_5us();  
    
    SCL_Low();                    
    Delay_5us();     
}
 
/*******************************************************************************
//  Function:     I2C_SendByte
//  Description:  模拟I2C通信 发送8位数据
//  Param:        发送的8为数据值
//  Return:       返回应答信号  0表示有应答  1表示无应答
*******************************************************************************/
static uint8_t I2C_SendByte(uint8_t SendByte)
{
  static uint8_t i,RevAck;
  
  SDA_Low();
  for (i= 0 ; i< 8; i++)         
  {
    SCL_Low();    
    
    if (SendByte & 0x80)             // write data
    {
      SDA_High();
    }
    else   
    {
      SDA_Low();
    }
    
    Delay_5us();
    SendByte <<=  1;
    SCL_High();                
    Delay_5us();     
  } 
  
  SCL_Low();   
  SDA_High();
  Delay_5us();  
  
  SET_SDA_IN();
  
  SCL_High();    
  asm("nop");
  asm("nop");  
  
  RevAck = (uint8_t)SDAM();
  
  Delay_5us();   
  SCL_Low();   
  
  SET_SDA_OUT();
  Delay_5us();  
  
  return RevAck;
}
 
/*******************************************************************************
//  Function:     I2C_RecvByte
//  Description:  模拟I2C通信 从从机读取8位数据
//  Param:        
//  Return:       返回读取的8为数据值
*******************************************************************************/
static uint8_t I2C_RecvByte()
{
    uint8_t i;
    uint8_t RecvData = 0;
    
    SDA_High();     // latch the Data port befor reading
    
    SET_SDA_IN();
    
    for (i=0; i<8; i++)         
    { 
       RecvData <<= 1;
        
       SCL_High(); 
       
       asm("nop");
       asm("nop");
       
       if (SDAM())
       {
          RecvData |= 0x01;
       }
       else
       {
          RecvData &= 0xfe;
       }
 
       Delay_5us(); 
       SCL_Low();                
       Delay_5us();  
    }
    
   SET_SDA_OUT();
   
   return RecvData;
}
 
/*******************************************************************************
//  Function:     Ds1307_WriteByte
//  Description:  模拟I2C通信 写入1字节数据到指定地址
//  Param:        WriteAddr:待写入数据  WriteData;写入的地址
//  Return:       1: 成功写入  0: 写入出错
*******************************************************************************/
uint8_t Ds1307_WriteByte(uint8_t WriteAddr,uint8_t WriteData)
{
    I2C_Start();            
    if(I2C_SendByte(0xD0))    // Device Addr + Write (operation) 
    {
       return 0; 
    }
    
    if(I2C_SendByte(WriteAddr))
    {
      return 0;
    }
    
    if(I2C_SendByte(WriteData))
    {
     return 0; 
    }
    I2C_Stop();   
    
    return 1;
}
 
/*******************************************************************************
//  Function:     Ds1307_ReadByte
//  Description:  模拟I2C通信 从指定地址读取1字节数据
//  Param:        ReadAddr:读取的地址
//  Return:       RevData:读取的8位数据
*******************************************************************************/
uint8_t Ds1307_ReadByte(uint8_t ReadAddr)
{
  uint8_t RevData;
  
  I2C_Start();            
  I2C_SendByte(0xD0);     // Device Addr + Write (operation)   
  I2C_SendByte(ReadAddr); 
  
  I2C_Start();    
  I2C_SendByte(0xD1);     // Device Addr + Write (operation)   
  
  RevData = I2C_RecvByte();    
  
  I2C_SendACK(1);
 
  I2C_Stop();   
  
  return RevData;
}
 
/*******************************************************************************
//  Function:     Ds1307_WriteData
//  Description:  模拟I2C通信 写入8字节数据 从0x00~0x07
//  Param:        pWriteData: 指针指向待写入的数组的地址
//  Return:      
*******************************************************************************/
void Ds1307_WriteData()
{
    uint8_t i;
    uint8_t *pWriteData;
    
    pWriteData = (uint8_t *)&ICTimerBuf;
      
    I2C_Start();            
    I2C_SendByte(0xD0);     // Device Addr + Write (operation) 
    I2C_SendByte(0x00); 
    
    for(i=0; i<8; i++)
    {
      I2C_SendByte(*pWriteData++); 
    }
    
    I2C_Stop();             
}
 
/*******************************************************************************
//  Function:     Ds1307_ReadData
//  Description:  模拟I2C通信 读取8字节数据 从0x00~0x07
//  Param:        pReadData: 指针指向保存数据的数组
//  Return:      
*******************************************************************************/
void Ds1307_ReadData()
{
  uint8_t i;
  uint8_t *pReadData;
  
  pReadData = (uint8_t *)&ICTimerBuf;
  I2C_Start();            
  I2C_SendByte(0xD0);     // Device Addr + Write (operation)   
  I2C_SendByte(0x00); 
  
  I2C_Start();    
  I2C_SendByte(0xD1);     // Device Addr + Write (operation)   
  
  for(i=0; i<7; i++)
  {
   // *pReadData++ = I2C_RecvByte();  
    *pReadData = I2C_RecvByte();
    pReadData++;
    
    if(i < 6)
      I2C_SendACK(0);    //DIO低电平 表示ACK 应答
    else 
      I2C_SendACK(1);
  }
  
  I2C_Stop();   
}
 
/*******************************************************************************
//  Function:     Init_Timer
//  Description:  上电初始化时钟以及读时钟
//  Param:       
//  Return:      判断0x00 地址bit7 是否为1  为1表示时钟芯片掉电
*******************************************************************************/
void Init_Timer()
{
  I2C_Int();
  Ds1307_ReadData();
  
  if(ICTimerBuf.TimerSec & 0x80)
  {
    Ds1307_ReadData();
    if(ICTimerBuf.TimerSec & 0x80)
    {
      ICTimerBuf.TimerSec =0x00;
      ICTimerBuf.TimerMin =0x00;
      ICTimerBuf.TimerHour =0x12;
      ICTimerBuf.TimerWeek =0x02;
      ICTimerBuf.TimerDay =0x15;
      ICTimerBuf.TimerMonth =0x04;
      ICTimerBuf.TimerYear =0x14;
      Ds1307_WriteData();
    }
  }
  ICTimer.TimerSec =(ICTimerBuf.TimerSec/16) * 10 +  (ICTimerBuf.TimerSec%16);
  ICTimer.TimerMin =(ICTimerBuf.TimerMin/16) * 10 +  (ICTimerBuf.TimerMin%16);
  ICTimer.TimerHour =((ICTimerBuf.TimerHour&0x1f)/16) * 10 +  ((ICTimerBuf.TimerHour&0x1f)%16);
  ICTimer.TimerWeek =(ICTimerBuf.TimerWeek/16) * 10 +  (ICTimerBuf.TimerWeek%16);
  ICTimer.TimerDay =(ICTimerBuf.TimerDay/16) * 10 +  (ICTimerBuf.TimerDay%16);
  ICTimer.TimerMonth =(ICTimerBuf.TimerMonth/16) * 10 +  (ICTimerBuf.TimerMonth%16);
  ICTimer.TimerYear =(ICTimerBuf.TimerYear/16) * 10 +  (ICTimerBuf.TimerYear%16);
  
  //更新系统时间参数
  g_u8TimeSettingHourValue = ICTimer.TimerHour;
  g_u8TimeSettingMinutesValue = ICTimer.TimerMin;
  g_u8TimeSettingAmPmValue = (ICTimerBuf.TimerHour &0x20)?1:0;
}
 
/*******************************************************************************
//  Function:     Write_Time
//  Description:  如果设置了时钟则写入时钟
//  Param:       
//  Return:     
*******************************************************************************/
void Write_Time()
{
  if(g_u8TimeChangeFlag)    //如果设置了时钟
  {
    g_u8TimeChangeFlag = 0;
    ICTimerBuf.TimerSec = (ICTimer.TimerSec/10)*16 + (ICTimer.TimerSec%10);
    ICTimerBuf.TimerMin = (ICTimer.TimerMin/10)*16 + (ICTimer.TimerMin%10);
    ICTimerBuf.TimerHour = (ICTimer.TimerHour/10)*16 + (ICTimer.TimerHour%10);
    ICTimerBuf.TimerWeek = (ICTimer.TimerWeek/10)*16 + (ICTimer.TimerWeek%10);
    ICTimerBuf.TimerDay = (ICTimer.TimerDay/10)*16 + (ICTimer.TimerDay%10);
    ICTimerBuf.TimerMonth = (ICTimer.TimerMonth/10)*16 + (ICTimer.TimerMonth%10);
    ICTimerBuf.TimerYear = (ICTimer.TimerYear/10)*16 + (ICTimer.TimerYear%10);
    
    //转换为12时制时间
    if(g_u8TimeSettingAmPmValue %2)  //为1 表示 pM
    {
      ICTimerBuf.TimerHour |= 0x60;  
    }
    else  //为0表示AM
    {
      ICTimerBuf.TimerHour |= 0x40;  
    }
    //转换好之后把时间写入芯片
    Ds1307_WriteData();
  }
}
/*
*********************************************************************************************************
*    函 数 名: uint8_t DS1307_Read(uint8_t address)
*    功能说明: 向DS1307寄存器读取数据
*    形    参:寄存器地址
*    返 回 值: 读出的数据
*********************************************************************************************************
*/
uint8_t DS1307_Read(uint8_t address)
{
    uint8_t dat;    
    i2c_Start();
    i2c_SendByte(0xD0);//发送设备地址,写指令
    i2c_WaitAck();
    i2c_SendByte(address);//发送寄存器地址
    i2c_WaitAck();
    i2c_Stop();
    i2c_Start();//重新启动IIC总线
    i2c_SendByte(0xD1);    //发送设备地址,读指令
    i2c_WaitAck();
    dat=i2c_ReadByte(); //读一个字节数据
    i2c_NAck();    
    i2c_Stop();
    return dat;
}

/*
*********************************************************************************************************
*    函 数 名: DS1307_Wirte(uint8_t address , uint8_t dat)
*    功能说明: 向DS1307寄存器写数据
*    形    参:address:寄存器地址,dat:要写入的数据
*    返 回 值: 无
*********************************************************************************************************
*/
void DS1307_Wirte(uint8_t address , uint8_t dat)
{ 
    i2c_Start();
    i2c_SendByte(0xD0);//发送设备地址,写指令
    i2c_WaitAck();
    i2c_SendByte(address);//发送寄存器地址
    i2c_WaitAck();
    i2c_SendByte(dat);//写一个字节数据
    i2c_WaitAck();
    i2c_Stop();    
}

/*
*********************************************************************************************************
*    函 数 名: void DS1307_Init_Time(void)
*    功能说明: 第一次上电时,需要初始化时间,初始化一次后就不必重复初始化
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void DS1307_Init_Time(void)
{
    if(DS1307_Read(FLAG_ADDR)!=FLAG_VAL)//如果未初始化,执行初始化时间
    {
        DS1307_Set_Time(2023,2,16,19,02,00,4);//2023年2月16日 17:50:00 星期四
        printf("时间初始化完成,flag=%d\r\n",DS1307_Read(FLAG_ADDR));
    }    else{
        printf("时间已初始化过,flag=%d\r\n",DS1307_Read(FLAG_ADDR));
    }
}
//时间初始化设置
void DS1307_Set_Time(uint16_t year,uint8_t mon,uint8_t day,uint8_t hour,uint8_t min,uint8_t sec,uint8_t week)
{
    year-=2000;//年默认2000年开始
    if(year > 100) year = 0;
    
    //十进制转为BCD码
    year = ((year /10) << 4) + year %10;
    mon  = ((mon  /10) << 4) + mon  %10;
    day  = ((day  /10) << 4) + day  %10;
    week = ((week /10) << 4) + week  %10;
    hour = ((hour /10) << 4) + hour %10;
    min  = ((min  /10) << 4) + min  %10;
    sec  = ((sec  /10) << 4) + sec  %10;
    
    //写入寄存器,同时标记一个地址
    DS1307_Wirte(FLAG_ADDR,FLAG_VAL);   //写入已经设置时间标志        
    DS1307_Wirte(0x00,sec);    //设置秒
    DS1307_Wirte(0x01,min);    //设置分
    DS1307_Wirte(0x02,hour);   //设置时
    DS1307_Wirte(0x03,week);   //设置周
    DS1307_Wirte(0x04,day);    //设置日
    DS1307_Wirte(0x05,mon);    //设置月    
    DS1307_Wirte(0x06,year);   //设置年        
}
//获取当前时间
void Get_Now_Time(void)
{
    uint8_t sec,min,hour,week,day,mon,year;
    uint8_t i;
    
    sec  = DS1307_Read(0x00);
    min  = DS1307_Read(0x01);
    hour = DS1307_Read(0x02);
    week = DS1307_Read(0x03);    
    day  = DS1307_Read(0x04);
    mon  = DS1307_Read(0x05);
    year = DS1307_Read(0x06);
    
    //BCD码转十进制
    date_time.sec  = (sec/16)*10 + sec%16;
    date_time.min  = (min/16)*10 + min%16;
    date_time.hour = (hour/16)*10 + hour%16;
    date_time.day  = (day/16)*10  + day%16;
    date_time.mon  = (mon/16)*10  + mon%16;
    date_time.year = (year/16)*10 + year%16 + 2000;
    date_time.week = (week/16)*10 + week%16;               
}

猜你喜欢

转载自blog.csdn.net/yyandad/article/details/129673846
RTC
今日推荐