打印

软件无累积误差的定时中断程序模板,供初学者学习和行家

[复制链接]
楼主: xwj
手机看帖
扫描二维码
随时随地手机跟帖
21
aolin| | 2007-7-27 08:53 | 只看该作者 回帖奖励 |倒序浏览

昨晚做了实验,结果下我一跳!

13小时差了7分钟!
正在找原因中........................

使用特权

评论回复
22
xwj|  楼主 | 2007-7-27 09:23 | 只看该作者

LS,用频率计核对你的晶振频率!

要注意测量方法哦,不要带来测量误差

使用特权

评论回复
23
农民讲习所| | 2007-7-27 09:38 | 只看该作者

累计误差及思维转变

fsaok说的很清楚明白了,软件补偿一定存在着累及误差。
而且可以用这句话表达软件补偿这种做法:"脱了xx放x",非常低级无聊的做法和思维。


思维转变就是说一定非要5MS?如果非要5MS,不会去选择正确的晶振吗?

俺的培训教材中已经有这方面的处理:标准的22.1184M,产生无偏差的5MS。

使用特权

评论回复
24
农民讲习所| | 2007-7-27 09:40 | 只看该作者

再贴一遍,俺估计很多人没那个水平看懂,不理解。

//-----------------------------------------------------------
//系统时间管理
//T0产生系统时间20ms
//T0中断5ms,处理弱实时任务。20ms主要提供按键扫描,5ms主要提供给数码LED、协议解析用。
//-----------------------------------------------------------
#define _SysTimerH

#include <reg52.h>
#include "Memory.h"
#include "SysTimer.h"

bit fInSys_20ms;                        //从中断产生的标志转为主循环系统使用的20MS标志需要

//内部使用的变量
struct InSysTimer{
    unsigned char mT0_PreLoad;            //T0在模式0的13位模式下的高位初装值,用来产生系统时间用
    unsigned char mFlashOff_Count;        //闪烁灭的时间计数器
    unsigned char mFlashOn_Count;        //闪烁亮的时间计数器
    unsigned char mFlash_Count;            //闪烁计数

    unsigned char m20msCount;            //从5MS产生20MS需要的计数器

    void ( *Weekness_20ms )();            //20ms弱实时任务函数数组指针
    void ( *Weekness_5ms )();            //5ms弱实时任务函数数组指针
};
struct InSysTimer sInSysTimer;

//-------------------------------------------------------------------------
//系统时间初始化
//T0工作在16位的模式1下
//入口:产生20MS需要的T0高位预装值
//-------------------------------------------------------------------------
void SysTimer_Init( unsigned char mPreLoad, unsigned char mFlashOnCount, unsigned char mFlashOffCount )
{
    //变量清0
    Memory_Memset( (unsigned char *)&sInSysTimer, 0, sizeof(struct InSysTimer) );

    sInSysTimer.mT0_PreLoad = (~mPreLoad) + 1;        //T0高位预装值
    sInSysTimer.mFlashOn_Count = mFlashOnCount;
    sInSysTimer.mFlash_Count = sInSysTimer.mFlashOff_Count = mFlashOffCount;

    TMOD |= 0x1;                        //T0.M0 = 1;    
    TH0 = sInSysTimer.mT0_PreLoad;
    ET0 = 1;
    TR0 = 1;                            //T0开始运行
}

//-------------------------------------------------------------------------
//析构
//-------------------------------------------------------------------------
void SysTimer_Destory(void)
{
    TR0 = 0;
    ET0 = 0;
    TMOD &= ~0x1;                        //释放硬件资源
}

//-------------------------------------------------------------------------
//注册弱实时任务处理函数
//-------------------------------------------------------------------------
void SysTimer_WeeknessRegister( void(*Function_20ms)(), void(*Function_5ms)() )
{
    sInSysTimer.Weekness_20ms = Function_20ms;
    sInSysTimer.Weekness_5ms = Function_5ms;
}


