最近使用stm32F40x做一个项目,遇到比较蛋疼的一件事,同一份代码,在两个不同的环境下(Linux,windows下的keil5)编译出来的固件,烧录到板上,系统时间会自动改变,使用Linux平台编译的固件,系统时间总是比使用keil5编译出来的固件少1天,折腾了很久,最后发现,从RTC寄存器里面读出来的时间,两者是一致的,在调mktime()生成时间戳后就不一致了,那么问题就是出现在这个mktime()上面,因为都是调底层C库里面的mktime(),没法看到它们的实现方式,而且Linux版本的固件已经有产品在用户手上了,没办法,所以只能在keil版本上修改,以便与Linux版本保持一致,于是在网上找了好几种实现方式,但还是没能达到预期的效果,于是就自己重新实现了mktime();
1、首先定义tm结构体:(其实这个结构体我直接使用系统里面的定义)
struct tm {
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
int tm_wday; /* Day of week. [0-6] */
int tm_yday; /* Days in year.[0-365] */
int tm_isdst; /* DST. [-1/0/1]*/
long int tm_gmtoff; /* Seconds east of UTC. */
const char *tm_zone; /* Timezone abbreviation. */
};
2、重新定义time_t ;
typedef unsigned long time_t;
3、声明一个当前月中所经过的天数数组
const short __mday[13] =
{ 0,
(31),
(31+28),
(31+28+31),
(31+28+31+30),
(31+28+31+30+31),
(31+28+31+30+31+30),
(31+28+31+30+31+30+31),
(31+28+31+30+31+30+31+31),
(31+28+31+30+31+30+31+31+30),
(31+28+31+30+31+30+31+31+30+31),
(31+28+31+30+31+30+31+31+30+31+30),
(31+28+31+30+31+30+31+31+30+31+30+31),
};
4、写一个判断是否是闰年的接口
int __isleap(int year)
{
return (!(year % 4) && ((year % 100) || !(year % 400)));
}
5、实现mymktime()接口
time_t mymktime(struct tm *const t)
{
time_t day;
time_t i;
time_t years = t->tm_year - 70;
if (t->tm_sec > 60) {
t->tm_min += t->tm_sec/60;
t->tm_sec %= 60;
}
if (t->tm_min > 60) {
t->tm_hour += t->tm_min / 60;
t->tm_min %= 60;
}
if (t->tm_hour>24) {
t->tm_mday += t->tm_hour / 24;
t->tm_hour %= 24;
}
if (t->tm_mon > 12) {
t->tm_year += t->tm_mon / 12;
t->tm_mon %= 12;
}
while (t->tm_mday > __mday[1+t->tm_mon]) {
if (t->tm_mon == 1 && __isleap(t->tm_year + 1900)) {
--t->tm_mday;
}
t->tm_mday -= __mday[t->tm_mon];
++t->tm_mon;
if (t->tm_mon>11) {
t->tm_mon=0;
++t->tm_year;
}
}
if (t->tm_year < 70)
return (time_t) -1;
/* 1970年以来的天数等于365 *年数+ 1970年以来的闰年数 */
day = years * 365 + (years + 1) / 4;
/* 2100年以后,计算闰年的方式不一样了,每400年减去3个闰年,大多数mktime实现不支持2059年后的日期,所以可以把这个省略掉 */
if ((int)(years -= 131) >= 0) {
years /= 100;
day -= (years >> 2) * 3 + 1;
if ((years &= 3) == 3)
years--;
day -= years;
}
day += t->tm_yday = __mday [t->tm_mon] + t->tm_mday-1 + ( __isleap (t->tm_year + 1900) & (t->tm_mon > 1) );
/* 现在是自1970年1月1日以来的天数 */
i = 7;
t->tm_wday = (day + 4) % i; /* 星期天=0, 星期一=1, ..., 星期六=6 */
i = 24;
day *= i;
i = 60;
return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec;
}
6、测试
void show_system_time(void)
{
struct tm dt;
utime_t utime;
RTC_TimeTypeDef RTC_TimeStructure;
RTC_DateTypeDef RTC_DateStructure;
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);
dt.tm_sec = RTC_TimeStructure.RTC_Seconds;
dt.tm_min = RTC_TimeStructure.RTC_Minutes;
dt.tm_hour = RTC_TimeStructure.RTC_Hours;
dt.tm_mon = RTC_DateStructure.RTC_Month -1;
dt.tm_mday = RTC_DateStructure.RTC_Date;
dt.tm_year = RTC_DateStructure.RTC_Year + 100;
utime = (utime_t)mymktime(&dt);
printf("utime: %d \r\n",utime);
return ;
}