CANOpen定时器

https://blog.csdn.net/lushoumin/article/details/79613987

在CANOpen中,有部分和时间相关的子协议,比如pdo和lifegrd等,这就要求移植的时候实现定时器的底层接口。

在timer.h中给出了接口声明

[cpp]  view plain  copy
  1. /* 设置定时器重载值 */  
  2. void setTimer(TIMEVAL value);  
  3.   
  4. /* 获取当前定时器计数器值 */  
  5. TIMEVAL getElapsedTime(void);  


timer.c通过一个定时器实现各种定时事务的管理,定时事件数的上限取决于config.h中的宏MAX_NB_TIMER,在timer.c中定义了定时事件入口数组s_timer_entry timers[MAX_NB_TIMER]。

[cpp]  view plain  copy
  1. /* 定时事件入口结构体 */  
  2. struct struct_s_timer_entry   
  3. {  
  4.     UNS8 state;     <span style="white-space:pre;"> </span>/* 事件状态 */  
  5.     CO_Data *d;         /* 节点指针 */  
  6.     TimerCallback_t callback;<span style="white-space:pre;">    </span>/* 回调函数 */  
  7.     UNS32 id;           /* 回调函数参数,用来区分事件 */  
  8.     TIMEVAL val;            /* 定时时间 */  
  9.     TIMEVAL interval;       /* 是否周期触发,0表示单次触发,非0表示周期触发 */  
  10. };  


所有定时事件入口有4中状态

[cpp]  view plain  copy
  1. #define TIMER_FREE 0        /* 空闲,即该入口没有被定时事件占用 */  
  2. #define TIMER_ARMED 1       /* 被占用,即该入口已经定时事件占用 */  
  3. #define TIMER_TRIG 2        /* 单次触发 */  
  4. #define TIMER_TRIG_PERIOD 3 /* 周期触发 */  

向定时事件入口中添加一个定时事件

[cpp]  view plain  copy
  1. /* 功能:添加一个定时事件 
  2.  * 参数:d表示节点指针 
  3.  *   id作为回调函数的参数,用以区分事件 
  4.  *   callback是回调函数 
  5.  *   value表示定时时间(32位即最长71.6分钟) 
  6.  *   period为0表示单次触发,不为0表示循环触发 
  7.  */  
  8. TIMER_HANDLE SetAlarm(CO_Data *d, UNS32 id, TimerCallback_t callback, TIMEVAL value, TIMEVAL period)  
  9. {  
  10.     TIMER_HANDLE row_number;  
  11.     s_timer_entry *row;  
  12.   
  13.     /* 遍历定时事件入口 */  
  14.     for(row_number = 0, row = timers; row_number <= last_timer_raw + 1 && row_number < MAX_NB_TIMER; row_number++, row++)  
  15.     {  
  16.         /* 当注册的回调函数不为空,并且该入口状态为空闲,则可以将事件添加到该入口 */  
  17.         if(callback && row->state == TIMER_FREE)  
  18.         {  
  19.             TIMEVAL real_timer_value;  
  20.             TIMEVAL elapsed_time;  
  21.   
  22.             /* 更新定时事件在事件入口数组中的最大下标 */  
  23.             if(row_number == last_timer_raw + 1)   
  24.                 last_timer_raw++;  
  25.   
  26.             /* 获取定时器当前已经流逝的时间 */  
  27.             elapsed_time = getElapsedTime();  
  28.             /* STM32自动重载寄存器为16位,所以这个触发时间不能大于65535 */  
  29.             real_timer_value = value;  
  30.             real_timer_value = min_val(real_timer_value, TIMEVAL_MAX);  
  31.   
  32.             /* 比较原本预定下一次唤醒时间和本事件触发时间,如果本事件先触发,则更新定时器唤醒时间 */  
  33.             if(total_sleep_time > elapsed_time && total_sleep_time - elapsed_time > real_timer_value)  
  34.             {  
  35.                 /* 更新唤醒时间 */  
  36.                 total_sleep_time = elapsed_time + real_timer_value;  
  37.                 /* 设置定时器重载值 */  
  38.                 setTimer(real_timer_value);  
  39.             }  
  40.   
  41.             /* 初始化回调函数 */  
  42.             row->callback = callback;  
  43.             /* 初始化节点指针 */  
  44.             row->d = d;  
  45.             /* 初始化id */  
  46.             row->id = id;  
  47.             /* 初始化触发时间 */  
  48.             row->val = value + elapsed_time;  
  49.             /* 初始化周期 */  
  50.             row->interval = period;  
  51.             /* 初始化状态为入口以被占用 */  
  52.             row->state = TIMER_ARMED;  
  53.               
  54.             /* 返回定时器事件入口数组下标,作为句柄 */  
  55.             return row_number;  
  56.         }  
  57.     }  
  58.   
  59.     /* 返回错误 */  
  60.     return TIMER_NONE;  
  61. }  

