質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • Arduino

    552questions

    Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Arduinoのdelay関数が正確に動作しません(遅延します)

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 9,328

K.U.

score 3

デジタル回路初心者です.
 arduinoを用いて正確なサンプリング時間を可能とするデータロガーの作製を目指しております.

 アナログピンから電圧データを取り込み,シリアルウィンドウにテキストデータで表示します.
 サンプリング時間はdelay関数で設定しています.
 しかしながら,下記に示すプログラムではdelay関数が正確に動作しません.
 delay(1000)では1秒刻みで動作しているようなのですが,遅延時間をこれより小さくすると指定した遅延よりさらに遅くなります.
 arduinoで時間分解能が正確(サンプリング周波数が100~1kHz程度)なデータロガーを作ることは可能なのでしょうか.

ソースコード―――――――――――――――――――――――――――――――――――
const int BUTTON = 9;
int indata, val=0, sno=0;
float stress;  //入力信号は圧力センサの電圧値

void setup(){
  Serial.begin(9600);
    pinMode(BUTTON, INPUT);
}

void loop(){
  val = digitalRead(BUTTON);  //スイッチを押すと取り込み開始
  if(val == LOW){
      return;
  }
  else{  
  indata = analogRead(0);
  stress = indata * 5;
    sno++;  //データ数を確認しやすくするため,各データにシリアル番号を付ける
    Serial.print(sno);
      Serial.print(",");
  Serial.println(indata);
  delayMicroseconds(5000);
}
}

試したこと―――――――――――――――――――――――――――――――――――
 例えば,delay(500)の場合,ループ回数は10秒間で18回程度,delay(100)では80~90回程度となります.
 とりあえず遅延時間を小さくした場合,最大で360回程度(10秒間当たり)になります.
 一方で,delayMicroseconds()を用いた場合,ループ回数は増加するのですが,遅延時間を変更しても一様に1200回程度(10秒間当たり)になります.
 単純に考えれば,delayMicroseconds()では1秒間当たり100回以上ループしているので,delay(100)でももう少し正確に動作してもよい気がするのですが,そういうものではないのでしょうか.

補足情報―――――――――――――――――――――――――――――――――――
 言語:スケッチ
 使用ハード:arduino uno

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

delay(), delayMicroseconds()の精度の問題もあると思いますが、loop() の中で何かのアクション後に一定時間次のアクションを無効化する場合 millis() で時間計測を行うのが一般的だと思います。
理由は主に次の2点です。

  1. 監視対象の入力ポート(例えばボタン)が複数あるループ監視処理に対応できない。例えばBUTTON-A、BUTTON-Bがあり、それぞれが押されたらLED-A、LED-Bを点灯し、10秒後に消灯というループを考えたとき、もしBUTTON-AがHIGH -> LED-A点灯 -> delay(10000) としてしまうと、delay()中にBUTTON-BがHIGHになっても検出できない。
  2. 入力イベント(例えばボタン=HIGH)を検出してから、delay() をコールするまでの処理時間はゼロではないため、delay(10000) のように固定値をセットしてしまうと、その処理時間分の遅延がループごとに累積することで、実際の時刻系と差異が発生してしまう。

millis() によるシステム時間を使ったループは例えば以下のようになります。

#define MILLISECONDS_TO_WAIT 500
unsigned long time_zero = millis();
boolean button_is_high = false;

void loop() {
  if (!button_is_high) {
    if (digitalRead(BUTTON) == HIGH) {
      button_is_high = true;
      time_zero = millis();
      indata = analogRead(0); 
      stress = indata * 5; 
      sno++;  //データ数を確認しやすくするため,各データにシリアル番号を付ける 
      Serial.print(sno); 
      Serial.print(","); 
      Serial.println(indata); 
    }
  }
  if (button_is_high) {
    if (millis() - time_zero > MILLISECONDS_TO_WAIT) {
      button_is_high = false;
    }
  }
}

delay() は一般的に、外部デバイスへの出力ピンにシグナルした後で入力ピンからシグナルを検出する時に、デバイス側の制約によって数ミリ秒経過後でないと入力シグナルが安定しないので、ほんの少し WAIT させる、というような場合に使用されます。delay() の使い方については公式ドキュメントにも以下の注意書きがあります。

delay()を使えば簡単にLEDをチカチカさせることができます。また、スイッチのバウンス対策のためにdelay()を使っているスケッチもよく見られます。ただし、こうしたdelay()の使い方には不利な点があります。delay()の実行中は、計算やピン操作といった他の処理が実質的に止まってしまうのです。delay()の代わりにmillis()を使って時間を測り、タイミングをコントロールするほうがいいでしょう。熟練したプログラマーは、よほどスケッチが簡単になる場合を除き、10ms以上のイベントのコントロールにdelay()を使うことは避けるでしょう。 

ご参考になれば。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/11 20:25

     詳細にご教授いただき誠にありがとうございます.
     これまで,delay関数とmillis関数の違いに関して特に意識しておらず,大変勉強になりました.
     また,プログラムの方も添削していただき重ねて御礼申し上げます.
     ちなみに作成いただいたプログラムに関して一点質問がございます.
     直していただいたプログラムの5,7行目にて”!”や”true”を用いた構文に変更いただいておりますが,これも何かしらの理由があるのでしょうか.
     millis関数を使う上で,このような構文にしたいただいたのでしょうか.

    キャンセル