//-------------------------------------------------------------------------
//循环
//-------------------------------------------------------------------------
void SysTimer_Loop(void)
{
    if( fInSys_20ms ){
        fInSys_20ms = 0;                //中断中产生的20MS,不能直接在主循环中使用,必须转换

        fSysTimer_Touch = 1;            //系统时间到达
    
        //闪烁时间控制
        if( fSysTimer_FlashState ){
            //处于闪烁亮
            if( --sInSysTimer.mFlash_Count == 0 ){
                //进入闪烁灭的状态
                sInSysTimer.mFlash_Count = sInSysTimer.mFlashOff_Count;
                fSysTimer_FlashState = 0;
                fSysTimer_FlashTouch = 1;
            }
        }
        else {
            //处于闪烁灭
            if( --sInSysTimer.mFlash_Count == 0 ){
                //进入闪烁亮的状态
                sInSysTimer.mFlash_Count = sInSysTimer.mFlashOn_Count;
                fSysTimer_FlashState = 1;
                fSysTimer_FlashTouch = 1;
            }
        }
    }
}


//-------------------------------------------------------------------------
//T0中断
//处理弱实时任务,并产生20MS系统时间
//-------------------------------------------------------------------------
void Timer0(void) interrupt 1 using 1
{
    TH0 = sInSysTimer.mT0_PreLoad;        //重装T0高位初始值

    if( ++sInSysTimer.m20msCount > 3 ){
        sInSysTimer.m20msCount = 0;
        //20ms触发
        fInSys_20ms = 1;
        //调用20ms中断要处理的弱实时任务
        if( sInSysTimer.Weekness_20ms )(*sInSysTimer.Weekness_20ms)();
    }

    //调用5ms中断要处理的弱实时任务。
    if( sInSysTimer.Weekness_5ms )(*sInSysTimer.Weekness_5ms)();
}

使用特权

评论回复
25
xwj|  楼主 | 2007-7-27 10:09 | 只看该作者

切,只要是12*256的整数倍,都能让重载值低8位为0,这谁不知道啊

唉,LS由何必跳出来"脱了xx放x"呢?

没看到别人的要求就是非要"只用标准51和12MHz的晶体"吗?

使用特权

评论回复
26
农民讲习所| | 2007-7-27 10:18 | 只看该作者

别人不懂,难道你要跟着他思维?

本来就应该选择11.0592m倍数,不能选择12M,这是设计产品必须的思维。思维转变就是换不同角度思考。

使用特权

评论回复
27
农民讲习所| | 2007-7-27 10:23 | 只看该作者

再说既然想精确,还可以换T2的自动装载功能.

使用特权

评论回复
28
aolin| | 2007-7-27 10:50 | 只看该作者

我还没有用你的方法去实验

我先用我自己的方法去实验,原来搞错了一个运算符号,本来应该是用">"的,结果用成了">=",少了一次计数,所以快了!

所长的方法在实时性较低的系统里(即外部触发事件较少)还可以,但如果定时器中断响应时间超过256计数时(大概128us),就出错了!

使用特权

评论回复
29
hqgboy| | 2007-7-27 10:52 | 只看该作者

有争论了....

使用特权

评论回复
30
农民讲习所| | 2007-7-27 11:08 | 只看该作者

可以再改进为只加载高N位

俺这个系统中,该时间是允许丢失,只要保证总体差不多就行。当然,在小实时要求场合可以保证非常精确,比如仅仅电子钟。

使用特权

评论回复
31
xwj|  楼主 | 2007-7-27 11:25 | 只看该作者

aolin,如果你的中断256周期还得不到运行,那就得考虑你的程序.

是否有问题了





此贴本为抛砖引玉,能真正做到无软件误差得方法还是很多的,各有各的优缺点和局限性,要系统的考虑才行。


论坛讨论有争论是在所难免的,也要有争论才会进步,

但也请各位注意说话的口气哦,乱放废气污染空气就不对了,那样也就太没意思了。。。



使用特权

