首页 > 代码库 > 硬件时钟--DS1307时钟芯片

硬件时钟--DS1307时钟芯片

模拟I2C通讯控制DS1307读写硬件时钟


#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:       
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
static void I2C_Int(void)
{
   SET_SDA_OUT();  
   SET_SCL_OUT();
}

/*******************************************************************************
//  Function:     Delay_5us
//  Description:  微妙级延时函数   延时时间约为16us
//  Param:        
//  Return:       fcpu 16MHz 时
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
static void Delay_5us(void)
{
   uint8_t i;                 
   for (i=5; i>0; i--);
}

/*******************************************************************************
//  Function:     I2C_Start
//  Description:  I2C 开始传输信号  当SCL 为高时  SDA由高变低
//  Param:        
//  Return:      
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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:      
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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:      
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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表示无应答
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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为数据值
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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: 写入出错
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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位数据
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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:      
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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:      
//  Author: Huangzhigang 2014-0410
*******************************************************************************/
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表示时钟芯片掉电
//  Author: Huangzhigang 2014-0422
*******************************************************************************/
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:     
//  Author: Huangzhigang 2014-0422
*******************************************************************************/
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();
  }
}