0

Delay を使う事の是非に関しては、tkanda さんが書いていらっしゃるので、
>arduinoで時間分解能が正確(サンプリング周波数が100~1kHz程度)な
>データロガーを作ることは可能なのでしょうか. 
分解能と、精度の違いについて理解していますか?
目標とする、周期が、100Hz~1KHz となっていますが、
安定度、精度、温度変化に対してはどの程度を目安としていますか?
単に、趣味の物、普通のデータロガー、計量検定機器程度、精密計測機器
目指すところによって、使用する技術の適否があります。
各部品においては、温度係数や、温度による精度があります。
一般的なマイコンに使われる、xtal やレゾネータの精度は高くありません。
⇒なので、RTCが無い場合時計の精度が出ない、有っても月差±十数秒等は、当たり前
 月差±数秒を望むと途端に環境と価格の面で厳しくなります。
 PCなどで、データロガーを作成する場合は、時刻の担保を考えます。
 RTC毎に時計のズレが異なりますので、RTCの補正機能が付いているものもあり、
 補正機能が無い場合は、時刻の合わせ込機能をプログラムで実装したりします。

RC発信程度で済む。:精度、安定度この程度で十分。
            安い発信器モジュールと、マイコンのプリスケーラを使います。
発振器 の精度の良い物を使って足りる:このレベルで収めないと、
             発振器だけで済まず高価になります。
発振器 の精度の良い物でも足りない。
温度管理された環境が用意できて、費用は掛かっても良い。

ソフトウェア的には、
例えば、100Hz を担保する場合は、
100Hz の間に、最低2回、もしくは、3回以上計測を行います。
値の処理としては、各種平均処理有無、変化量による除外処理等を考慮します。
定周期計測を行う場合は、割込み機能を使い、ポーリングの使用は避けます。
ポーリングで行うのは、割込みルーチンの結果を処理したり、
上位との通信処理や、定周期でなくても良い処理です。
割込みラインを使う場合、プリスケーラを使う場合で異なりますが、
プリスケーラを使う場合は、目的とする周期の10~100倍の
信号を入れて、割込みを発生させます。
⇒232c/422 のプリスケーラ用の周波数や、時計のクリスタルが中途半端な数字な理由を考えてみて下さい。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/11 22:13

     詳細な解説をいただき誠にありがとうございます.

     現在,普通のデータロガー程度の性能を目指しております.
     必要な分解能は標本化定理とこれまでの経験則から100~1kHz程度と考えております.
     測定は長くとも数十分程度を考えており,月差数十秒までの精度は必要ありません.精度は±10μsほどで問題ないかと考えております.
     測定環境も室温であり高温や大きな温度変化は無いため,温度変化は特に意識しておりませんでした.
     よって,外付けで水晶振動子やRTCモジュールがあれば十分でしょうか.現在,別件でRTCモジュール(DS1307)も購入したので,こちらの利用も考えております.
     また,「100Hz の間に、最低2回、もしくは、3回以上計測を行います。」とのことですが,これはつまり,最低でも200Hz,もしくは300Hzのサンプリングが必要ということでしょうか.
     ソフトウェア的な開発(割り込み処理や平均処理有無,除外処理等)に関しては,未だ噛み砕けていない状態です.こちらに関してはもう少々時間をかけて理解を進めていきたいと考えております.

    キャンセル

  • 2016/05/12 05:49 編集

    簡単な処では、三菱、オムロン、キーエンスのPLC用の、
    アナログ入力モジュールの仕様、機能や
    データロガーなどから、調べてみてください。
    データロガーでは、
    ノイズを含めた、生値が欲しい場合
    各種平均値が欲しい場合
    変化量を逸脱した値は除外したい場合
    などが有ったりします。
    ⇒計測時に行うのか、後処理で行うのかは、システムの考え方次第。
     短時間での計測では、単純に生値を取得して、後処理で対応が多い筈です。

    計測時間が数十分であれば、数百円のモジュールでも
    気付く程のズレは出ないと思います。
    ズレがばれるのは、積算入力、時間積算、
    アナログ値⇒積算化がある場合です。

    >これはつまり,最低でも200Hz,もしくは300Hzのサンプリングが
    >必要ということでしょうか
    考え方と、仕様書の書き方次第になると思います。
    >標本化定理とこれまでの経験則
    であれば、必要無いと思われます。後処理をするのですよね?
    '
    RTC:DS1307
    https://www.maximintegrated.com/jp/products/digital/real-time-clocks/DS1307.html
    ついでに、
    データロガーIC
    https://www.maximintegrated.com/jp/products/digital/data-loggers.html

    開発中、機能テストなどで、I2Cのチップでアドレス
    が同じ物を、どうしても使わなければならない場合は、
    I2CマルチプレクサというICもあったりします。

    キャンセル

  • 2016/05/21 23:09

     返信いただきありがとうございます.
     確かに,製品化されているデータロガーのデータシート等を見て評価項目を知ることで,作製に当たりどのような情報が必要になるか勉強できそうです.
     確認してみます.

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Arduino

    552questions

    Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。