ds1302

ds1302_drive_function.h

/******************************************************************************
* @ File name --> ds1302.h
* @ Author    --> By@ Sam Chan
* @ Version   --> V1.0
* @ Date      --> 08 - 23 - 2012
* @ Brief     --> 时钟芯片DS1302驱动
*
* @ Copyright (C) 20**
* @ All rights reserved
*******************************************************************************
*
*                                  File Update
* @ Version   --> V1.0.1
* @ Author    --> By@ Sam Chan
* @ Date      --> 10 - 20 - 2013 
* @ Revise    --> A、增加对STM32控制的移植支持
* @           --> B、增加对内置的RAM操作相关函数
* @           --> C、增加检测DS1302是否存在,是否第一次上电检测函数
* @           --> D、增加对DS1302内置的锂电池充电寄存器参数设置函数和结构体
*
******************************************************************************/
#ifndef __DS1302_DRIVE_FUNCTION_H
#define __DS1302_DRIVE_FUNCTION_H


#include "main.h"


/********************************************************************************
                                引脚定义
*******************************************************************************/
//时钟引脚
#define DS1302_SCL_GPIO_PORT            GPIOF
#define DS1302_SCL_GPIO_PIN                GPIO_Pin_2


//数据引脚
#define DS1302_SDA_GPIO_PORT            GPIOF
#define DS1302_SDA_GPIO_PIN                GPIO_Pin_3


//复位引脚
#define DS1302_RST_GPIO_PORT            GPIOF
#define DS1302_RST_GPIO_PIN                GPIO_Pin_4



#define DS1302_GPIO_CLK                    RCC_APB2Periph_GPIOF            //GPIO端口时钟
#define DS1302_GPIO_ClockCmd            RCC_APB2PeriphClockCmd            //打开端口时钟的函数




#define DS1302_SCL_H()        GPIO_SetBits(DS1302_SCL_GPIO_PORT, DS1302_SCL_GPIO_PIN)
#define DS1302_SDA_H()        GPIO_SetBits(DS1302_SDA_GPIO_PORT, DS1302_SDA_GPIO_PIN)
#define DS1302_RST_H()        GPIO_SetBits(DS1302_RST_GPIO_PORT, DS1302_RST_GPIO_PIN)


#define DS1302_SCL_L()        GPIO_ResetBits(DS1302_SCL_GPIO_PORT, DS1302_SCL_GPIO_PIN)
#define DS1302_SDA_L()        GPIO_ResetBits(DS1302_SDA_GPIO_PORT, DS1302_SDA_GPIO_PIN)
#define DS1302_RST_L()        GPIO_ResetBits(DS1302_RST_GPIO_PORT, DS1302_RST_GPIO_PIN)


#define DS1302_SDA_READ()      GPIO_ReadInputDataBit(DS1302_SDA_GPIO_PORT, DS1302_SDA_GPIO_PIN)    //读IO口线状态




#define test_data                    0x01    //此数据用来检测DS1302是否存在于总线上用,可以改用其他值




/******************************************************************************
                                时间寄存器地址
******************************************************************************/
#define Clock_Address_Bass            0x80    //基地址

#define DS1302_Address_Year            (Clock_Address_Bass | 0x0c)    //
#define DS1302_Address_Month        (Clock_Address_Bass | 0x08)    //
#define DS1302_Address_Date            (Clock_Address_Bass | 0x06)    //
#define DS1302_Address_Week            (Clock_Address_Bass | 0x0a)    //星期
#define DS1302_Address_Hour            (Clock_Address_Bass | 0x04)    //小时
#define DS1302_Address_Minute        (Clock_Address_Bass | 0x02)    //分钟
#define DS1302_Address_Second        (Clock_Address_Bass | 0x00)    //

#define Clock_Soft_Reset            (Clock_Address_Bass | 0x3e)    //时钟软复位

