標(biāo)題:
C語言日期與時(shí)間戳轉(zhuǎn)換 STM32F103 DS1302
[打印本頁]
作者:
1直到世界盡頭
時(shí)間:
2020-3-2 16:58
標(biāo)題:
C語言日期與時(shí)間戳轉(zhuǎn)換 STM32F103 DS1302
由于公司項(xiàng)目原因 用到了DS1302
其中時(shí)間是由時(shí)間戳轉(zhuǎn)換成日期存到DS1302的 在網(wǎng)上查找過一些代碼 再加上自己的一些理解 將代碼提供出來
適用于 DS1302 的讀寫驅(qū)動(dòng) 以及 時(shí)間戳轉(zhuǎn)日期 日期轉(zhuǎn)時(shí)間戳 DS1302是否掉電等問題。有需要的可以了解一下。
DS1302.c
#include "ds1302.h"
char PowerDown=0; //掉電標(biāo)志 如果為 1 說明掉過電
extern volatile u32 system_time; //系統(tǒng)時(shí)間
struct DS1302DATA ds1302Data = {0,0,0,0,0,0,0};
u8 ascii_time[7] = {0}; //保存ascii格式數(shù)據(jù)
u8 bcd_time[7] = {0}; //保存bcd碼數(shù)據(jù)
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);
}
//讀取一個(gè)字節(jié)的時(shí)序
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;
}
//寫入一個(gè)字節(jié)的時(shí)序
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;
}
}
//寫入一個(gè)寄存器
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;
}
//單個(gè)寫入時(shí)間
void Ds1302_Write_Time_Singel(u8 address,u8 dat)
{
Ds1302_Write(DS1302_CONTROL_REG,0x00); //取消寫保護(hù)
Ds1302_Write(address,dat);
Ds1302_Write(DS1302_CONTROL_REG,0x80); //打開寫保護(hù)
}
//一次完成所有時(shí)間更新
//start當(dāng)前時(shí)鐘運(yùn)行還是停止
void Ds1302_Write_Time_All(u8 start)
{
Ds1302_Write(DS1302_CONTROL_REG,0x00); //取消寫保護(hù)
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); //打開寫保護(hù)
}
//讀取一個(gè)字節(jié)
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;
}
//讀取時(shí)間的時(shí)候默認(rèn)讓時(shí)間走起來
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)); //小時(shí)
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中掉電會(huì)丟失
}
//UNIX轉(zhuǎn)為UTC 已進(jìn)行時(shí)區(qū)轉(zhuǎn)換 北京時(shí)間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 ; //時(shí)區(qū)矯正 轉(zhuǎn)為UTC+8 bylzs
seconds/=60;
ds1302Data.hour=seconds % 24;//獲得時(shí)
days=seconds/24;//獲得總天數(shù)
leap_y_count=(days + 365)/1461;//過去了多少個(gè)閏年(4年一閏)
if(((days + 366)%1461)==0)
{//閏年的最后1天
ds1302Data.year=1970+(days/366);//獲得年
ds1302Data.month=12; //調(diào)整月
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; //閏年調(diào)整
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; //調(diào)整月
ds1302Data.day=days; //獲得日
}
typedef struct t_xtime {
int year; int month; int day;
int hour; int minute; int second;
} _xtime ;
#define xMINUTE (60) //1分的秒數(shù)
#define xHOUR (60*xMINUTE) //1小時(shí)的秒數(shù)
#define xDAY (24*xHOUR) //1天的秒數(shù)
#define xYEAR (365*xDAY) //1年的秒數(shù)
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); //前幾年過去的秒數(shù)
seconds += month[ds1302Data.month-1]; //加上今年本月過去的秒數(shù)
if( (ds1302Data.month > 2) && (((year+2)%4)==0) )//2008年為閏年
seconds += xDAY; //閏年加1天秒數(shù)
seconds += xDAY*(ds1302Data.day-1); //加上本天過去的秒數(shù)
seconds += xHOUR*ds1302Data.hour; //加上本小時(shí)過去的秒數(shù)
seconds += xMINUTE*ds1302Data.min; //加上本分鐘過去的秒數(shù)
seconds += ds1302Data.sec; //加上當(dāng)前秒數(shù)<br> seconds -= 8 * xHOUR;
return seconds;
}
//讀取日期轉(zhuǎn)時(shí)間戳 本地時(shí)間
void Read_TimeStamp(void)
{
Ds1302_Readtime();
system_time=xDate2Seconds();
}
//時(shí)間戳轉(zhuǎn)日期 寫入DS1302
void Write_TimeStamp(unsigned int secon)
{
xSeconds2Date(secon);
Ds1302_Write_Time_All(0);
PowerDown=0;
Ds1302_Write(DS1302_RAM_BASE,0x55); // RAM中掉電會(huì)丟失
}
復(fù)制代碼
DS1302.h
#ifndef __DS1302_H
#define __DS1302_H
#include "stm32f10x.h"
#include "delay.h"
extern u8 ascii_time[7]; //保存ascii格式數(shù)據(jù)
extern u8 bcd_time[7]; //保存bcd碼數(shù)據(jù)
typedef struct DS1302DATA
{
u8 year; //年
u8 month; //月
u8 day; //日
u8 hour; //時(shí)
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 //秒數(shù)據(jù)地址
#define DS1302_MIN_REG 0x82 //分?jǐn)?shù)據(jù)地址
#define DS1302_HR_REG 0x84 //時(shí)數(shù)據(jù)地址
#define DS1302_DATE_REG 0x86 //日數(shù)據(jù)地址
#define DS1302_MONTH_REG 0x88 //月數(shù)據(jù)地址
#define DS1302_DAY_REG 0x8a //星期幾數(shù)據(jù)地址
#define DS1302_YEAR_REG 0x8c //年數(shù)據(jù)地址
#define DS1302_CONTROL_REG 0x8e //寫保護(hù)寄存器地址
#define DS1302_CHARGER_REG 0x90 //涓流充電寄存器
#define DS1302_CLKBURST_REG 0xbe //脈沖串寄存器
#define DS1302_RAM_BASE 0X30 //RAM基礎(chǔ)地址
#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
復(fù)制代碼
需要注意的是 DS1302的秒寄存器需要最高位置0,DS1302才能正常工作。
另外DS1302預(yù)留有RAM 可以通過讀取可以上電判斷是否DS1302掉過電
,掉電則需要時(shí)鐘更新 (掉電后時(shí)間不準(zhǔn)確)。
作者:
喂豬兒
時(shí)間:
2020-4-28 19:37
你好,請(qǐng)教一下:在void DS1302_WriteByte(u8 dat)中“DAT_OUT = data&0x01;”報(bào)錯(cuò)是什么原因呢?
作者:
Crazy·
時(shí)間:
2022-9-13 10:33
年應(yīng)該用u16吧,u8不太夠
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1