将32位无符号整数表示的时间信号转化为习惯的形式

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年左右。

转载于:https://my.oschina.net/mummy108/blog/115299

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值