评论回复
32
cbbs| | 2007-7-27 12:46 | 只看该作者

下面是一本资料书上的2051计时实例

大家看一下中断重装TL0和TH0部分的程序。晶振12MHz.


;******************
        ;    倒计时程序   ;
        ;******************

            PGT0:   CLR   EA                     ;关中断

                    PUSH  ACC                       ;保护现场

            PUSH  PSW
            PUSH  DPL
            PUSH  DPH
            MOV   PSW#08H               ;选用寄存器组1

            CLR   TR0                     ;暂停计时

            MOV   A,#0B7H                ;中断同步修正

            ADD   A,TL0
            MOV   TL0,A
            MOV   A,#3CH
            ADD   A,TH0
            MOV   TH0,A
                    SETB  TR0                     ;恢复计时

                    DEC   TCOUNT                  ;定时器T0每50 000毫秒溢出一次,则

            MOV   A,  TCOUNT              ; 溢出10次为0.5秒

                JNZ   OUTT0                   ;判断是否到半秒

            MOV   TCOUNT, #0AH            ;

            CPL   LED4                        ; 若到半秒LED取反

            JNB   LED4, OUTT0         ;LED每闪烁一次是一秒

            MOV   R0#SH             ;移入秒位的地址

            SETB  IFDEC                ;BCD子程序参数,使其做减法

            ACALL ADDBCD            ;调用BCD子程序, 秒减1

            CJNE  R3#99H, OUTT0      ;判断秒要否借位

                    MOV   SH, #05H            ;要借位则

                    MOV   SL, #09H            ; 送数据59(否则显示99)

            MOV   R0#MH             ;移入分位的地址

            ACALL ADDBCD               ;分减1

            CJNE  R3#99H, OUTT0     ;判断分要否借位

                    MOV   MH, #05H
                    MOV   ML, #09H
            MOV   R0#HH
            ACALL ADDBCD
            OUTT0:  POP   DPH                       ;恢复现场

            POP   DPL
            POP   PSW
            POP   ACC
            SETB  EA
            RETI                          ;中断返回

                    NOP
            NOP
                    LJMP
 ERR                    ;软件陷阱
    ;

使用特权

评论回复
33
aolin| | 2007-7-27 13:07 | 只看该作者

复杂系统中128us不响应定时器中断很正常!

再一个组合音响系统中,那么多外部中断,遥控器,串口通讯,RDS中断等,随时都会有可能触发,有时候128us过后还不能响应定时器中断一点不奇怪啦!

使用特权

评论回复
34
xwj|  楼主 | 2007-7-27 13:49 | 只看该作者

cbbs 贴的程序问题多多啊


            CLR   TR0                     ;暂停计时
            MOV   A,#0B7H                ;中断同步修正,已修正了丢失的7个周期
            ADD   A,TL0
            MOV   TL0,A
            MOV   A,#3CH
            ADD   A,TH0                     ;这里应该用ADDC,把ADD   A,TL0可能的溢出加近来,
                                                         否则,当中断有所延时TL0>0x49时就错了
            MOV   TH0,A
            SETB  TR0                     ;恢复计时

 
这几句:
            DEC   TCOUNT                  ;定时器T0每50 000毫秒溢出一次,则
            MOV   A,  TCOUNT              ; 溢出10次为0.5秒
            JNZ   OUTT0                   ;判断是否到半秒

为什么不直接用
            DJNZ   TCOUNT,  OUTT0              ; 溢出10次为0.5秒
 
而且,用BCD减法感觉很不合理,还不如二进制计算好后再砖BCD送显示缓存

使用特权

评论回复
35
cbbs| | 2007-7-27 17:24 | 只看该作者

楼上厉害。

上面这个程序我只是简单的复制出来的。出处是楼然苗、李光飞《51系列单片机设计实例》附带的光盘(实例13《电子定时器的设计》).

但是如果定时器0设为高优先级,其余为低优先级。或只有定时器一个中断。那ADD   A,TL0
发生进位的情况倒也不会发生。

