概述
https://blog.csdn.net/lushoumin/article/details/79613987
在CANOpen中,有部分和时间相关的子协议,比如pdo和lifegrd等,这就要求移植的时候实现定时器的底层接口。
在timer.h中给出了接口声明
- /* 设置定时器重载值 */
- void setTimer(TIMEVAL value);
- /* 获取当前定时器计数器值 */
- TIMEVAL getElapsedTime(void);
timer.c通过一个定时器实现各种定时事务的管理,定时事件数的上限取决于config.h中的宏MAX_NB_TIMER,在timer.c中定义了定时事件入口数组s_timer_entry timers[MAX_NB_TIMER]。
- /* 定时事件入口结构体 */
- struct struct_s_timer_entry
- {
- UNS8 state; <span style="white-space:pre;"> </span>/* 事件状态 */
- CO_Data *d; /* 节点指针 */
- TimerCallback_t callback;<span style="white-space:pre;"> </span>/* 回调函数 */
- UNS32 id; /* 回调函数参数,用来区分事件 */
- TIMEVAL val; /* 定时时间 */
- TIMEVAL interval; /* 是否周期触发,0表示单次触发,非0表示周期触发 */
- };
所有定时事件入口有4中状态
- #define TIMER_FREE 0 /* 空闲,即该入口没有被定时事件占用 */
- #define TIMER_ARMED 1 /* 被占用,即该入口已经定时事件占用 */
- #define TIMER_TRIG 2 /* 单次触发 */
- #define TIMER_TRIG_PERIOD 3 /* 周期触发 */
向定时事件入口中添加一个定时事件
- /* 功能:添加一个定时事件
- * 参数:d表示节点指针
- * id作为回调函数的参数,用以区分事件
- * callback是回调函数
- * value表示定时时间(32位即最长71.6分钟)
- * period为0表示单次触发,不为0表示循环触发
- */
- TIMER_HANDLE SetAlarm(CO_Data *d, UNS32 id, TimerCallback_t callback, TIMEVAL value, TIMEVAL period)
- {
- TIMER_HANDLE row_number;
- s_timer_entry *row;
- /* 遍历定时事件入口 */
- for(row_number = 0, row = timers; row_number <= last_timer_raw + 1 && row_number < MAX_NB_TIMER; row_number++, row++)
- {
- /* 当注册的回调函数不为空,并且该入口状态为空闲,则可以将事件添加到该入口 */
- if(callback && row->state == TIMER_FREE)
- {
- TIMEVAL real_timer_value;
- TIMEVAL elapsed_time;
- /* 更新定时事件在事件入口数组中的最大下标 */
- if(row_number == last_timer_raw + 1)
- last_timer_raw++;
- /* 获取定时器当前已经流逝的时间 */
- elapsed_time = getElapsedTime();
- /* STM32自动重载寄存器为16位,所以这个触发时间不能大于65535 */
- real_timer_value = value;
- real_timer_value = min_val(real_timer_value, TIMEVAL_MAX);
- /* 比较原本预定下一次唤醒时间和本事件触发时间,如果本事件先触发,则更新定时器唤醒时间 */
- if(total_sleep_time > elapsed_time && total_sleep_time - elapsed_time > real_timer_value)
- {
- /* 更新唤醒时间 */
- total_sleep_time = elapsed_time + real_timer_value;
- /* 设置定时器重载值 */
- setTimer(real_timer_value);
- }
- /* 初始化回调函数 */
- row->callback = callback;
- /* 初始化节点指针 */
- row->d = d;
- /* 初始化id */
- row->id = id;
- /* 初始化触发时间 */
- row->val = value + elapsed_time;
- /* 初始化周期 */
- row->interval = period;
- /* 初始化状态为入口以被占用 */
- row->state = TIMER_ARMED;
- /* 返回定时器事件入口数组下标,作为句柄 */
- return row_number;
- }
- }
- /* 返回错误 */
- return TIMER_NONE;
- }
从定时事件入口中删除一个定时事件
- /* 删除定时事件 */
- TIMER_HANDLE DelAlarm(TIMER_HANDLE handle)
- {
- MSG_WAR(0x3320, "DelAlarm. handle = ", handle);
- /* 将该定时事件入口状态置为空闲 */
- if(handle != TIMER_NONE)
- {
- if(handle == last_timer_raw)
- last_timer_raw--;
- timers[handle].state = TIMER_FREE;
- }
- /* 返回错误 */
- return TIMER_NONE;
- }
在移植CANOpen协议栈时,要在中断处理函数中调用TimeDispatch函数进行定时事件触发处理
- /* 定时事件触发处理函数 */
- void TimeDispatch(void)
- {
- TIMER_HANDLE i;
- TIMEVAL next_wakeup = TIMEVAL_MAX;
- /* 获取定时器中断到现在已经流逝的时间 */
- UNS32 overrun = (UNS32)getElapsedTime();
- /* 计算出到目前为止真正流逝的时间 */
- TIMEVAL real_total_sleep_time = total_sleep_time + overrun;
- s_timer_entry *row;
- /* 遍历定时事件入口 */
- for(i = 0, row = timers; i <= last_timer_raw; i++, row++)
- {
- /* 如果该定时事件入口被定时事件占用,如判断是否超时 */
- if(row->state & TIMER_ARMED)
- {
- /* 如果已经超时,则需要触发 */
- if(row->val <= real_total_sleep_time)
- {
- /* 如果该事件为单次触发,则将该事件状态设置为已触发 */
- if(!row->interval)
- {
- row->state = TIMER_TRIG;
- }
- /* 如果该事件为周期触发 */
- else
- {
- /* 校正定时时间 */
- row->val = row->interval - (overrun % (UNS32)row->interval);
- /* 状态置为已周期触发 */
- row->state = TIMER_TRIG_PERIOD;
- /* 更新定时器唤醒时间 */
- if(row->val < next_wakeup)
- next_wakeup = row->val;
- }
- }
- /* 没有超时,不需要触发 */
- else
- {
- /* 更新该事件唤醒时间 */
- row->val -= real_total_sleep_time;
- /* 更新定时器唤醒时间 */
- if(row->val < next_wakeup)
- next_wakeup = row->val;
- }
- }
- }
- /* 将得出定时器唤醒时间赋值 */
- total_sleep_time = next_wakeup;
- /* 设置定时器重载值 */
- setTimer(next_wakeup);
- /* 遍历所欲定时事件接口 */
- for(i = 0, row = timers; i <= last_timer_raw; i++, row++)
- {
- /* 如果该事件已经被触发(单次触发/周期触发) */
- if(row->state & TIMER_TRIG)
- {
- /* 将单次触发更新为空闲,周期触发的更新为被占用 */
- row->state &= ~TIMER_TRIG;
- /* 需要触发的事件,调用一下回调函数 */
- if(row->callback)
- (*row->callback)(row->d, row->id);
- }
- }
- }
最后
以上就是瘦瘦荔枝为你收集整理的CANOpen定时器的全部内容,希望文章能够帮你解决CANOpen定时器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复