• 嵌入式软件之定时器的设计


    这是真正意义上的第一篇自己写的博客,以前的都是copy的,后来发现这有很多弊病,所以果断全部给delete了!

    不说废话了,正式开始!

    前段时间,跟着项目做智能家居里的一部分工作,里面有写一个定时器,今天就专门来说说这个!

    一说到定时器,估计很多人都第一个想到的是用alarm来做,这个是没问题的,我最初所用的方法也是用的是alarm,但是由于项目要求是在一个进程内控制多个设备的定时开关机(我设计的是16个),于是用alarm就会觉得力有不逮了!

    先来看看用alarm吧!一个进程只能有一个闹钟时间,如果在调用alarm之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。在最初用alarm时,我是先写一个控制设备开关机的函数setPowerOnOff,然后当alarm的时间到了之后,系统会发出一个SIGALRM信号,我再用调用signal函数,使得系统接收到这个信号时就调用setPowerOnOff函数,但是问题出来了,当我alarm倒计时还没结束时,我再次设置定时开关机,假设刚才设置的是1号机,现在我设置2号机,那么系统就会清除之前的1号机alarm,而采用2号机的定时时间重新alarm,那么一号机就被这样被抛弃了!

    于是换了个方法,通过开辟一个线程来维护一个结构体:

    我先声明一个结构体:

    typedef struct intervaltime
    {
        int hour;
        int min;
        int sec;
    }IntervalTime;                                      //时间格式
    
    typedef struct Timing
    {
        int devid[16];                               //16台设备的id
        IntervalTime timeOn[16];             //定时开机时间
        IntervalTime timeOff[16];             //定时关机时间
        int OnState[16];                           //定时开机状态位
        int OffState[16];                           //定时关机状态位
    }timing;

    在维护这个结构体之前,我们还需要写一个获取当前系统时间的函数,代码如下:

    struct tm *ipp_sac_getNowTime()
    {
        time_t rawtime;
        struct tm *systime;
        time(&rawtime);
        systime = localtime(&rawtime);
        return systime;
    }

    前面两部分代码都很简单,也就不多说什么了。

    在声明结构体时,我们可以看到,此定时器只是需要时、分、秒,其余的天,月什么的我们都没去考虑,当然如果说非要用的话,也不是什么难事。我的方法是比较传统的方法,通过比较当前系统时间和设置的定时时间是否相等,以及相应的开关机状态位,来判断在什么时候执行什么样的操作。在我跟的这个项目里,用户端发送的是一个倒计时给我,所以我需要先将这个倒计时转化为一个我们平时所看到的系统时间的格式:

     1     struct tm *timeinfo;
     2     timeinfo = ipp_sac_getNowTime();
     3         static timing TimingPowerOnOff;
     4 
     5     //当前系统时间加上设置的定时关机时间,即为系统将要执行关机动作的时间。
     6     TimingPowerOnOff.devid[deviceid] = deviceid;
     7     TimingPowerOnOff.timeOff[deviceid].hour = timeinfo->tm_hour + time.hour;
     8     TimingPowerOnOff.timeOff[deviceid].min = timeinfo->tm_min + time.minute;
     9     TimingPowerOnOff.timeOff[deviceid].sec = timeinfo->tm_sec + time.sec;
    10         //当时,分达到24和60时,则需要如下的处理:
    11     if(TimingPowerOnOff.timeOff[deviceid].min > 59)
    12     {
    13         TimingPowerOnOff.timeOff[deviceid].min = TimingPowerOnOff.timeOff[deviceid].min - 60;
    14         TimingPowerOnOff.timeOff[deviceid].hour = TimingPowerOnOff.timeOff[deviceid].hour + 1;
    15     }
    16 
    17     if(TimingPowerOnOff.timeOff[deviceid].hour > 23)
    18     {
    19         TimingPowerOnOff.timeOff[deviceid].hour = TimingPowerOnOff.timeOff[deviceid].hour - 24;
    20     }        

    时间处理好了,接下来我们就只需要判断当前时间是否等于设置的时间就行了,以前设置的是定时开机还是定时关机,设置定时开关机状态就是0和1的问题,就不多说了。

        while(1)
        {
            int tmp;
            struct tm *nowTimeInfo;
            nowTimeInfo = ipp_sac_getNowTime();
    
            for(tmp = 0;tmp < 16;tmp++)
            {
                if(TimingPowerOnOff.timeOff[tmp].hour ==  nowTimeInfo->tm_hour && TimingPowerOnOff.timeOff[tmp].min == nowTimeInfo->tm_min)
                {
                    if(TimingPowerOnOff.OffState[tmp] == 1)
                    {
                        mcu_sac_setPower(tmp,POWER_OFF);     //mcu_sac_setPower即为触发设备开关机的函数,此处就不列代码了。POWER_OFF = 1;
                        TimingPowerOnOff.OffState[tmp] = 0;
                    }
                }
    
                if(TimingPowerOnOff.timeOn[tmp].hour ==  nowTimeInfo->tm_hour && TimingPowerOnOff.timeOn[tmp].min == nowTimeInfo->tm_min)
                {
                    if(TimingPowerOnOff.OnState[tmp] == 1)
                    {
                        mcu_sac_setPower(tmp,POWER_ON);  //POWER_ON = 0;
                        TimingPowerOnOff.OnState[tmp] = 0;
                    }
                }
            }
            sleep(60);                 //虽然我声明的时间类型的有秒,但是实际项目里我没用到,所以这里就加了个sleep(60),让它每隔一分钟循环一次。
        }

    到这里,定时器就设计好了,但是同时值得注意的是,我是开辟了一个线程来做定时器这个功能的,只是代码里我没有把那部分给列举出来而已;当然,如果整个进程只是跑一个定时器,线程神马的就可以不用了,这看个人喜好啦!

    第一篇博客就算搞定啦,虽然定时器这个很简单,我说的估计也不仔细,但是不积跬步无以至千里,一切慢慢来吧!

  • 相关阅读:
    PHP中单引号与双引号的区别分析
    utf8_unicode_ci与utf8_general_ci的区别
    [mysql-Ver5.6.23] windows版my.ini配置
    Gateway/Worker模型 数据库使用示例
    php 字符串 以 开头 以结尾 startWith endWith
    MySQL错误ERROR 2002 (HY000): Can't connect to local MySQL server
    vim变ide
    在Vue中使用样式
    Vue指令之`v-model`和`双向数据绑定
    Vue指令之事件修饰符
  • 原文地址:https://www.cnblogs.com/rade/p/3503638.html
Copyright © 2020-2023  润新知