使用特权

评论回复
36
huangqi412| | 2007-7-27 18:34 | 只看该作者

学习了。

使用特权

评论回复
37
datouyuan| | 2007-7-28 01:37 | 只看该作者

我记不清在哪里看的,我在实际中用过,很准确。

我记不清在哪里看的,我在实际中用过,只要很准确。

#define FOSC        3686400
#define MACHINE_NUM 12
#define SYSTEM_TICKS_PER_SEC    50    
#define TIMER0_COUNT (-FOSC/SYSTEM_TICKS_PER_SEC/MACHINE_NUM)
//调整FOSC、SYSTEM_TICKS_PER_SEC使TIMER0_COUNT正好为整数

void SystemTickService(void) interrupt 3
{
    unsigned int abc;

    bSystemTick=1;//处理移到中断外执行,处理后 bSystemTick=0
    //要处理的内容    

    TR0 = 0;
    abc=TIMER0_COUNT+15+(TL0|(TH0<<8));//15 这个值最好在编译后再确定
    TL0=(unsigned char)abc;
    TH0=(unsigned char)(abc>>8);
    TR0 = 1;
}

使用特权

评论回复
38
ayb_ice| | 2007-7-28 07:33 | 只看该作者

我用12M做过RTC,一天误差在1秒以内...

我还没有进行软件校正...

使用特权

评论回复
39
fsaok| | 2007-7-28 09:06 | 只看该作者

.

xwj 的整个过程还是花了不少功夫 
不过,xwj 还是没有明白 

第一,停钟完全没有必要, 

第二,晶振也不需要刻意去选择11.0592(好像最早是howpower提倡的) 或者是12M, 

但 TL0 = t0buf%256; 这种写法软件积累误差的最大来源,不信,你自己在这句设断点,用keil仿真看看,看看每次停在这里的时钟是多少就清楚了. 

所以,应该改为 TL0 += CONL; 这个CONL 是多少可以自己灵活设定,和晶振有关, 不过还要注意,别这个时候进入其他中断程序

空谈是没有用的,上机试一下吧,

使用特权

评论回复
40
古道热肠| | 2007-7-28 09:11 | 只看该作者

我也贴一个,软实时时钟谁都玩过

  误差不算大,有误差修正参数就行了。

//@@***********************************************************
//-------------------------------------------------------------
//
// 文件名   :Calender.c
// 描述     :日历时钟模块,用于不带时钟芯片的系统
// 语言     :C
// 作者     :Jean J. Labrosse
// 修改     :李艳平  
// 日期     :2002-05-17
// 说明     :原来的程序用于UCII_RTOS中,现移植C51中
//@@***********************************************************

//备注:
//盛唐电子公司移植到EPS112仿真编程器,用于显示测试与数码管试验。
//完成日期:07-04-12
//联系方式:Xg_2004_sy@126.com  (025)51615878 13057504110

#define   SYS_CLOCK_EN  1

#if       SYS_CLOCK_EN

#include  "Caltypedef.h"
//#include  "string.h"
//#include  "stdlib.h"
//#include  "Stdio.h"
#include "..\inc\includes.h"

//#include "DriverComm.h"
//#include "HardResource.h"
//#define   FOSC                    22118400L
//#define   FOSC                    11059200L
#define   FOSC                    18432000L

#define   MACHINE_NUM             24          /*根据需要调整,如:W777E58=4*/
#define   TICKS_PER_SEC           80            /* # of clock ticks to obtain 1 second               */
//#define   TICKS_PER_SEC           10            //Only for Test

//#define   CLK_DATE_EN             1             /* Enable DATE (when 1)                               */  

#define   ENTER_CRITICAL()        EA=1
#define   EXIT_CRITICAL()         EA=0                         


static UCHAR   ClkTickCtr;           /* Counter used to keep track of system clock ticks             */

static UCHAR   ClkHr;
static UCHAR   ClkMin;
static UCHAR   ClkSec;               /* Counters for local TIME 
                                     */
