2019独角兽企业重金招聘Python工程师标准>>>
STM32 的RTC模块中有需要将无符号的32位整形数字转化为包含年,月,日,时,分,秒的结构体或者其余表达形式的信号,在纠结了好久之后,勉强第一次实现了功能,现在贴上代码
PS: 因为KEIL调试不够方便,将代码移植到WINDOWS里面调试成功,目前还未移植到STM32中。
#include <stdio.h>
typedef unsigned char INT8U;
typedef unsigned short int INT16U;
typedef unsigned int INT32U;
/* rtc.h
*/
#ifndef __RTC_H__
#define __RTC_H__
#define SECDAY 86400UL
#define YEAR_START 1970 //系统第一天为1970年1月1日
#define FIRST_WEEK 6 //1970年1月1日为星期四 2000年1月1日为星期六
#define YEAR_TOTAL 130 //只支持100年的数据
//定义结构体记录从RTC模块读取出的数据
typedef struct rtc_time{ //没有加入溢出检查模块,请自行防止数字溢出
INT8U tm_sec; //0-59
INT8U tm_min; //0-59
INT8U tm_hour; //0-23
INT8U tm_day; //1-31
INT8U tm_week; //1-7
INT8U tm_mon; //1-12
INT8U tm_year; //0- YEARTOTAL-1
} RTC_S;
void to_tm(INT32U tim,RTC_S* tm); //将32位数字转换为结构体
void from_tm(RTC_S* tm,INT32U* tim); //从tm中读取内容记录到tim中
void quick_init(void); //快速初始化,其实功能是加快后续运算,空间换时间
#endif
/* rtc.c
事实时钟模块
*/
//#include "includes.h"
#define ISLEEP(YEAR) (((YEAR)%4 == 0)&&\
(((YEAR)%100!=0)||((YEAR)%400 == 0)))
INT8U quick_leep[YEAR_TOTAL]; //该处理方式浪费了大量空间
INT16U year_sort[YEAR_TOTAL]; //用于判断具体哪年
INT16U month[12] = {31,59,90, 120,151,181, //判断月份
212,243,273, 304,334,365};
INT16U month_leep[12] = {31,60,91, 121,152,182, //判断闰年的月份
213,244,274, 305,335,366};
void quick_init(void) //快速初始化,其实功能是加快后续运算,空间换时间
{
INT8U i;
INT32U j;
for(i = 0 ; i < YEAR_TOTAL ; i++) //建立闰年快速查询表
{
j = i + YEAR_START;
if(ISLEEP(j))
{
quick_leep[i] = 1;
} else
{
quick_leep[i] = 0;
}
}
j = 0;
for(i = 0;i<YEAR_TOTAL;i++) //用于天数记录 判断属于哪年
{
j += quick_leep[i];
j += 365;
year_sort[i] = j;
}
}
void to_tm(INT32U tim,RTC_S* tm) //将32位数字转换为结构体
{
INT16U year_1; //用于查找年份
INT16U year_2; //用于查找出去年份后剩余多少天
INT16U year_3; //用于查找月份
INT16U year_4; //用于查找去除月份后剩余多少天
INT32U days,sec;
INT16U* pmonth;
sec = tim % SECDAY; //当前秒总数
//得到小时、分钟、秒钟数值
tm->tm_hour = sec / 3600;
tm->tm_min = (sec % 3600) / 60;
tm->tm_sec = (sec % 3600) % 60;
days = tim / SECDAY; //当前天总数
days += 2; //算上第一天
//得到星期
tm->tm_week = (days + 5 + FIRST_WEEK )%7 + 1;
//初步得到年份
year_1 = days / 365;
//最终得到year_1 即为当前所在的年份;
while(1)
{
if((0 == year_1)&&(days <= year_sort[0]))
{
year_2 = days;
break;
}
if((days <= year_sort[year_1])&&(days > year_sort[year_1 - 1]))
{
year_2 = days - year_sort[year_1 - 1];
break;
}
if(days > year_sort[year_1])
{
year_1 ++;
continue;
} else
{
year_1 --;
}
}
tm->tm_year = year_1;
year_3 = year_2 / 31; //初步决定是几月份
if(quick_leep[year_1]) //根据闰年与否选择不同的数组
{
pmonth = month_leep;
} else
{
pmonth = month;
}
while(1) //最终得到正确的月份 year_3
{
if((0 == year_3)&&(year_3 <= pmonth[0]))
{
year_4 = year_2;
break;
}
if((year_2 > pmonth[year_3 - 1])&&(year_2 <= pmonth[year_3] ))
{
year_4 = year_2 - pmonth[year_3 - 1];
break;
}
if(year_2 > pmonth[year_3])
{
year_3 ++;
continue;
} else
{
year_3 --;
}
}
tm->tm_mon = year_3 + 1; //没有0月
tm->tm_day = year_4 ; //没有0日
}
void from_tm(RTC_S* tm,INT32U* tim) //从tm中读取内容记录到tim中
{
INT8U leep_flag; //闰年标志位
INT16U day_temp = 0; //记录总共计时多少天
INT32U sec_temp = 0; //记录总共一天剩下的多少秒
leep_flag = quick_leep[tm->tm_year];
sec_temp = tm->tm_hour * 3600 +
tm->tm_min * 60 +
tm->tm_sec;
day_temp = tm->tm_day - 1; //没有0号
if( 0 == tm->tm_year) //累加年 级别的天数
{
day_temp += 0;
} else
{
day_temp += (year_sort[tm->tm_year - 1]);
}
if(1 == tm->tm_mon) //累加月 级别的天数
{
day_temp += 0;
} else if(leep_flag)
{
day_temp += month_leep[tm->tm_mon - 2];
} else
{
day_temp += month[tm->tm_mon - 2];
}
day_temp--; //减去第一天
*tim = day_temp * SECDAY + sec_temp; //耦合到一个32位数字中去
}
void tmprint(RTC_S* tm) //Windows编程环境拓展,用于检查
{
printf("year: %d\n",tm->tm_year + YEAR_START);
printf("mon: %d\n",tm->tm_mon);
printf("day: %d\n",tm->tm_day);
printf("week: %d\n",tm->tm_week);
printf("hour: %d\n",tm->tm_hour);
printf("min: %d\n",tm->tm_min);
printf("sec: %d\n",tm->tm_sec);
}
int main()
{
RTC_S tm1,tm2;
INT32U i,j,k;
tm1.tm_sec = 30;
tm1.tm_min = 30;
tm1.tm_hour = 10;
tm1.tm_day = 1;
tm1.tm_week = 4;
tm1.tm_mon = 2;
tm1.tm_year = 2080-YEAR_START;
quick_init();
tmprint(&tm1);
from_tm(&tm1,&i);
printf("%d\n",i);
printf("\n");
to_tm(i,&tm2);
tmprint(&tm2);
from_tm(&tm2,&j);
printf("%d\n",j);
// system("pause");
return 0;
}
程序运行后结果如下,运行一切正常
将代码进行了少量修改,经过测试,因为INT32U的影响,此次计数最多能够计数到130年左右。