[嵌入式开发模块]系统时间SYSTEMTIME 轻量实现
2017-08-02 23:30
295 查看
美丽的暑假被叫回来干活。要我改个3年前的嵌入式程序,马上项目要用。一看程序,亲娘滴,全部业务代码全部写在main.c文件中,大段大段的复制黏贴微改,任务间通信全用的轮询标志位╮(╯▽╰)╭。有强迫症的我用一周把整个程序重构了一遍,各模块分到不同的文件中,各种封装,同步的方式全改成异步。最后一算,扣掉操作系统的代码,代码量(CODE+DATA)减少了一半,这还是实现了许多原来没实现的功能后的,比原来更精简了操作系统的部分就不算它了。七天重构了个前人写了两个多月的程序,差点没把我累死。
因为之前做毕设的时候没时间好好封装系统时间模块,这次就顺带封装了一下,只实现了最基本的功能,一般的使用是够了。
由于嵌入式开发中没有提供系统时间,需要自己实现(不知道其他嵌入式操作系统有没有,反正uCOS是没有,它只是个内核),所以自己简单封装了个SYSTEMTIME模块。需要的自取。下面贴出代码:
目前版本只是最简单的实现,提供时间检查,系统时间递增,赋\取,而且递增还是必须1ms的,等以后有需要了再添加其他功能。
如嫌时间的结构体占的空间太大,其实可以把年以外的都改成INT8U。
要记得在适当的地方调用void Systemtime_Tick_Signal(void);以驱动系统时间模块。如在uC/OS-II中,可以把OSTick间隔设为1ms然后Hook在App_TimeTickHook()上(app_hook.c中),像这样修改:
当然,该使能的地方要记得使能。具体的就不细讲了。
使用提供的事件可以很方便的监听系统时间的变化,比如在这个项目中我需要每天重新初始化数据包编号,于是我就可以使能系统时间模块的SystemTime_onDayInc事件(SYSTEM_TIME_EVENT_ONDAYINC_EN设为TRUE)。在初始化时挂载事件:
然后在发生事件时的回调函数中初始化包编号:
然后调用接口获取及设置系统时间什么的都是C语言基本的东西,就不细讲了。
最后,既然读者有需要这个函数,那也有可能需要这个小工具。
【小工具】日期与一年中第几天的转换程序
OK就到这里吧,以后再慢慢改进。
更改历史:
2018/03/29 更新到v1.2
因为之前做毕设的时候没时间好好封装系统时间模块,这次就顺带封装了一下,只实现了最基本的功能,一般的使用是够了。
由于嵌入式开发中没有提供系统时间,需要自己实现(不知道其他嵌入式操作系统有没有,反正uCOS是没有,它只是个内核),所以自己简单封装了个SYSTEMTIME模块。需要的自取。下面贴出代码:
/* ********************************************************************************************************* * * * Systemtime SUPPORT PACKAGE * uCos-II * uCos-II系统时间支持包 * * File : time_uCos.h * By : Lin Shijun * Date : 2018/03/29 * Version: V1.2 * Note : 1. If you think struct system_time too big, you can modify all field,except for mYear and mMSecond, * to INT8U. * 2. you should call Systemtime_Tick_Signal() every 1ms in your app or operate system. * for example,make your OS tick once per ms and modify your app_hooks.c file: * * …… * #include "time_uCos.h" * …… * void App_TimeTickHook (void) * { * #if OS_CRITICAL_METHOD == 3 * OS_CPU_SR cpu_sr = 0; * #endif * …… * OS_ENTER_CRITICAL(); * Systemtime_Tick_Signal(); * OS_EXIT_CRITICAL(); * } * …… * * 3. this version is for banked memory model.If your are using other memory model, * some modification may need. * * History: 2017/05/04 v1.0 the original version of the systemtime module. * 2017/10/16 v1.1 modify some pragma statement to gain more efficiency. * 2018/03/29 v1.2 some modification to #pragma ********************************************************************************************************* */ #ifndef TIME_UCOS_H #define TIME_UCOS_H /* ********************************************************************************************************* * INCLUDES ********************************************************************************************************* */ #include <os_cpu.h> //typedef unsigned short INT16U ; //typedef unsigned char INT8U ; //typedef unsigned char BOOLEAN ; /* ********************************************************************************************************* * CONFIGURE ********************************************************************************************************* */ // 启动时初始化的时间设定 #define SYSTEM_DEFAULT_YEAR 2018 #define SYSTEM_DEFAULT_MONTH 4 #define SYSTEM_DEFAULT_DAY 1 #define SYSTEM_DEFAULT_HOUR 0 #define SYSTEM_DEFAULT_MINUTE 0 #define SYSTEM_DEFAULT_SECOND 0 #define SYSTEM_DEFAULT_MSECOND 0 // 是否使用对应事件 #define SYSTEM_EVENT_ONMSECONDINC_EN FALSE #define SYSTEM_EVENT_ONSECONDINC_EN FALSE #define SYSTEM_EVENT_ONMINUTEINC_EN FALSE #define SYSTEM_EVENT_ONHOURINC_EN FALSE #define SYSTEM_EVENT_ONDAYINC_EN TRUE #define SYSTEM_EVENT_ONMONTHINC_EN FALSE #define SYSTEM_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 函数原型 ********************************************************************************************************* */ /********* 注意: 以下函数都不需考虑任务冲突之类的事情 **********/ #pragma push #pragma CODE_SEG __NEAR_SEG NON_BANKED // 获取当前系统时间,用输入参数返回 void SystemTime_get(SYSTEM_TIME *rst); #pragma pop // 设置当前系统时间,如设置失败(一般是因为日期无效),则返回FALSE,如成功则返回TRUE BOOLEAN SystemTime_set(const SYSTEM_TIME *val); // 验证时间是否有效,有效则返回TRUE BOOLEAN SystemTime_Valid(const SYSTEM_TIME *val); // 赋值为NULL; void SystemTimeSetNull(SYSTEM_TIME *lval); // 计算某年是否是闰年 #define isLeapYear(Year) (Year % 4 == 0 && Year % 100 != 0 || Year % 400 == 0) /* ********************************************************************************************************* * EVENT 事件 ********************************************************************************************************* */ // 要注意,各事件都是由调用Systemtime_Tick_Signal()的函数内调用的,一般是中断服务程序中 // 事件中的传入参数为本地系统时间,只读 // 用法:声明个SYSTEM_TIME_EVENT类型的函数,然后赋值给对应事件 extern 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 函数原型 ********************************************************************************************************* */ // 对外接口,需要被外部定时调用来 ffc3 通知系统时间增加1ms // 调用时要保证执行过程中不会发生中断(比如禁止中断嵌套并在中断中调用) #pragma push #pragma CODE_SEG __NEAR_SEG NON_BANKED void Systemtime_Tick_Signal(void); #pragma pop /* ********************************************************************************************************* * ERROR CHECK 错误检查 ********************************************************************************************************* */ #if (SYSTEM_DEFAULT_YEAR < 0) #error "year must bigger than 0!" #endif #if (SYSTEM_DEFAULT_MONTH <= 0 || SYSTEM_DEFAULT_MONTH >= 13) #error "month must between 1 and 12!" #endif #if (SYSTEM_DEFAULT_DAY <= 0 || SYSTEM_DEFAULT_DAY >= 32) #error "day must between 1 and 31!" #endif #if (SYSTEM_DEFAULT_HOUR < 0 || SYSTEM_DEFAULT_HOUR >= 24) #error "hour must between 0 and 23!" #endif #if (SYSTEM_DEFAULT_MINUTE < 0 || SYSTEM_DEFAULT_MINUTE >= 60) #error "minute must between 0 and 59!" #endif #if (SYSTEM_DEFAULT_SECOND < 0 || SYSTEM_DEFAULT_SECOND >= 60) #error "second must between 0 and 59!" #endif #if (SYSTEM_DEFAULT_MSECOND < 0 || SYSTEM_DEFAULT_MSECOND >= 1000) #error "millsecond must between 0 and 999!" #endif #endif
/* ********************************************************************************************************* * * * Systemtime SUPPORT PACKAGE * uCos-II * uCos-II系统时间支持包 * * File : time_uCos.c * By : Lin Shijun * Date : 2018/03/29 * Version: V1.2 * Note : 1. If you think struct system_time too big, you can modify all field,except for mYear and mMSecond, * to INT8U. * 2. you should call Systemtime_Tick_Signal() every 1ms in your app or operate system. * for example,make your OS tick once per ms and modify your app_hooks.c file: * * …… * #include "time_uCos.h" * …… * void App_TimeTickHook (void) * { * #if OS_CRITICAL_METHOD == 3 * OS_CPU_SR cpu_sr = 0; * #endif * …… * OS_ENTER_CRITICAL(); * Systemtime_Tick_Signal(); * OS_EXIT_CRITICAL(); * } * …… * * 3. this version is for banked memory model.If your are using other memory model, * some modification may need. * * History: 2017/05/04 v1.0 the original version of the systemtime module. * 2017/10/16 v1.1 modify some pragma statement to gain more efficiency. * 2018/03/29 v1.2 some modification to #pragma ********************************************************************************************************* */ /* ********************************************************************************************************* * INCLUDES ********************************************************************************************************* */ #include <stddef.h> #include <string.h> #include "time_uCos.h" /* ********************************************************************************************************* * EVENT VARIABLE ********************************************************************************************************* */ #if (SYSTEM_EVENT_ONMSECONDINC_EN == TRUE) SYSTEM_TIME_EVENT SystemTime_onMSecondInc = NULL; #endif #if (SYSTEM_EVENT_ONSECONDINC_EN == TRUE) SYSTEM_TIME_EVENT SystemTime_onSecondInc = NULL; #endif #if (SYSTEM_EVENT_ONMINUTEINC_EN == TRUE) SYSTEM_TIME_EVENT SystemTime_onMinuteInc = NULL; #endif #if (SYSTEM_EVENT_ONHOURINC_EN == TRUE) SYSTEM_TIME_EVENT SystemTime_onHourInc = NULL; #endif #if (SYSTEM_EVENT_ONDAYINC_EN == TRUE) SYSTEM_TIME_EVENT SystemTime_onDayInc = NULL; #endif #if (SYSTEM_EVENT_ONMONTHINC_EN == TRUE) SYSTEM_TIME_EVENT SystemTime_onMonthInc = NULL; #endif #if (SYSTEM_EVENT_ONYEARINC_EN == TRUE) SYSTEM_TIME_EVENT SystemTime_onYearInc = NULL; #endif /* ********************************************************************************************************* * LOCAL FUNCTION PROTOTYPE ********************************************************************************************************* */ // 内部使用,对本地系统时间各种单位的自增运算 #pragma push #pragma CODE_SEG __NEAR_SEG NON_BANKED static void _SystemTime_incMSecond(void); static void _SystemTime_incSecond(void); #pragma pop 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 ********************************************************************************************************* */ static 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 } }; static const SYSTEM_TIME time_Null = { 0,0,0,0,0,0,0 }; const SYSTEM_TIME* const TimeNull = &time_Null; /* ********************************************************************************************************* * LOCAL VARIABLE ********************************************************************************************************* */ // 当前MCU的系统时间 static SYSTEM_TIME LocalTime ={ SYSTEM_DEFAULT_YEAR, SYSTEM_DEFAULT_MONTH, SYSTEM_DEFAULT_DAY, SYSTEM_DEFAULT_HOUR, SYSTEM_DEFAULT_MINUTE, SYSTEM_DEFAULT_SECOND, SYSTEM_DEFAULT_MSECOND }; // 存储当前本地时间是否是闰年。用于加快计算,只在年份变更时重新计算 static INT8U leapYearNow = isLeapYear(SYSTEM_DEFAULT_YEAR); // 重新计算现在是否是闰年 #define ReCalculateLeap() leapYearNow = isLeapYear(LocalTime.wYear) /* ********************************************************************************************************* * PUBLIC FUNCTION ********************************************************************************************************* */ #pragma push #pragma CODE_SEG __NEAR_SEG NON_BANKED void 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; } #pragma pop 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 SystemTimeSetNull(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 push #pragma CODE_SEG __NEAR_SEG NON_BANKED void Systemtime_Tick_Signal(void) { _SystemTime_incMSecond(); } #pragma pop /* ********************************************************************************************************* * LOCAL FUNCTION ********************************************************************************************************* */ #pragma push #pragma CODE_SEG __NEAR_SEG NON_BANKED static void _SystemTime_incMSecond(void){ if(++LocalTime.wMSecond >= 1000){ LocalTime.wMSecond = 0; _SystemTime_incSecond(); } #if (SYSTEM_EVENT_ONMSECONDINC_EN == TRUE) if(SystemTime_onMSecondInc != NULL) SystemTime_onMSecondInc(&LocalTime); #endif } static void _SystemTime_incSecond(void){ if(++LocalTime.wSecond >= 60){ LocalTime.wSecond = 0; _SystemTime_incMinute(); } #if (SYSTEM_EVENT_ONSECONDINC_EN == TRUE) if(SystemTime_onSecondInc != NULL) SystemTime_onSecondInc(&LocalTime); #endif } #pragma pop static void _SystemTime_incMinute(void){ if(++LocalTime.wMinute >= 60){ LocalTime.wMinute = 0; _SystemTime_incHour(); } #if (SYSTEM_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_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_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_EVENT_ONMONTHINC_EN == TRUE) if(SystemTime_onMonthInc != NULL) SystemTime_onMonthInc(&LocalTime); #endif } static void _SystemTime_incYear(void){ ++LocalTime.wYear; // 重计算当前是否是闰年 ReCalculateLeap(); #if (SYSTEM_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 > 0 void 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就到这里吧,以后再慢慢改进。
更改历史:
2018/03/29 更新到v1.2
相关文章推荐
- 嵌入式linux驱动开发之给linux系统添加温度传感器模块
- [DSP开发]嵌入式系统中LCD驱动的实现原理
- ARM嵌入式系统开发之发送过程的实现
- 模块管理常规功能自定义系统的设计与实现(56--开源开发测试版发布 )
- 嵌入式系统开发之中断控制的实现
- [嵌入式开发模块]机械按钮模块 纯C语言 面向对象实现 按键消抖、长按、连击
- 二次开发Jumpserver,增加权限申请模块实现用户组归属,服务器及组授权,系统用户授权申请处理
- 嵌入式ARM处理器的通信模块实现-龙人嵌入式开发
- ARM嵌入式系统开发之接收函数的实现
- [嵌入式开发模块]环形缓冲区/循环队列 C语言实现
- ARM嵌入式系统开发之发送过程的实现
- 卫星任务规划系统时间窗口模块的设计与实现
- ARM嵌入式系统开发之发送过程的实现
- VB.NET 如何实现强制修改系统时间
- 基于ARM的嵌入式MPEG-4远程网络监控系统的设计与实现
- 用GNU工具开发基于ARM的嵌入式系统
- 嵌入式系统开发
- 用GNU工具开发基于ARM的嵌入式系统(zt)
- 嵌入式设备上的 Linux 系统开发
- 一个典型的嵌入式系统设计和实现