从定时事件入口中删除一个定时事件

[cpp]  view plain  copy
  1. /* 删除定时事件 */  
  2. TIMER_HANDLE DelAlarm(TIMER_HANDLE handle)  
  3. {  
  4.     MSG_WAR(0x3320, "DelAlarm. handle = ", handle);  
  5.       
  6.     /* 将该定时事件入口状态置为空闲 */  
  7.     if(handle != TIMER_NONE)  
  8.     {  
  9.         if(handle == last_timer_raw)  
  10.             last_timer_raw--;  
  11.         timers[handle].state = TIMER_FREE;  
  12.     }  
  13.       
  14.     /* 返回错误 */  
  15.     return TIMER_NONE;  
  16. }  

在移植CANOpen协议栈时,要在中断处理函数中调用TimeDispatch函数进行定时事件触发处理

[cpp]  view plain  copy
  1. /* 定时事件触发处理函数 */  
  2. void TimeDispatch(void)  
  3. {  
  4.     TIMER_HANDLE i;  
  5.     TIMEVAL next_wakeup = TIMEVAL_MAX;  
  6.       
  7.     /* 获取定时器中断到现在已经流逝的时间 */  
  8.     UNS32 overrun = (UNS32)getElapsedTime();  
  9.   
  10.     /* 计算出到目前为止真正流逝的时间 */  
  11.     TIMEVAL real_total_sleep_time = total_sleep_time + overrun;  
  12.   
  13.     s_timer_entry *row;  
  14.   
  15.     /* 遍历定时事件入口 */  
  16.     for(i = 0, row = timers; i <= last_timer_raw; i++, row++)  
  17.     {  
  18.         /* 如果该定时事件入口被定时事件占用,如判断是否超时 */  
  19.         if(row->state & TIMER_ARMED)  
  20.         {  
  21.             /* 如果已经超时,则需要触发 */  
  22.             if(row->val <= real_total_sleep_time)  
  23.             {  
  24.                 /* 如果该事件为单次触发,则将该事件状态设置为已触发 */  
  25.                 if(!row->interval)  
  26.                 {  
  27.                     row->state = TIMER_TRIG;  
  28.                 }  
  29.                 /* 如果该事件为周期触发 */  
  30.                 else  
  31.                 {  
  32.                     /* 校正定时时间 */  
  33.                     row->val = row->interval - (overrun % (UNS32)row->interval);  
  34.                     /* 状态置为已周期触发 */  
  35.                     row->state = TIMER_TRIG_PERIOD;  
  36.                       
  37.                     /* 更新定时器唤醒时间 */  
  38.                     if(row->val < next_wakeup)  
  39.                         next_wakeup = row->val;  
  40.                 }  
  41.             }  
  42.             /* 没有超时,不需要触发 */  
  43.             else  
  44.             {  
  45.                 /* 更新该事件唤醒时间 */  
  46.                 row->val -= real_total_sleep_time;  
  47.   
  48.                 /* 更新定时器唤醒时间 */  
  49.                 if(row->val < next_wakeup)  
  50.                     next_wakeup = row->val;  
  51.             }  
  52.         }  
  53.     }  
  54.   
  55.     /* 将得出定时器唤醒时间赋值 */  
  56.     total_sleep_time = next_wakeup;  
  57.   
  58.     /* 设置定时器重载值 */  
  59.     setTimer(next_wakeup);  
  60.   
  61.     /* 遍历所欲定时事件接口 */  
  62.     for(i = 0, row = timers; i <= last_timer_raw; i++, row++)  
  63.     {  
  64.         /* 如果该事件已经被触发(单次触发/周期触发) */  
  65.         if(row->state & TIMER_TRIG)  
  66.         {  
  67.             /* 将单次触发更新为空闲,周期触发的更新为被占用 */  
  68.             row->state &= ~TIMER_TRIG;  
  69.               
  70.             /* 需要触发的事件,调用一下回调函数 */  
  71.             if(row->callback)  
  72.                 (*row->callback)(row->d, row->id);  
  73.         }  
  74.     }  

猜你喜欢

转载自blog.csdn.net/android_lover2014/article/details/80009071