/**********************************************************************************************************
*                                          FUNCTION PROTOTYPES
**********************************************************************************************************/       
static  BOOL       ClkUpdateTime(void);

static  BOOL       ClkIsLeapYear(UINT year);
static  void       ClkUpdateDate(void);
static  void       ClkUpdateDOW(void);
#endif

void   Init_sys_timer(void);
void   Sys_clk_init(void); 
void   Sys_clk_task(void);

void   Clk_format_time(UCHAR mode, char *s);
void   Clk_set_time(UCHAR hr, UCHAR min, UCHAR sec);
int    Cmp_now_time(UCHAR hr, UCHAR min, UCHAR sec);

/*********************************************************************************************************/
void Set_LEDFlashDot_On(void);
void Set_LEDFlashDot_Off(void);


/*
*********************************************************************************************************
*                                        TIME-OF-DAY CLOCK TASK
*
* Description : This task is created by Sys_clk_init() and is responsible for updating the time and date.
*               Sys_clk_task() executes every second.
* Arguments   : None.
* Returns     : None.
* Notes       : CLK_DLY_TICKS must be set to produce 1 second delays.
*********************************************************************************************************
*/
extern uchar ucDispTemperatureCount;
extern bool bDispTemperatureSwitch;
#define c_DispTemperatureIntervalMinute 10  //显示温度的间隔时间(以分钏钟为单位)
//功能:时钟中断任务
static void  Sys_clk_task (void)
{
    static bool bFlashFlag;    

    if(++ClkTickCtr==TICKS_PER_SEC)   
       {
         ClkTickCtr=0;
                               
           if (ClkUpdateTime() == TRUE)
        {
         }

         if(bFlashFlag)
         {
              Set_LEDFlashDot_On();
         }
         else
         {
              Set_LEDFlashDot_Off();
         }
        
        bFlashFlag = !bFlashFlag;

        if(ucDispTemperatureCount > 0)
        {
            ucDispTemperatureCount--;
          }

    
    }   
}  

uchar ucFlagEnableClock;    //全局变量是否开启时钟的标志

//@@***********************************************************
//
//   功能:  系统时钟中断服务函数
//   函数:  void Sys_tick_isr(void)
//   语言:  C
//   输入:  NONE
//   输出:  NONE
//   作者:  李艳平
//   日期:  2002-05-17
//
//@@***********************************************************
//-------------------------------------------------------------
static void Sys_tick_isr(void)  interrupt 5  using  3
{
    TF2=0;
    
//    P2_0 = 0;
/*
    if(ucFlagEnableClock == 0)
    {
        RunLedPin = ~RunLedPin;        //没有闹钟时闪烁
    }
    else
    {
        RunLedPin = 0;                //启动闹钟时常亮
    }
*/
    Sys_clk_task();  
    
}

//@@***********************************************************
//
//   功能:  系统定时器初始化
//   函数:  void Vtimer_init(void)
//   语言:  C
//   输入:  NONE
//   输出:  NONE
//   作者:  李艳平
//   日期:  2002-05-17
//
//@@***********************************************************
//-------------------------------------------------------------
void Init_sys_timer(void)
{
  BYTE_WORD Init_value; 

  
  Sys_clk_init();  
    
  T2CON=0x00;
//定时器2使用机器周期作为计数脉冲(Fosc/12)
  //Init_value.word=FOSC/((ulong)TICKS_PER_SEC*MACHINE_NUM); 
  Init_value.word=38400; 
  TH2=RCAP2H=-Init_value.bytes.high;
  TL2=RCAP2L=-Init_value.bytes.low;

//    ComSendTxt ("TH2Value", &Init_value, 2);

//启动定时器2工作
      ET2=1;
    TR2=1; 
//开中断总开关    
    ENTER_CRITICAL();   
  //TMOD&=0xF0;                  //使用定时器0,但在中断中需要重新赋初值,因而我更倾向用Timer2
  //TMOD|=0x01;
  
 // Init_value.word=FOSC/(TICKS_PER_SEC*MACHINE_NUM); 
  //TH0=-Init_value.bytes.high;
  //TL0=-Init_value.bytes.low;

  //ET0=1;
  //TR0=1;
}

