【小工具】系统时间SYSTEMTIME 轻量实现

来源:互联网 发布:91手机助手mac版 编辑:程序博客网 时间:2024/05/29 18:03

美丽的暑假被叫回来干活。要我改个3年前的嵌入式程序,马上项目要用。一看程序,亲娘滴,全部业务代码全部写在main.c文件中,大段大段的复制黏贴微改,任务间通信全用的轮询标志位╮(╯▽╰)╭。有强迫症的我用一周把整个程序重构了一遍,各模块分到不同的文件中,各种封装,同步的方式全改成异步。最后一算,扣掉操作系统的代码,代码量(CODE+DATA)减少了一半,这还是实现了许多原来没实现的功能后的,比原来更精简了操作系统的部分就不算它了。七天重构了个前人写了两个多月的程序,差点没把我累死。

因为之前做毕设的时候没时间好好封装系统时间模块,这次就顺带封装了一下,只实现了最基本的功能,一般的使用是够了。


由于嵌入式开发中没有提供系统时间,需要自己实现(不知道其他嵌入式操作系统有没有,反正uCOS是没有,它只是个内核),所以自己简单封装了个SYSTEMTIME模块。需要的自取。下面贴出代码:

/*************************************************************************************************************                                     Systemtime SUPPORT PACKAGE*                                           系统时间支持包** File : SystemTime.h* By   : Lin Shijun* Date : 2017/07/20* version: 1.0.0 * NOTE : 1. 此系统时间需要由外部驱动运作,典型地,在每增加1ms时关闭中断并调用Systemtime_Tick_Signal()*             来通知 系统时间模块 增加一毫秒*        2. 可以通过挂载事件来在年/月/日……增加时进行对应操作,但要注意这个事件是由调用Systemtime_Tick_Signal()的*             地方驱动的,如是在中断中调用的Systemtime_Tick_Signal(),则别执行中断中不能进行的操作。**********************************************************************************************************/#ifndef SYSTEM_TIME_H#define SYSTEM_TIME_H/***********************************************************************************************************                                       INCLUDES**********************************************************************************************************/#include <os_cpu.h>/***********************************************************************************************************                                      CONFIGURE**********************************************************************************************************/// 启动时初始化的时间设定#define  SYSTEM_TIME_DEFAULT_YEAR     2017#define  SYSTEM_TIME_DEFAULT_MONTH    7#define  SYSTEM_TIME_DEFAULT_DAY      20#define  SYSTEM_TIME_DEFAULT_HOUR     23#define  SYSTEM_TIME_DEFAULT_MINUTE   59#define  SYSTEM_TIME_DEFAULT_SECOND   50#define  SYSTEM_TIME_DEFAULT_MSECOND  0// 是否使用对应事件#define  SYSTEM_TIME_EVENT_ONMSECONDINC_EN FALSE#define  SYSTEM_TIME_EVENT_ONSECONDINC_EN  FALSE   #define  SYSTEM_TIME_EVENT_ONMINUTEINC_EN  FALSE#define  SYSTEM_TIME_EVENT_ONHOURINC_EN    FALSE#define  SYSTEM_TIME_EVENT_ONDAYINC_EN     TRUE#define  SYSTEM_TIME_EVENT_ONMONTHINC_EN   FALSE#define  SYSTEM_TIME_EVENT_ONYEARINC_EN    FALSE/***********************************************************************************************************                                      DATATYPE 数据类型**********************************************************************************************************/typedef struct system_time{  INT16U wYear;            // 年  INT16U wMonth;           // 月  INT16U wDay;             // 日  INT16U wHour;            // 时  INT16U wMinute;          // 分  INT16U wSecond;          // 秒  INT16U wMSecond;         // 毫秒} SYSTEM_TIME;typedef void (* SYSTEM_TIME_EVENT)(const SYSTEM_TIME *time);/***********************************************************************************************************                                      CONSTANT**********************************************************************************************************/// 定义空时间,便于比较赋值extern const SYSTEM_TIME* const TimeNull;/***********************************************************************************************************                                  FUNCTION PROTOTYPES  函数原型**********************************************************************************************************//********* 注意: 以下函数都不需考虑任务冲突之类的事情 **********/// 获取当前系统时间,用输入参数返回void SystemTime_get(SYSTEM_TIME *rst);// 设置当前系统时间,如设置失败(一般是因为日期无效),则返回FALSE,如成功则返回TRUEBOOLEAN SystemTime_set(const SYSTEM_TIME *val);// 验证时间是否有效,有效则返回TRUEBOOLEAN SystemTime_Valid(const SYSTEM_TIME *val);// 赋值为NULL;void SystemTime_setNull(SYSTEM_TIME *lval);// 计算某年是否是闰年#define isLeapYear(Year) (Year % 4 == 0 && Year % 100 != 0 || Year % 400 == 0)/***********************************************************************************************************                                        EVENT 事件**********************************************************************************************************/// 要注意,各事件都是由调用Systemtime_Tick_Signal()的函数内调用的,一般是中断服务程序中// 事件中的传入参数为本地系统时间,只读// 用法:声明个SYSTEM_TIME_EVENT类型的函数,然后赋值给对应事件#pragma DATA_SEG DEFAULTextern SYSTEM_TIME_EVENT SystemTime_onMSecondInc;extern SYSTEM_TIME_EVENT SystemTime_onSecondInc;extern SYSTEM_TIME_EVENT SystemTime_onMinuteInc;extern SYSTEM_TIME_EVENT SystemTime_onHourInc;extern SYSTEM_TIME_EVENT SystemTime_onDayInc;extern SYSTEM_TIME_EVENT SystemTime_onMonthInc;extern SYSTEM_TIME_EVENT SystemTime_onYearInc;/***********************************************************************************************************                                  FUNCTION PROTOTYPES  函数原型**********************************************************************************************************/// 对外接口,需要被外部定时调用来通知系统时间增加1ms// 调用时要保证执行过程中不会发生中断(比如禁止中断嵌套并在中断中调用)void Systemtime_Tick_Signal(void);/***********************************************************************************************************                                     ERROR CHECK     错误检查**********************************************************************************************************/#if (SYSTEM_TIME_DEFAULT_YEAR < 0)   #error "year must bigger than 0!"#endif#if (SYSTEM_TIME_DEFAULT_MONTH <= 0 || SYSTEM_TIME_DEFAULT_MONTH >= 13)   #error "month must between 1 and 12!"#endif#if (SYSTEM_TIME_DEFAULT_DAY <= 0 || SYSTEM_TIME_DEFAULT_DAY >= 32)   #error "day must between 1 and 31!"#endif#if (SYSTEM_TIME_DEFAULT_HOUR < 0 || SYSTEM_TIME_DEFAULT_HOUR >= 24)   #error "hour must between 0 and 23!"#endif#if (SYSTEM_TIME_DEFAULT_MINUTE < 0 || SYSTEM_TIME_DEFAULT_MINUTE >= 60)   #error "minute must between 0 and 59!"#endif#if (SYSTEM_TIME_DEFAULT_SECOND < 0 || SYSTEM_TIME_DEFAULT_SECOND >= 60)   #error "second must between 0 and 59!"#endif#if (SYSTEM_TIME_DEFAULT_MSECOND < 0 || SYSTEM_TIME_DEFAULT_MSECOND >= 1000)   #error "millsecond must between 0 and 999!"#endif#endif
/*************************************************************************************************************                                    Systemtime SUPPORT PACKAGE*                                         系统时间支持包** File : SystemTime.c* By   : Lin Shijun* Date : 2017/07/20* version: 1.0.0**********************************************************************************************************//***********************************************************************************************************                                       INCLUDES**********************************************************************************************************/#include <stddef.h>#include "SystemTime.h"/***********************************************************************************************************                                      EVENT VARIABLE**********************************************************************************************************/#pragma DATA_SEG DEFAULT#if (SYSTEM_TIME_EVENT_ONMSECONDINC_EN == TRUE)   SYSTEM_TIME_EVENT SystemTime_onMSecondInc = NULL;#endif #if (SYSTEM_TIME_EVENT_ONSECONDINC_EN == TRUE)   SYSTEM_TIME_EVENT SystemTime_onSecondInc = NULL;#endif #if (SYSTEM_TIME_EVENT_ONMINUTEINC_EN == TRUE)   SYSTEM_TIME_EVENT SystemTime_onMinuteInc = NULL;#endif#if (SYSTEM_TIME_EVENT_ONHOURINC_EN   == TRUE)   SYSTEM_TIME_EVENT SystemTime_onHourInc   = NULL;#endif#if (SYSTEM_TIME_EVENT_ONDAYINC_EN    == TRUE)   SYSTEM_TIME_EVENT SystemTime_onDayInc    = NULL;#endif#if (SYSTEM_TIME_EVENT_ONMONTHINC_EN  == TRUE)   SYSTEM_TIME_EVENT SystemTime_onMonthInc  = NULL;#endif#if (SYSTEM_TIME_EVENT_ONYEARINC_EN   == TRUE)   SYSTEM_TIME_EVENT SystemTime_onYearInc   = NULL;#endif /***********************************************************************************************************                                   LOCAL FUNCTION PROTOTYPE**********************************************************************************************************/// 内部使用,对本地系统时间各种单位的自增运算static void _SystemTime_incMSecond(void);static void _SystemTime_incSecond(void);static void _SystemTime_incMinute(void);static void _SystemTime_incHour(void);static void _SystemTime_incDay(void);static void _SystemTime_incMonth(void);static void _SystemTime_incYear(void);/***********************************************************************************************************                                      LOCAL CONST**********************************************************************************************************/#pragma CONST_SEG DEFAULTstatic const INT8U daytab[2][13] = {    { 0,31,28,31,30,31,30,31,31,30,31,30,31 },    { 0,31,29,31,30,31,30,31,31,30,31,30,31 }};#pragma CONST_SEG DEFAULTstatic const SYSTEM_TIME time_Null = {     0,0,0,0,0,0,0};#pragma CONST_SEG DEFAULTconst SYSTEM_TIME* const TimeNull = &time_Null;/***********************************************************************************************************                                      LOCAL VARIABLE**********************************************************************************************************///#pragma DATA_SEG __NEAR_SEG DEFAULT#pragma DATA_SEG DEFAULT// 当前MCU的系统时间static SYSTEM_TIME LocalTime ={   SYSTEM_TIME_DEFAULT_YEAR,   SYSTEM_TIME_DEFAULT_MONTH,   SYSTEM_TIME_DEFAULT_DAY,   SYSTEM_TIME_DEFAULT_HOUR,   SYSTEM_TIME_DEFAULT_MINUTE,   SYSTEM_TIME_DEFAULT_SECOND,   SYSTEM_TIME_DEFAULT_MSECOND};#pragma DATA_SEG DEFAULT// 存储当前本地时间是否是闰年。用于加快计算,只在年份变更时重新计算static INT8U leapYearNow = isLeapYear(SYSTEM_TIME_DEFAULT_YEAR);// 重新计算现在是否是闰年#define ReCalculateLeap()     leapYearNow = isLeapYear(LocalTime.wYear)/***********************************************************************************************************                                     PUBLIC  FUNCTION**********************************************************************************************************/#pragma CODE_SEG DEFAULTvoid SystemTime_get(SYSTEM_TIME *rst){  #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */    OS_CPU_SR  cpu_sr = 0;  #endif    OS_ENTER_CRITICAL();    *rst = LocalTime;    OS_EXIT_CRITICAL();    return;}BOOLEAN SystemTime_set(const SYSTEM_TIME *val){  #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */    OS_CPU_SR  cpu_sr = 0;  #endif  if(SystemTime_Valid(val)){    OS_ENTER_CRITICAL();    LocalTime = *val;    OS_EXIT_CRITICAL();    return TRUE;  }  return FALSE;}BOOLEAN SystemTime_Valid(const SYSTEM_TIME *val){    INT8U leap;    if(val->wHour >= 24 || val->wMinute >= 60 || val->wSecond >= 60 || val->wMSecond >= 1000 ||          val->wMonth >= 13 || val->wMonth == 0 || val->wDay == 0)       return FALSE;    leap = isLeapYear(val->wYear);    if(val->wDay > daytab[leap][val->wMonth])       return FALSE;    return TRUE;}void SystemTime_setNull(SYSTEM_TIME *lval){   memcpy(lval,TimeNull,sizeof(SYSTEM_TIME));}/**************************************************************************************************************************                                      SIGNAL THAT IT'S TIME TO UPDATE THE SYSTEMTIME** Description: This function is typically called by the ISR that occurs at the timer tick rate and is used to signal*              the systemtime module to update.** Arguments  : none** Returns    : *************************************************************************************************************************/#pragma CODE_SEG __NEAR_SEG DEFAULTvoid Systemtime_Tick_Signal(void){    _SystemTime_incMSecond();}/***********************************************************************************************************                                      LOCAL FUNCTION**********************************************************************************************************/#pragma CODE_SEG __NEAR_SEG DEFAULTstatic void _SystemTime_incMSecond(void){    if(++LocalTime.wMSecond >= 1000){       LocalTime.wMSecond = 0;       _SystemTime_incSecond();    }    #if (SYSTEM_TIME_EVENT_ONMSECONDINC_EN == TRUE)       if(SystemTime_onMSecondInc != NULL)          SystemTime_onMSecondInc(&LocalTime);    #endif }#pragma CODE_SEG __NEAR_SEG DEFAULTstatic void _SystemTime_incSecond(void){    if(++LocalTime.wSecond >= 60){        LocalTime.wSecond = 0;        _SystemTime_incMinute();    }    #if (SYSTEM_TIME_EVENT_ONSECONDINC_EN == TRUE)       if(SystemTime_onSecondInc != NULL)          SystemTime_onSecondInc(&LocalTime);    #endif}#pragma CODE_SEG DEFAULTstatic void _SystemTime_incMinute(void){    if(++LocalTime.wMinute >= 60){       LocalTime.wMinute = 0;       _SystemTime_incHour();    }    #if (SYSTEM_TIME_EVENT_ONMINUTEINC_EN == TRUE)       if(SystemTime_onMinuteInc != NULL)          SystemTime_onMinuteInc(&LocalTime);    #endif }static void _SystemTime_incHour(void){    if(++LocalTime.wHour >= 24){       LocalTime.wHour = 0;       _SystemTime_incDay();    }    #if (SYSTEM_TIME_EVENT_ONHOURINC_EN == TRUE)       if(SystemTime_onHourInc != NULL)          SystemTime_onHourInc(&LocalTime);    #endif }static void _SystemTime_incDay(void){    if(++LocalTime.wDay > daytab[leapYearNow][LocalTime.wMonth]){        LocalTime.wDay = 1;        _SystemTime_incMonth();    }    #if (SYSTEM_TIME_EVENT_ONDAYINC_EN == TRUE)       if(SystemTime_onDayInc != NULL)          SystemTime_onDayInc(&LocalTime);    #endif}static void _SystemTime_incMonth(void){    if(++LocalTime.wMonth > 12){        LocalTime.wMonth = 1;        _SystemTime_incYear();     }    #if (SYSTEM_TIME_EVENT_ONMONTHINC_EN == TRUE)       if(SystemTime_onMonthInc != NULL)          SystemTime_onMonthInc(&LocalTime);    #endif}static void _SystemTime_incYear(void){    ++LocalTime.wYear;     // 重计算当前是否是闰年    ReCalculateLeap();    #if (SYSTEM_TIME_EVENT_ONYEARINC_EN == TRUE)       if(SystemTime_onYearInc != NULL)          SystemTime_onYearInc(&LocalTime);    #endif}

