C语言日期与时间戳转换 STM32F103 DS1302

由于公司项目原因 用到了DS1302
其中时间是由时间戳转换成日期存到DS1302的 在网上查找过一些代码 再加上自己的一些理解 将代码提供出来
适用于 DS1302 的读写驱动 以及 时间戳转日期 日期转时间戳 DS1302是否掉电等问题。有需要的可以了解一下。
1.ds1302.c

#include "ds1302.h"

char PowerDown=0;            //掉电标志 如果为 1 说明掉过电
extern volatile u32 system_time;   //系统时间

struct DS1302DATA ds1302Data = {0,0,0,0,0,0,0};
u8 ascii_time[7] = {0};     //保存ascii格式数据
 
u8 bcd_time[7] = {0};       //保存bcd码数据
 
static u8 AsciiToBcd(u8 asciiData)
{
    u8 bcdData = 0;
    bcdData = (((asciiData/10)<<4)|((asciiData%10)));
    return bcdData;
}
static u8 BcdToAscii(u8 bcdData)
{
    u8 asciiData = 0;
    asciiData = (((bcdData&0xf0)>>4)*10 + (bcdData&0x0f));
    return asciiData;
}
 
//IO口初始化
void Ds1302_Gpio_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    
    //RST
    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_12;      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
    GPIO_Init(GPIOD, &GPIO_InitStructure);
    
    //CLK
    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10;      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
    GPIO_Init(GPIOD, &GPIO_InitStructure);
    
    //IO
    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11;      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
    GPIO_Init(GPIOD, &GPIO_InitStructure);
}
 
//读取一个字节的时序
u8 Ds1302_ReadByte(void)
{
    u8 i = 0, dat = 0;
    DS1302_DAT_INPUT();
    delay_us(5);
    for(i = 0; i <8; i++)
    {
        dat >>= 1;
        if(DS1302_DATIN == 1)dat |= 0x80;
        DS1302_CLK = 1;
        delay_us(2);
        DS1302_CLK = 0;
        delay_us(2);
    }
    return dat;
}
 
//写入一个字节的时序
void Ds1302_WriteByte(u8 dat)
{
    u8 i = 0, data = dat;
    DS1302_DAT_OUTPUT(); 
    DS1302_CLK = 0;
    delay_us(2);
    for(i = 0; i < 8; i++)
    {
        DS1302_DATOUT = data&0x01;
        delay_us(2);
        DS1302_CLK = 1;
        delay_us(2);
        DS1302_CLK = 0;
        data >>= 1;
    }
}
 
//写入一个寄存器
void Ds1302_Write(u8 address,u8 dat)
{
    DS1302_RST = 0;
    DS1302_CLK = 0;
    DS1302_RST = 1;
    Ds1302_WriteByte(address);
    Ds1302_WriteByte(dat);
    DS1302_CLK = 1;
    DS1302_RST = 0;
}
 
//单个写入时间
void Ds1302_Write_Time_Singel(u8 address,u8 dat)
{
    Ds1302_Write(DS1302_CONTROL_REG,0x00);  //取消写保护
    Ds1302_Write(address,dat);
    Ds1302_Write(DS1302_CONTROL_REG,0x80);  //打开写保护
}
 
//一次完成所有时间更新
//start当前时钟运行还是停止
void Ds1302_Write_Time_All(u8 start)
{
    Ds1302_Write(DS1302_CONTROL_REG,0x00);      //取消写保护
    Ds1302_Write(DS1302_SEC_REG,(AsciiToBcd(ds1302Data.sec)|start));
    Ds1302_Write(DS1302_MIN_REG,AsciiToBcd(ds1302Data.min));
    Ds1302_Write(DS1302_HR_REG,AsciiToBcd(ds1302Data.hour));
    Ds1302_Write(DS1302_DATE_REG,AsciiToBcd(ds1302Data.day));
    Ds1302_Write(DS1302_MONTH_REG,AsciiToBcd(ds1302Data.month));
    Ds1302_Write(DS1302_DAY_REG,AsciiToBcd(ds1302Data.week));
    Ds1302_Write(DS1302_YEAR_REG,AsciiToBcd(ds1302Data.year));
    Ds1302_Write(DS1302_CONTROL_REG,0x80);  //打开写保护
}
 
 
//读取一个字节
u8 Ds1302_Read(u8 address)
{
    u8 data = 0;
    DS1302_RST = 0;
    DS1302_CLK = 0;
    DS1302_RST = 1;
    Ds1302_WriteByte(address|0x01); //读取地址需要与0x01相或,最低为变成1
    data = Ds1302_ReadByte();
    DS1302_CLK = 1;
    DS1302_RST = 0;
    return data;
}
 