#define Address_WP                    (Clock_Address_Bass | 0x0e)    //写保护地址
#define WP_Enable                    0x80    //打开写保护
#define WP_Disable                    0x00    //关闭写保护




/******************************************************************************
                               电源管理寄存器地址
******************************************************************************/

/******************************************************************************
电源管理寄存器位描述
    bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
    TCS3  TCS2  TCS1  TCS0   DS1   DS0   RS1   RS0

    TCSx:充电电流大小选择,值为0xa0时打开充电,其他值时关闭,DS1302默认是关闭的
    DSx:设置VCC1和VCC2之间的二极管串联数量,0x01时为串联一只二极管,0x10时为串联两只二极管,0x00或0x11时关闭充电功能
    RSx:设置限流电阻大小,0x00为开路并关闭充电功能,0x01为2K,0x10为4K,0x11为8K
******************************************************************************/
#define Trickle_Charger_Address    (Clock_Address_Bass | 0x10)    //管理电源,主电源供电时可以设置给备用电池充电


#define Open_Trickle_Charge        0x0a
#define Close_Trickle_Charge    0x00    //设置为其他值也可以


#define One_Diode                0x01
#define Two_Diode                0x10
#define None_Diode                0x00    //or 0x11,断开串联并关闭充电功能


#define Resistor_For2K            0x01
#define Resistor_For4K            0x10
#define Resistor_For8K            0x11
#define None_Resistor            0x00    //断开串联限流电阻并关闭充电功能




//RAM地址
#define RAM_Address_Bass        0xc0    //基地址

#define RAM_Address0            (RAM_Address_Bass | 0x00)    //RAM地址 = 基地址 + 地址偏移量
#define RAM_Address1            (RAM_Address_Bass | 0x02)
#define RAM_Address2            (RAM_Address_Bass | 0x04)
#define RAM_Address3            (RAM_Address_Bass | 0x06)
#define RAM_Address4            (RAM_Address_Bass | 0x08)
#define RAM_Address5            (RAM_Address_Bass | 0x0a)
#define RAM_Address6            (RAM_Address_Bass | 0x0c)
#define RAM_Address7            (RAM_Address_Bass | 0x0e)

#define RAM_Address8            (RAM_Address_Bass | 0x10)
#define RAM_Address9            (RAM_Address_Bass | 0x12)
#define RAM_Address10            (RAM_Address_Bass | 0x14)
#define RAM_Address11            (RAM_Address_Bass | 0x16)
#define RAM_Address12            (RAM_Address_Bass | 0x18)
#define RAM_Address13            (RAM_Address_Bass | 0x1a)
#define RAM_Address14            (RAM_Address_Bass | 0x1c)
#define RAM_Address15            (RAM_Address_Bass | 0x1e)

#define RAM_Address16            (RAM_Address_Bass | 0x20)
#define RAM_Address17            (RAM_Address_Bass | 0x22)
#define RAM_Address18            (RAM_Address_Bass | 0x24)
#define RAM_Address19            (RAM_Address_Bass | 0x26)
#define RAM_Address20            (RAM_Address_Bass | 0x28)
#define RAM_Address21            (RAM_Address_Bass | 0x2a)
#define RAM_Address22            (RAM_Address_Bass | 0x2c)
#define RAM_Address23            (RAM_Address_Bass | 0x2e)

#define RAM_Address24            (RAM_Address_Bass | 0x32)
#define RAM_Address25            (RAM_Address_Bass | 0x34)
#define RAM_Address26            (RAM_Address_Bass | 0x36)
#define RAM_Address27            (RAM_Address_Bass | 0x38)
#define RAM_Address28            (RAM_Address_Bass | 0x3a)
#define RAM_Address29            (RAM_Address_Bass | 0x3c)

#define RAM_BURST                (RAM_Address_Bass | 0x3e)






//写秒为00并启动时钟
#define DS1302_Start_Second()    (DS1302_Write_Data(Address_second,0x00))