/*
*********************************************************************************************************
*                                        TIME MODULE INITIALIZATION
*                                     TIME-OF-DAY CLOCK INITIALIZATION
*
* Description : This function initializes the time module.  The time of day clock task will be created
*               by this function.
* Arguments   : None
* Returns     : None.
*********************************************************************************************************
*/
//功能:系统时钟初始化
static  void  Sys_clk_init (void)
{
    ClkTickCtr = 0;
    Clk_set_time(0,0,0);
}
/*
*********************************************************************************************************
*                                    FORMAT CURRENT DATE INTO STRING
*
* Description : Formats the current date into an ASCII string.
* Arguments   : mode   is the format type:
*                      1   will format the time as "MM-DD-YY"           (needs at least  9 characters)
*                      2   will format the time as "Day Month DD, YYYY" (needs at least 30 characters)
*                      3   will format the time as "YYYY-MM-DD"         (needs at least 11 characters)
*               s      is a pointer to the destination string.  The destination string must be large
*                      enough to hold the formatted date.
*                      contain
* Returns     : None.
* Notes       : - A 'switch' statement has been used to allow you to add your own date formats.  For
*                 example, you could display the date in French, Spanish, German etc. by assigning
*                 numbers for those types of conversions.
*               - This function assumes that strcpy(), strcat() and itoa() are reentrant.
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*                                    FORMAT CURRENT TIME INTO STRING
*
* Description : Formats the current time into an ASCII string.
* Arguments   : mode   is the format type:
*                      1   will format the time as "HH:MM:SS"     (24 Hour format)
*                                                                 (needs at least  9 characters)
*                      2   will format the time as "HH:MM:SS AM"  (With AM/PM indication)
*                                                                 (needs at least 13 characters)
*               s      is a pointer to the destination string.  The destination string must be large
*                      enough to hold the formatted time.
*                      contain
* Returns     : None.
* Notes       : - A 'switch' statement has been used to allow you to add your own time formats.
*               - This function assumes that strcpy() is reentrant.
*********************************************************************************************************
*/
//功能:格式化时间
void  Clk_format_time (UCHAR mode, char *s)
{
    UCHAR hr;
    switch (mode)
     {
        case  1:
              strcpy(s, "HH:MM:SS");                  /* Create the template for the selected format   */
              s[0] = ClkHr  / 10 + '0';               /* Convert TIME to ASCII                         */
              s[1] = ClkHr  % 10 + '0';
              s[3] = ClkMin / 10 + '0';
              s[4] = ClkMin % 10 + '0';
              s[6] = ClkSec / 10 + '0';
              s[7] = ClkSec % 10 + '0';
              break;

        case  2:
              strcpy(s, "HH:MM:SS AM");               /* Create the template for the selected format   */
              s[9] = (ClkHr >= 12) ? 'P' : 'A';       /* Set AM or PM indicator                        */
              if (ClkHr > 12) 
                {                                     /* Adjust time to be displayed                   */
                  hr   = ClkHr - 12;
                } 
              else
                {
                  hr = ClkHr;
                }
              s[0] = hr     / 10 + '0';               /* Convert TIME to ASCII                         */
              s[1] = hr     % 10 + '0';
              s[3] = ClkMin / 10 + '0';
              s[4] = ClkMin % 10 + '0';
              s[6] = ClkSec / 10 + '0';
              s[7] = ClkSec % 10 + '0';
              break;
        
         case 3:                                    //xg Add 格式为“HHMMSS”
              strcpy(s, "000000");                  /* Create the template for the selected format   */
              s[0] = ClkHr  / 10 + '0';               /* Convert TIME to ASCII                         */
              s[1] = ClkHr  % 10 + '0';
              s[2] = ClkMin / 10 + '0';
              s[3] = ClkMin % 10 + '0';
              s[4] = ClkSec / 10 + '0';
              s[5] = ClkSec % 10 + '0';
              break;

        default:
              strcpy(s, "?");
              break;
    }
}
/*
*********************************************************************************************************
*                                            UPDATE THE TIME
*
* Description : This function is called to update the time (i.e. hours, minutes and seconds)
* Arguments   : None.
* Returns     : TRUE     if we have completed one day.
*               FALSE    otherwise
* Notes       : This function updates ClkSec, ClkMin and ClkHr.
*********************************************************************************************************
*/
//功能:更新时间
static  BOOL  ClkUpdateTime (void)
{
    BOOL newday;
    
    newday = FALSE;                           /* Assume that we haven't completed one whole day yet      */
    if (ClkSec >= 59)
      {                                        /* See if we have completed one minute yet                 */
          ClkSec = 0;                         /* Yes, clear seconds                                      */

          if (ClkMin >= 59)
           {                                 /*    See if we have completed one hour yet                */
              ClkMin = 0;                     /*    Yes, clear minutes                                   */
            bDispTemperatureSwitch = true;    //整点时显示温度    


              if (ClkHr >= 23) 
               {                              /*        See if we have completed one day yet             */
                 ClkHr = 0;                   /*        Yes, clear hours ...                             */
                //时钟计时跨天
                 newday    = TRUE;            /*        ... change flag to indicate we have a new day    */
               } 
              else
               {
                ClkHr++;                      /*        No,  increment hours                             */
               }
        }
          else
           {
            ClkMin++;                         /*    No,  increment minutes                               */
              if((ClkMin % c_DispTemperatureIntervalMinute) == 0)
              {
                bDispTemperatureSwitch = true;        
              }
              else
              {
                bDispTemperatureSwitch = false;        
              }
           }
     } 
    else
     {
        ClkSec++;                             /* No,  increment seconds                                  */
     }
    return (newday);
}