//读取时间的时候默认让时间走起来
void Ds1302_Readtime(void)
{
    ds1302Data.sec = BcdToAscii(Ds1302_Read(DS1302_SEC_REG));  //秒
    ds1302Data.min = BcdToAscii(Ds1302_Read(DS1302_MIN_REG));  //分
    ds1302Data.hour = BcdToAscii(Ds1302_Read(DS1302_HR_REG));   //小时
    ds1302Data.day = BcdToAscii(Ds1302_Read(DS1302_DATE_REG)); //日
    ds1302Data.month = BcdToAscii(Ds1302_Read(DS1302_MONTH_REG)); //月
    ds1302Data.week = BcdToAscii(Ds1302_Read(DS1302_DAY_REG));  //星期几
    ds1302Data.year = BcdToAscii(Ds1302_Read(DS1302_YEAR_REG)); //年

}
//判断DS1302是否掉过电
void Time_correct()
{
   
  if(Ds1302_Read(DS1302_RAM_BASE)!=0x55)   //掉过电
  {
	Ds1302_Readtime();
    PowerDown=1;
  }
//   Ds1302_Write(DS1302_RAM_BASE,0x55);   //  RAM中掉电会丢失
 
}
 
//UNIX转为UTC 已进行时区转换 北京时间UTC+8
void xSeconds2Date(unsigned int seconds)
{
    static unsigned int month[12]={
        /*01月*/31, 
        /*02月*/28, 
        /*03月*/31, 
        /*04月*/30, 
        /*05月*/31, 
        /*06月*/30, 
        /*07月*/31, 
        /*08月*/31, 
        /*09月*/30, 
        /*10月*/31, 
        /*11月*/30, 
        /*12月*/31 
    };
    unsigned int days; 
    unsigned short leap_y_count; 
    ds1302Data.sec=seconds%60;//获得秒 
    seconds/=60; 
    ds1302Data.min=seconds%60;//获得分 
    seconds+=8*60 ;        //时区矫正 转为UTC+8 bylzs
    seconds/=60; 
    ds1302Data.hour=seconds % 24;//获得时 
    days=seconds/24;//获得总天数 
    leap_y_count=(days + 365)/1461;//过去了多少个闰年(4年一闰) 
    if(((days + 366)%1461)==0) 
    {//闰年的最后1天 
        ds1302Data.year=1970+(days/366);//获得年 
        ds1302Data.month=12;              //调整月 
        ds1302Data.day=31; 
        return; 
    } 
    days-=leap_y_count; 
    ds1302Data.year=1970+(days/365);     //获得年 
    days%=365;                       //今年的第几天 
    days=01+days;                  //1日开始 
    if((ds1302Data.year%4)==0) 
    { 
        if(days>60)--days;            //闰年调整 
        else 
        { 
            if(days == 60) 
            { 
                ds1302Data.month=2; 
                ds1302Data.day=29; 
                return; 
            } 
        } 
    } 
    for(ds1302Data.month= 0;month[ds1302Data.month]<days;ds1302Data.month++) 
    { 
        days-=month[ds1302Data.month]; 
    } 
    ++ds1302Data.month;               //调整月 
    ds1302Data.day=days;           //获得日 
}
typedef struct t_xtime {
  int year; int month;  int day;  
  int hour; int minute;  int second;
} _xtime ;
 
