10

以下に小さなコードがあります。unsigned output[38]このコードを使用して、組み込みボードのGPIOからいくつかの1と0()を出力します。

私の質問:2つの出力値(1、0または0、1)の間の時間は、以下のコードで定義するように416マイクロ秒である必要があります。また、より良い時間分解能のために使用しました。ただし、オシロスコープ(下の写真)の測定では、2つの出力値の間の時間は770usecであることが示されています。なぜ信号間にそれほど不正確なのかしら?clock_nanosleepsched_priority()

PS。ボード(ビーグルボード)にはLinux 3.2.0-23-omap#36-Ubuntu Tue Apr 10 20:24:21 UTC 2012 armv7l armv7l armv7l GNU / Linuxカーネルがあり、750 MHzのCPUを搭載しており、topCPUはほとんど表示されません(〜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が提案するのと同じ解決策を見つけました。ただし、forループが終了すると、信号に不具合が発生します。私の意見では、組み込みプラットフォームでPWMまたはデータ出力を作成することは、スリープ機能には適していません。プラットフォームが提供するCPUタイマーを学習して、精度の高いPWMまたはデータ出力を生成することをお勧めします。

4

3 に答える 3

2

clock_getres()を呼び出すと問題がどのように解決されるかわかりません。マニュアルページでは、時計の解像度のみを読み取ると言われています。

ジェフが言ったように、絶対睡眠時計を使用することはより良い解決策であるはずです。これにより、他のコードによる予期しないタイミング遅延を回避できます。

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
}

私はこれをイーサネットネットワーク上で定期的なメッセージを生成するために持っているいくつかのプログラムで使用しています。そして、それはうまく機能しています。

于 2013-02-08T14:43:36.780 に答える
1

時間に敏感な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てその絶対時間が発生するのを待ちます。

于 2013-02-08T04:58:18.123 に答える
0

問題は、clock_nanosleepが416マイクロ秒スリープしていることと、ループ内の他のコマンド、およびループとclock_nanosleepアーキテクチャ自体が354マイクロ秒かかっていることだと思います。OSも要求を出している可能性があります。

sleep = 0に設定すると、どのくらいの間隔が得られますか?

これをコンピューターまたはPLCで実行していますか?

コメントへの回答

ハードウェア/ソフトウェアに予期しないことをしている何かがあるようです-見つけるのはバガーかもしれません。

期間の重要度に応じて、2つの提案があります。

  1. 重要度が低い-ループに必要な時間がかかる原因となる数値をプログラムに入れます。ただし、これが一時的または時間/温度に依存する影響である場合は、ドリフトを定期的にチェックする必要があります。
  2. 高い重要度-ハードウェアに温度安定性のあるオシレーターを構築します。これらは既製で購入できます。
于 2013-02-08T03:44:05.540 に答える