目前版本只是最简单的实现,提供时间检查,系统时间递增,赋\取,而且递增还是必须1ms的,等以后有需要了再添加其他功能。

如嫌时间的结构体占的空间太大,其实可以把年以外的都改成INT8U。

要记得在适当的地方调用void Systemtime_Tick_Signal(void);以驱动系统时间模块。如在uC/OS-II中,可以把OSTick间隔设为1ms然后Hook在App_TimeTickHook()上(app_hook.c中),像这样修改:

#if OS_TIME_TICK_HOOK_EN > 0void  App_TimeTickHook (void){  #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */    OS_CPU_SR  cpu_sr = 0;  #endif#if (uC_PROBE_OS_PLUGIN > 0) && (OS_PROBE_HOOKS_EN > 0)    OSProbe_TickHook();#endif    OS_ENTER_CRITICAL();    // 通知系统时间模块,当前时间+1ms    Systemtime_Tick_Signal();    OS_EXIT_CRITICAL();}

当然,该使能的地方要记得使能。具体的就不细讲了。

使用提供的事件可以很方便的监听系统时间的变化,比如在这个项目中我需要每天重新初始化数据包编号,于是我就可以使能系统时间模块的SystemTime_onDayInc事件(SYSTEM_TIME_EVENT_ONDAYINC_EN设为TRUE)。在初始化时挂载事件:

     // 挂载天数增加事件     SystemTime_onDayInc = &onDayInc;

然后在发生事件时的回调函数中初始化包编号:

static void onDayInc(const SYSTEM_TIME *time){   PacketNum = 0;}

然后调用接口获取及设置系统时间什么的都是C语言基本的东西,就不细讲了。

最后,既然读者有需要这个函数,那也有可能需要这个小工具。
【小工具】日期与一年中第几天的转换程序

OK就到这里吧,以后再慢慢改进。