//写保护命令
#define    DS1302_WP_Enable()        (DS1302_Write_Byte(Address_WP,WP_Enable))    //打开写保护
#define    DS1302_WP_Disable()        (DS1302_Write_Byte(Address_WP,WP_Disable))    //关闭写保护


//关闭充电功能,可以直接调用
#define DS1302_Disable_Charge()    (DS1302_Write_Byte(Trickle_Charger_Address,0x00))





/******************************************************************************
                                 定义时间结构
******************************************************************************/
typedef struct DS1302_Time_Typedef
{
    uint8_t  year;        //
    uint8_t  month;        //
    uint8_t  date;        //
    uint8_t  week;        //星期
    uint8_t     hour;        //小时
    uint8_t  minute;    //分钟
    uint8_t  second;    //秒钟 
}DS1302_Time_Typedef;



/******************************************************************************
                              定义充电管理寄存器结构
******************************************************************************/
typedef struct DS1302_Charge_Typedef
{
    u8 TCSx;    //充电开关
    u8 DSx;        //串联二极管
    u8 RSx;        //限流电阻 
}DS1302_Charge_Typedef;




/******************************************************************************
                                 外部功能函数
******************************************************************************/

#define DS1302_Delay_US   SysTick_Delay_US 
#define DS1302_Delay_MS   SysTick_Delay_MS 


void DS1302_Config_Init(void);


uint8_t DS1302_Read_Byte(uint8_t Read_Addr);
void DS1302_Write_Byte(uint8_t Write_Addr,uint8_t Write_Data);


void DS1302_Charge_Manage(DS1302_Charge_Typedef* CHG_dat);
uint8_t DS1302_Check(void);


void DS1302_Time_Init(void);
void DS1302_Write_Time(DS1302_Time_Typedef * Time);
void DS1302_Read_Time(DS1302_Time_Typedef* Time);
void DS1302_Time_Revise(DS1302_Time_Typedef* Time);


extern DS1302_Time_Typedef DS1302_Time_Value;
extern DS1302_Charge_Typedef DS1302_Charge_Value;



#endif

 

ds1302_drive_function.c

#include "ds1302_drive_function.h"


DS1302_Time_Typedef DS1302_Time_Value;        //读时间值
DS1302_Charge_Typedef DS1302_Charge_Value;    //定义充电寄存器
uint8_t DS1302_Time_Revise_Flag = 0;


/********************************************************************************
                                    引脚配置
*******************************************************************************/
/**
  * @brief  配置DS1302的引脚
  * @param  无
  * @retval 无
  */