#define xMINUTE   (60) //1分的秒数
#define xHOUR     (60*xMINUTE) //1小时的秒数
#define xDAY      (24*xHOUR) //1天的秒数
#define xYEAR     (365*xDAY) //1年的秒数
unsigned int  xDate2Seconds()
{
  static unsigned int  month[12]={
    /*01月*/xDAY*(0),
    /*02月*/xDAY*(31),
    /*03月*/xDAY*(31+28),
    /*04月*/xDAY*(31+28+31),
    /*05月*/xDAY*(31+28+31+30),
    /*06月*/xDAY*(31+28+31+30+31),
    /*07月*/xDAY*(31+28+31+30+31+30),
    /*08月*/xDAY*(31+28+31+30+31+30+31),
    /*09月*/xDAY*(31+28+31+30+31+30+31+31),
    /*10月*/xDAY*(31+28+31+30+31+30+31+31+30),
    /*11月*/xDAY*(31+28+31+30+31+30+31+31+30+31),
    /*12月*/xDAY*(31+28+31+30+31+30+31+31+30+31+30)
  };
  unsigned int  seconds = 0;
  unsigned int  year = 0;
  year=ds1302Data.year-1970;       //不考虑2100年千年虫问题
  seconds = xYEAR*year + xDAY*((year+1)/4);  //前几年过去的秒数
  seconds += month[ds1302Data.month-1];      //加上今年本月过去的秒数
  if( (ds1302Data.month > 2) && (((year+2)%4)==0) )//2008年为闰年
    seconds += xDAY;            //闰年加1天秒数
  seconds += xDAY*(ds1302Data.day-1);         //加上本天过去的秒数
  seconds += xHOUR*ds1302Data.hour;           //加上本小时过去的秒数
  seconds += xMINUTE*ds1302Data.min;       //加上本分钟过去的秒数
  seconds += ds1302Data.sec;               //加上当前秒数<br> seconds -= 8 * xHOUR;
  return seconds;
}
//读取日期转时间戳 本地时间
void Read_TimeStamp(void)
{
  Ds1302_Readtime();
  system_time=xDate2Seconds();
}
//时间戳转日期 写入DS1302
void Write_TimeStamp(unsigned int secon)
{
  xSeconds2Date(secon);
  
  Ds1302_Write_Time_All(0);
  PowerDown=0;
  Ds1302_Write(DS1302_RAM_BASE,0x55);   //  RAM中掉电会丢失
}

2.ds1302.h

#ifndef __DS1302_H
#define __DS1302_H
#include "stm32f10x.h"
#include "delay.h"
extern u8 ascii_time[7];     //保存ascii格式数据
 
extern u8 bcd_time[7];       //保存bcd码数据
 
typedef struct DS1302DATA
{
    u8 year;    //年
    u8 month;   //月
    u8 day;     //日
    u8 hour;    //时
    u8 min;     //分
    u8 sec;     //秒
    u8 week;    //周
}DS1302DATA;
 
extern struct DS1302DATA ds1302Data;
 
#define DS1302_RST      PDout(12)
#define DS1302_CLK      PDout(10)
#define DS1302_DATIN    PDin(11)
#define DS1302_DATOUT   PDout(11)
 
#define DS1302_DAT_INPUT()     {GPIOD->CRH &= 0XFFFF0FFF;GPIOD->CRH|=8<<12;}
#define DS1302_DAT_OUTPUT()    {GPIOD->CRH &= 0XFFFF0FFF;GPIOD->CRH|=3<<12;}
 
//芯片寄存器地址定义 定义的写地址,读需要+1
#define DS1302_SEC_REG			0x80		//秒数据地址
#define DS1302_MIN_REG			0x82		//分数据地址
#define DS1302_HR_REG			0x84		//时数据地址
#define DS1302_DATE_REG			0x86		//日数据地址
#define DS1302_MONTH_REG		0x88		//月数据地址
#define DS1302_DAY_REG			0x8a		//星期几数据地址
#define DS1302_YEAR_REG			0x8c		//年数据地址
#define DS1302_CONTROL_REG		0x8e		//写保护寄存器地址
#define DS1302_CHARGER_REG		0x90 		//涓流充电寄存器			 
#define DS1302_CLKBURST_REG		0xbe             //脉冲串寄存器
#define DS1302_RAM_BASE                 0X30            //RAM基础地址
 
#define CLOCKSTOP       0X80
#define CLOCKSTART      0X00
 
 
void Ds1302_Gpio_Init(void);
void Ds1302_Write_Time_All(u8 start);
void Ds1302_Readtime(void);
void Time_correct(); 
unsigned int  xDate2Seconds();
void xSeconds2Date(unsigned int seconds);
void Read_TimeStamp(void);
void Write_TimeStamp(unsigned int secon);

#endif

需要注意的是 DS1302的秒寄存器需要最高位置0,DS1302才能正常工作。
另外DS1302预留有RAM 可以通过读取可以上电判断是否DS1302掉过电
,掉电则需要时钟更新 (掉电后时间不准确)。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值