本专题相关教程:
0 前言
温馨提示,本文为基于Linux C的CANopen移植后续。
如果你在移植完canfestival之后,需要使用与时间相关的功能,如pdo或者心跳检测。那么你可能会发现时间计算有问题,比如pdo计算时间会加倍,或者主站判断节点心跳帧时间不能正常使用。
主要原因是时间函数存在一些bug,只要超过一种功能对其进行调用,便会出错,因此我们需要对其进行一些修改。
1 配置timerscfg.h
如图,我们设置时间变量单位为10ms(即10ms增加一次),类型为unsigned long(32位),最大值设置为0xFFFFFFFF。那么这个变量最大值约有497天(也就是说基本达不到最大值,好处就是不用考虑计时数据溢出的情况)。
为啥是10ms一次呢,因为linux下高精度定时非常难弄,反倒是简单select函数延时越久精度越高。
2022年3月22日记:有些同学并不是跟着我的教程来的,那么这里就不用和我一样。你只需要估计一下自己设置的最大值,是否存在溢出的可能,如果有可能,则代码会多几句,如下边代码所示
2 修改timer0.c文件
该文件为时间函数实现文件,大家的文件不一定是这个名字。它需要包含如下功能:
函数 | 解释 |
---|---|
setTimer | 名字固定,设置下一次定时任务。会被源文件调用 |
getElapsedTime | 名字固定,获取系统运行时间(上次调用与这次调用的间隔)。会被源文件调用 |
因为移植的相关函数写得很复杂。我将其简化,使其更容易阅读与修改。
代码如下:
#include "timer0.h"
pthread_t tid_canopen_timer;//线程任务句柄
UNS32 cur_time = 0; //当前时间 32位
TIMEVAL last_time = 0; //记录上一次时间
TIMEVAL next_time_set = 0; //设置下一次时间
/*********************select延时**************************************/
static void delay_ms(int ms) //使用select延时,分辨率约为10ms
{
struct timeval time;
time.tv_sec = 0;
time.tv_usec = ms * 1000;
select(0, NULL, NULL, NULL, &time);//等待
}
/*********************CANopen定时器任务**************************************/
void CANopen_Timer_Task(void)
{
TimeDispatch(); //先执行一遍定时任务
printf("canopen timer init\r\n");
while (1)
{
delay_ms(10); // 10ms。模拟10ms一次中断
cur_time++;
if (cur_time == next_time_set)//达到预设的下一次时间
{
last_time = cur_time; //设置为上一次时间
TimeDispatch();
}
}
}
// 设置下一次定时任务
void setTimer(TIMEVAL value)
{
next_time_set = cur_time + value; //设置下一次时间
// printf("setTimer %lu, next time set %lu\r\n", value, next_time_set);
}
//返回数据,自从上次调用该函数到现在间隔多久
TIMEVAL getElapsedTime(void)
{
return cur_time - last_time;
}
如果计数存在溢出的可能,则setTimer和getElapsedTime需要略作修改,如下。该代码是兼容上边的。
void setTimer(TIMEVAL value)
{
next_time_set = (cur_time + value) % TIMEVAL_MAX; //设置下一次时间
// printf("setTimer %lu, next time set %lu\r\n", value, next_time_set);
}
//返回数据,自从上次调用该函数到现在间隔多久
TIMEVAL getElapsedTime(void)
{
if (cur_time >= last_time)
return cur_time - last_time;
else
return (cur_time + TIMEVAL_MAX) - last_time;
}
可以看到,函数都非常简单,见名知意。经过实验,没有问题。
所以按照道理,基于STM32平台也可以进行相关的修改。
主要思路同理:设置一个定时器,10ms一个溢出中断,在中断函数里面每次让时间计数加一,达到下一次预设时间则调用解析函数。
我这里因为节点只有心跳报文调用了时间(没有多个功能同时调用,则正常),我就懒得改了。