static void DS1302_GPIO_Config(void)
{    
    DS1302_GPIO_ClockCmd(DS1302_GPIO_CLK,ENABLE);            //开启引脚时钟
    
    GPIO_InitTypeDef GPIO_InitStructure;   //定义一个GPIO_InitTypeDef类型的结构体
        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    GPIO_InitStructure.GPIO_Pin = DS1302_SCL_GPIO_PIN;
    GPIO_Init(DS1302_SCL_GPIO_PORT, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = DS1302_SDA_GPIO_PIN;
    GPIO_Init(DS1302_SDA_GPIO_PORT, &GPIO_InitStructure);
        
    GPIO_InitStructure.GPIO_Pin = DS1302_RST_GPIO_PIN;
    GPIO_Init(DS1302_RST_GPIO_PORT, &GPIO_InitStructure);

    DS1302_SCL_L();            //SCLK置低    
    DS1302_SDA_H();            //IO断开拉高
    DS1302_RST_L();            //RST置低
}



/**
  * @brief  DS1302引脚初始化
  * @param  无
  * @retval 无
  */
void DS1302_Config_Init(void)
{
    DS1302_GPIO_Config();
}


/**
  * @brief  配置DS1302的IO口为输入
  * @param  无
  * @retval 无
  */
static void DS1302_SDA_INTPUT(void)
{    
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    GPIO_InitStructure.GPIO_Pin = DS1302_SDA_GPIO_PIN;
    GPIO_Init(DS1302_SDA_GPIO_PORT, &GPIO_InitStructure);    
}



/**
  * @brief  配置DS1302的IO口为输出
  * @param  无
  * @retval 无
  */
static void DS1302_SDA_OUTPUT(void)
{    
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    GPIO_InitStructure.GPIO_Pin = DS1302_SDA_GPIO_PIN;
    GPIO_Init(DS1302_SDA_GPIO_PORT, &GPIO_InitStructure);    
}




/********************************************************************************
                                    驱动函数
*******************************************************************************/
/**
  * @brief  接收DS1302数据
  * @param  无
  * @retval 接收的数据
  */
static uint8_t DS1302_ReceiveData(void)
{
    uint8_t Data=0x00;

    DS1302_SDA_INTPUT();                //设置为输入口
    for(uint8_t i=0;i<8;i++)
    {
        Data >>= 1;
        if(DS1302_SDA_READ())        //读出一位数据是1
        {
            Data |= 0x80;    
        }
        else
        {
            Data &= 0x7F;
        }        
        DS1302_SCL_H();
        DS1302_Delay_US(3);
        DS1302_SCL_L();    
    }
    
    return Data;    //返回读取到的数据
}



/**
  * @brief  给DS1302发送数据
  * @param  Data:要发送的数据
  * @retval 无
  */
static void DS1302_SendData(uint8_t Data)
{
    DS1302_SDA_OUTPUT();    //设置为输出口
    for(uint8_t i=0;i<8;i++)
    {        
        if(Data & 0x01)    
        {
            DS1302_SDA_H();
        }
        else
        {
            DS1302_SDA_L();;    
        }
        DS1302_SCL_H();
        DS1302_Delay_US(10);
        DS1302_SCL_L();
        
        Data >>= 1;    
    }
}




/**
  * @brief  从DS1302某地址读取数据
  * @param  Read_Addr:要操作的地址
  * @retval 读取的数据
  */
uint8_t DS1302_Read_Byte(uint8_t Read_Addr)
{
    uint8_t Read_Data;

    DS1302_RST_L();
    DS1302_Delay_US(10);
    DS1302_RST_H();
    
    Read_Addr = Read_Addr | 0x01;
    
    DS1302_SendData(Read_Addr);    //写入要读取地址
    Read_Data = DS1302_ReceiveData();    //开始读取数据
    
    DS1302_RST_L();
    
    return Read_Data;    
}


/**
  * @brief  向DS1302某地址写入一个数据
  * @param  Write_Addr:要操作的地址    Write_Data:要写入的数据
  * @retval 无
  */
void DS1302_Write_Byte(uint8_t Write_Addr,uint8_t Write_Data)
{
    DS1302_RST_L();
    DS1302_Delay_US(10);
    DS1302_RST_H();
    
    Write_Addr = Write_Addr & 0xFE; //最低位置零,写数据
    
    DS1302_SendData(Write_Addr);    //要写入的地址
    DS1302_SendData(Write_Data);    //要写入的数据
    
    DS1302_RST_L();
}


/**
  * @brief  从DS1302某地址读取多个数据
  * @param  Read_Addr:要读取的地址 ,范围在RAM_Address0 ~ RAM_Address28之间,最后一位地址有其他用途   
  *         Read_Num:要读取的数据字节数 ,范围在1 ~ 28之间    
  *         p_Read_Buffer:读取数据的缓冲区
  * @retval 读取的数据
  */
void DS1302_Read_Buffer(uint8_t Read_Addr,uint8_t Read_Num,uint8_t* p_Read_Buffer)
{                                                             
    for(uint8_t i= 0;i < Read_Num;i++)
    {
        DS1302_WP_Disable();//取消写保护
        p_Read_Buffer[i] = DS1302_Read_Byte(Read_Addr+1+(i<<1));
        DS1302_WP_Enable();//打开写保护
    }
}



/**
  * @brief  往DS1302某地址写入多个数据
  * @param  Write_Addr:要写入的地址 ,范围在RAM_Address0 ~ RAM_Address28之间,最后一位地址有其他用途   
  *         Write_Num:要写入的数据字节数 ,范围在1 ~ 28之间    
  *         p_Write_Buffer:写入数据的缓冲区
  * @retval 无
  */
void DS1302_Write_Buffer(uint8_t Write_Addr,uint8_t Write_Num,uint8_t* p_Write_Buffer)
{                                                             
    if(Write_Addr == RAM_Address29)    
    {
        return;    //要写入数据的RAM地址是最后一个,直接退出,因为最后一个字节是用来检测DS1302的
    }

    for(uint8_t i = 0;i < Write_Num;i++)
    {
        DS1302_WP_Disable();//取消写保护
        DS1302_Write_Byte(Write_Addr+(i<<1),p_Write_Buffer[i]);
        DS1302_WP_Enable();//打开写保护
    }

}



/********************************************************************************
                                    用户调用函数
*******************************************************************************/

/**
  * @brief  主电源对备用电池充电设置如果备用电池接的是可充电的锂电池或者其他可充电电池的时候,可以打开DS1302的充电电路,利用主供电对电池进行充电,免的换电池的麻烦
  * @param  *CHG_dat:寄存器控制指针
  * @retval 无
  */
void DS1302_Charge_Manage(DS1302_Charge_Typedef* CHG_dat)
{
    uint8_t CHG_Value;

    CHG_Value = (CHG_dat->TCSx << 4) | (CHG_dat->DSx << 2) | CHG_dat->RSx;  

    DS1302_WP_Disable();//取消写保护
    DS1302_Write_Byte(Trickle_Charger_Address,CHG_Value);
    DS1302_WP_Enable();//打开写保护
}




/**
  * @brief  测试设备好坏,在DS1302芯片的RAM的最后一个地址写入一个数据并读出来判断与上次写入的值相等,不是第一次上电,否则则初始化时间
  * @param  无
  * @retval 0:设备正常并不是第一次上电
  *         1:设备错误或者已损坏 
  */
uint8_t DS1302_Check(void)
{
    uint8_t test_value;

    DS1302_WP_Disable();//取消写保护
    test_value = DS1302_Read_Byte(RAM_Address29 + 1);    //读出最后一个RAM地址里的数据
    DS1302_WP_Enable();    //打开写保护
    
    if(test_value == test_data)    //判断数据是否对
    {
        return 0;    //设备正常,不是第一次上电
    }
    else
    {
        return 1;    //不是第一次上电或者设备异常        
    }
}





/**
  * @brief  DS1302时间初始化
  * @param  无
  * @retval 无
  */
void DS1302_Time_Init(void)
{    
    DS1302_Time_Typedef Time={0x20,0x05,0x11,0x01,0x09,0x06,0x00};
    
    if(!DS1302_Check())
    {
        return ;
    }
    else
    {    
        DS1302_WP_Disable();//取消写保护
        DS1302_Write_Byte(DS1302_Address_Second,0x80);          //暂停时钟
        DS1302_Write_Byte(DS1302_Address_Year,Time.year);        //写年数据
        DS1302_Write_Byte(DS1302_Address_Week,Time.week);        //写星期数据
        DS1302_Write_Byte(DS1302_Address_Month,Time.month);        //写月数据
        DS1302_Write_Byte(DS1302_Address_Date,Time.date);        //写日数据
        DS1302_Write_Byte(DS1302_Address_Hour,Time.hour);        //写小时数据
        DS1302_Write_Byte(DS1302_Address_Minute,Time.minute);    //写分钟数据
        DS1302_Write_Byte(DS1302_Address_Second,Time.second);    //写秒数据
        
        DS1302_Write_Byte(RAM_Address29+1,test_data);    //向RAM最后一个地址里写入数据
        
        DS1302_WP_Enable();//打开写保护
    }
}                          





/**
  * @brief  DS1302写时间
  * @param  *Time: 时间结构体指针
  * @retval 无
  */
void DS1302_Write_Time(DS1302_Time_Typedef *Time)
{        
    DS1302_WP_Disable();//取消写保护
    DS1302_Write_Byte(DS1302_Address_Second,0x80);           //暂停时钟
    DS1302_Write_Byte(DS1302_Address_Year,Time->year);        //写年数据
    DS1302_Write_Byte(DS1302_Address_Week,Time->week);        //写星期数据
    DS1302_Write_Byte(DS1302_Address_Month,Time->month);    //写月数据
    DS1302_Write_Byte(DS1302_Address_Date,Time->date);        //写日数据
    DS1302_Write_Byte(DS1302_Address_Hour,Time->hour);        //写小时数据
    DS1302_Write_Byte(DS1302_Address_Minute,Time->minute);    //写分钟数据
    DS1302_Write_Byte(DS1302_Address_Second,Time->second);    //写秒数据    
    DS1302_WP_Enable();//打开写保护
}    




/**
  * @brief  DS1302读时间
  * @param  *Time: 时间结构体指针
  * @retval 无
  */
void DS1302_Read_Time(DS1302_Time_Typedef* Time)
{
    uint8_t time_buffer[10];
    
    DS1302_WP_Disable();//取消写保护
    time_buffer[0] = DS1302_Read_Byte(DS1302_Address_Year);        //读年数据
    time_buffer[1] = DS1302_Read_Byte(DS1302_Address_Month);    //读月数据
    time_buffer[2] = DS1302_Read_Byte(DS1302_Address_Date);        //读日数据
    time_buffer[3] = DS1302_Read_Byte(DS1302_Address_Week);        //读星期数据
    time_buffer[4] = DS1302_Read_Byte(DS1302_Address_Hour);        //读小时数据
    time_buffer[5] = DS1302_Read_Byte(DS1302_Address_Minute);    //读分钟数据
    time_buffer[6] = DS1302_Read_Byte(DS1302_Address_Second);    //读秒数据
    DS1302_WP_Enable();//打开写保护
    
    
    Time->year = (time_buffer[0]>>4) * 10 + (time_buffer[0]&0x0f);
    Time->month = (time_buffer[1]>>4) * 10 + (time_buffer[1]&0x0f);
    Time->date = (time_buffer[2]>>4) * 10 + (time_buffer[2]&0x0f);
    Time->week = (time_buffer[3]&0x07);
    Time->hour = (time_buffer[4]>>4) * 10 + (time_buffer[4]&0x0f);
    Time->minute = (time_buffer[5]>>4) * 10 + (time_buffer[5]&0x0f);
    Time->second = (time_buffer[6]>>4) * 10 + (time_buffer[6]&0x0f);
}


/**
  * @brief  DS1302时间校正
  * @param  *Time: 时间结构体指针
  * @retval 无
  */
void DS1302_Time_Revise(DS1302_Time_Typedef* Time)
{
    if(Time->week == 1 && Time->hour == 11 && Time->minute == 59 && Time->second <= 30)
    {
        DS1302_Time_Revise_Flag = 1;
    }

    if(Time->week == 1 && Time->hour == 12 && Time->minute == 0 &&  Time->second == 7)
    {
        if(DS1302_Time_Revise_Flag == 1) //校正秒
        {
            DS1302_Write_Byte(DS1302_Address_Second,0);      

            DS1302_Time_Revise_Flag = 0;
        }    
    }        
}

 

posted @ 2020-08-13 22:08  孤情剑客  阅读(583)  评论(0)    收藏  举报