簡體   English   中英

C中的精確計時

[英]precise timing in C

我在下面有一些代碼。 我使用此代碼從嵌入式板的GPIO輸出一些1和0( unsigned output[38] )。

我的問題:兩個輸出值(1,0或0,1)之間的時間應該是416微秒,因為我在clock_nanosleep下面的clock_nanosleep定義,我還使用sched_priority()來獲得更好的時間分辨率。 但是,示波器(下圖)測量顯示兩個輸出值之間的時間是770 usec 我想知道為什么信號之間有那么多的不准確?

PS。 主板(beagleboard)有Linux 3.2.0-23-omap#36-Ubuntu Tue Apr 10 20:24:21 UTC 2012 armv7l armv7l armv7l GNU / Linux內核,它有750 MHz CPU, top顯示幾乎沒有CPU(〜在運行我的代碼之前消耗1%)和內存(~0.5%)。 我使用沒有校准問題的電子示波器。

#include <stdio.h>
#include <stdlib.h> //exit();
#include <sched.h>
#include <time.h>

void msg_send();
struct sched_param sp;

int main(void){
      sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
      sched_setscheduler(0, SCHED_FIFO, &sp);
      msg_send();
    return 0;
}

void msg_send(){
    unsigned output[38] = {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1}; 

    FILE *fp8;
    if ((fp8 = fopen("/sys/class/gpio/export", "w")) == NULL){  //echo 139 > export
           fprintf(stderr,"Cannot open export file: line844.\n"); fclose(fp8);exit(1);
    }
    fprintf(fp8, "%d", 139);  //pin 3
    fclose(fp8);

    if ((fp8 = fopen("/sys/class/gpio/gpio139/direction", "rb+")) == NULL){
       fprintf(stderr,"Cannot open direction file - GPIO139 - line851.\n");fclose(fp8); exit(1);
    }
    fprintf(fp8, "out");
    fclose(fp8);

   if((fp8 = fopen("/sys/class/gpio/gpio139/value", "w")) == NULL) {
        fprintf(stderr,"error in openning value\n");  fclose(fp8); exit(1);
}

struct timespec req = { .tv_sec=0, .tv_nsec = 416000 }; //416 usec

/* here is the part that my question focus*/
    while(1){
        for(i=0;i<38;i++){
        rewind(fp8);
        fprintf(fp8, "%d", output[i]);
        clock_nanosleep(CLOCK_MONOTONIC ,0, &req, NULL);

        }
    }
}

在此輸入圖像描述

編輯:我已經讀了幾天clock_nanosleep()或其他nanosleep,usleep等不保證按時醒來。 它們通常提供在規定時間內睡眠代碼,但喚醒進程取決於CPU。 我發現絕對時間提供了更好的分辨率( TIMER_ABSTIME標志)。 我找到了與Maxime建議相同的解決方案。 但是,當循環結束時,我的信號出現故障。 在我看來,在嵌入式平台上創建PWM或數據輸出的任何睡眠功能都不好。 花一些時間來學習平台提供的CPU定時器以生成具有良好精度的PWM或數據輸出是很好的。

我無法弄清楚對clock_getres()的調用如何解決你的問題。 在手冊頁中,據說只讀取時鍾的分辨率。

正如Geoff所說,使用絕對睡眠時鍾應該是更好的解決方案。 這可以避免來自其他代碼的不期望的定時延遲。

struct timespec Time;
clock_gettime(CLOCK_REALTIME, &(Time));

while(1){
    Time.tv_nsec += 416000;
    if(Time.tv_nsec > 999999999){
        (Time.tv_sec)++;
        Time.tv_nsec -= 1000000000;
    }
    clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &(Time), NULL);
    //Do something
}

我在少數幾個程序上使用它來在以太網上生成一些常規消息。 它工作正常。

如果你正在進行時間敏感的I / O,你可能不應該使用stdio.h的東西,而是由於stdio完成的緩沖而調用I / O系統。 看起來你可能會得到最緩慢的緩沖效果,因為你的程序執行以下步驟:

  1. 填充緩沖區
  2. 睡覺
  3. 倒帶,我相信會刷新緩沖區

你想要的是內核在你睡覺時為寫操作提供服務,而是在你睡覺之后刷新緩沖區並且你必須等待內核來處理它。

我認為你最好的選擇是使用open("/sys/class/gpio/gpio139/value", O_WRONLY|O_DIRECT)來最小化緩存造成的延遲。

如果您仍需要刷新緩沖區以強制寫入,則可能需要使用clock_gettime來計算刷新數據所花費的時間並從睡眠時間中減去該時間。 或者,將所需的時間間隔添加到clock_gettime的結果中,並將其傳遞給clock_nanosleep並使用TIMER_ABSTIME標志等待該絕對時間發生。

我猜想問題是clock_nanosleep正在休眠416微秒,而循環中的其他命令以及loop和clock_nanosleep架構本身都需要354微秒。 操作系統也可能提出要求。

如果設置sleep = 0,你會得到什么時間間隔?

你在電腦或PLC上運行嗎?

對評論的回應

看起來你在硬件/軟件中有些東西正在做出意想不到的事情 - 它可能是一個找到的bugger。

根據期間的重要程度,我有2條建議:

  1. 低臨界性 - 在程序中放置一個數字,使循環花費您想要的時間。 但是,如果這是瞬態或時間/溫度相關的影響,您需要定期檢查漂移。
  2. 高臨界性 - 在硬件中構建溫度穩定的振盪器。 這些可以現成的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM