CANopen补充--时间计算出错

本专题相关教程:

基于STM32F4的CANOpen移植教程

基于STM32F4的CANopen快速SDO通信

linux下CANopen for python的使用

基于Linux C的CANopen移植

CANopen补充–时间计算出错

CANopen补充–主站检测节点是否在线

0 前言

温馨提示,本文为基于Linux C的CANopen移植后续。
如果你在移植完canfestival之后,需要使用与时间相关的功能,如pdo或者心跳检测。那么你可能会发现时间计算有问题,比如pdo计算时间会加倍,或者主站判断节点心跳帧时间不能正常使用。
主要原因是时间函数存在一些bug,只要超过一种功能对其进行调用,便会出错,因此我们需要对其进行一些修改。

1 配置timerscfg.h

CANopen补充--时间计算出错_第1张图片
如图,我们设置时间变量单位为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一个溢出中断,在中断函数里面每次让时间计数加一,达到下一次预设时间则调用解析函数。
我这里因为节点只有心跳报文调用了时间(没有多个功能同时调用,则正常),我就懒得改了。

你可能感兴趣的:(CANopen教程,linux,c语言,单片机)