从EtherCAT中学到的高精度时间控制与测试

一、需要的头文件

#include <stdio.h>
#include <sys/time.h>	// for struct timeval
#include <time.h>
#include <sys/mman.h>
#include <malloc.h>
#include <sched.h> /* sched_setscheduler() */

#include <stdlib.h> // for size_t
#include <stdint.h>

二、前置知识

        timespec时间结构体

//定义
struct timespec
{
  __time_t tv_sec;		/* Seconds.  */
  __syscall_slong_t tv_nsec;	/* Nanoseconds.  */
};

//初始化
struct timespec startTime, endTime, lastStartTime = {};

//timespec时间结构体的加法
#define NSEC_PER_SEC (1000000000L)  //纳秒数10^9
#define PERIOD_NS (NSEC_PER_SEC / FREQUENCY)    /*本次设置周期PERIOD_NS为1ms*/

struct timespec timespec_add(struct timespec time1, struct timespec time2)
{
    struct timespec result;

    if ((time1.tv_nsec + time2.tv_nsec) >= NSEC_PER_SEC) {
        result.tv_sec = time1.tv_sec + time2.tv_sec + 1;    // 纳秒满进1
        result.tv_nsec = time1.tv_nsec + time2.tv_nsec - NSEC_PER_SEC;
    } else {
        result.tv_sec = time1.tv_sec + time2.tv_sec;
        result.tv_nsec = time1.tv_nsec + time2.tv_nsec;
    }

    return result;
}

       基于Linux C语言的时间函数<time.h>,可以用于计算时间,有秒和纳秒两种精度

        获取当前时间:clock_gettime;               其中cld_id类型四种。CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变。CLOCK_MONOTONIC,从系统启动这一刻起开始计时,不受系统时间被用户改变的影响。CLOCK_PROCESS_CPUTIME_ID,本进程到当前代码系统CPU花费的时间。CLOCK_THREAD_CPUTIME_ID,本线程到当前代码系统CPU花费的时间。第一、二两种类型均可

        调用线程以纳秒为精度进行指定的时间间隔睡眠:clock_nanosleep;

三、以1ms为间隔的休眠循环函数

const struct timespec cycletime = {0, PERIOD_NS};//1ms

void cyclic_task()
{


    struct timespec wakeupTime, time;

    // 获取当前时间
    //cld_id类型为CLOCK_MONOTONIC
    clock_gettime(CLOCK_MONOTONIC, &wakeupTime);

    while(1) {

	    //printf("wakeupTime: %10u--%10u\n",wakeupTime.tv_sec,wakeupTime.tv_nsec);
	    //循环时间 每次增加1个cycletime 从循环开始固定
        wakeupTime = timespec_add(wakeupTime, cycletime);
        //调用线程以纳秒精度指定的时间间隔进行睡眠	(高分辨率休眠)
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wakeupTime, NULL);
    }

}

四、代码运行时间测试

包括延迟时间latency_ns,执行时间exec_ns,周期时间period_ns。单位纳秒

#define DIFF_NS(A, B) (((B).tv_sec - (A).tv_sec) * NSEC_PER_SEC + \
       (B).tv_nsec - (A).tv_nsec)        计算时间差

void cyclic_task()
{

    struct timespec wakeupTime, time;
    //测量时间
#ifdef MEASURE_TIMING
    struct timespec startTime, endTime, lastStartTime = {};
    uint32_t period_ns = 0, exec_ns = 0, latency_ns = 0,
             latency_min_ns = 0, latency_max_ns = 0,
             period_min_ns = 0, period_max_ns = 0,
             exec_min_ns = 0, exec_max_ns = 0;
#endif

    // 获取当前时间系统
    clock_gettime(CLOCK_TO_USE, &wakeupTime);

    while(1) {

        wakeupTime = timespec_add(wakeupTime, cycletime);
        //调用线程以纳秒精度指定的时间间隔进行睡眠	(高分辨率休眠)
        clock_nanosleep(CLOCK_TO_USE, TIMER_ABSTIME, &wakeupTime, NULL);


#ifdef MEASURE_TIMING
        //记录工作代码开始时间
        clock_gettime(CLOCK_TO_USE, &startTime);


        //延迟时间
        latency_ns = DIFF_NS(wakeupTime, startTime);
        //周期时间
        period_ns = DIFF_NS(lastStartTime, startTime);
        //代码执行时间
        exec_ns = DIFF_NS(lastStartTime, endTime);
        //赋值    以记录完整的周期时间
        lastStartTime = startTime;


        //记录延时最大间隔
        if (latency_ns > latency_max_ns) {
            latency_max_ns = latency_ns;
        }
        if (latency_ns < latency_min_ns) {
            latency_min_ns = latency_ns;
        }
        if (period_ns > period_max_ns) {
            period_max_ns = period_ns;
        }
        if (period_ns < period_min_ns) {
            period_min_ns = period_ns;
        }
        if (exec_ns > exec_max_ns) {
            exec_max_ns = exec_ns;
        }
        if (exec_ns < exec_min_ns) {
            exec_min_ns = exec_ns;
        }
#endif

        /....../

#ifdef MEASURE_TIMING
            // 输出时间统计数据
            printf("period     %10u ... %10u\n",
                    period_min_ns, period_max_ns);
            printf("exec       %10u ... %10u\n",
                    exec_min_ns, exec_max_ns);
            printf("latency    %10u ... %10u\n",
                    latency_min_ns, latency_max_ns);
            period_max_ns = 0;
            period_min_ns = 0xffffffff;
            exec_max_ns = 0;
            exec_min_ns = 0xffffffff;
            latency_max_ns = 0;
            latency_min_ns = 0xffffffff;
#endif
        }

        /...主要代码.../
       
#ifdef MEASURE_TIMING
        //代码运行结束时间
        clock_gettime(CLOCK_TO_USE, &endTime);
#endif
    }
}

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值