//时钟的小时加1操作
void CLK_IncHour(void)
{
       if (ClkHr >= 23) 
    {                              
         ClkHr = 0;                 
     } 
       else
       {
        ClkHr++;                      
     }
}

//时钟的小时加1操作
void CLK_IncMinute(void)
{
       if (ClkMin >= 59) 
    {                              
         ClkMin = 0;                 
     } 
       else
       {
        ClkMin++;                     
     }
}

/*
*********************************************************************************************************
*                                          SET TIME ONLY
*
* Description : Set the time-of-day clock
* Arguments   : hr        is the desired hour    (0..23)
*               min       is the desired minutes (0..59)
*               sec       is the desired seconds (0..59)
* Returns     : None.
* Notes       : It is assumed that you are specifying a correct time (i.e. there is no range checking
*               done by this function).
*********************************************************************************************************
*/
void  Clk_set_time (UCHAR hr, UCHAR min, UCHAR sec)
{
    EXIT_CRITICAL();                          /* Release access to time-of-day clock                */
    ClkHr  = hr;
    ClkMin = min;
    ClkSec = sec;
    ENTER_CRITICAL();                         /* Gain exclusive access to time-of-day clock         */

}

//@@***********************************************************
//
//   功能:  给定的时间与当前时间比较
//   函数:  int Cmp_now_time(UCHAR hr, UCHAR min, UCHAR sec)
//   语言:  C
//   输入:         
//   输出:  0   相等
//          >0  给定时间大于当前时间
//          <0  给定时间小于当前时间 
//   作者:  李艳平
//   日期:  2002-05-17
//@@***********************************************************
//------------------------------------------------------------- 
/*
int Cmp_now_time(UCHAR hr, UCHAR min, UCHAR sec)
{
   if(ClkHr!=hr)
     return(hr-ClkHr);
   else if(ClkMin!= min) 
     return(min-ClkMin);   
   else
    // return(sec-ClkSec); 
    sec = sec;   
    return(0);
}
*/

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则