由于公司项目原因 用到了DS1302 其中时间是由时间戳转换成日期存到DS1302的 在网上查找过一些代码 再加上自己的一些理解 将代码提供出来
适用于 DS1302 的读写驱动 以及 时间戳转日期 日期转时间戳 DS1302是否掉电等问题。有需要的可以了解一下。 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中掉电会丢失
- }
复制代码 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掉过电
,掉电则需要时钟更新 (掉电后时间不准确)。
|