millis()を使用したArduinoの時間維持は正確または正確ではありませんか?


9

私はArduinoを使用していくつかのデータを記録しています。Arduinoのスケッチでは、このmillis()関数も使用したので、測定している各値が取得された時間を追跡できます。しかし、タイミングがおかしいことに気づきました。たとえば、実際の30秒は、10秒(構成例)としてのみ出力されます。

Arduinoの遅延機能が使用時間の維持に影響を与えると言ってmillis()いいのですか?言い換えると、50ミリ秒の遅延があると仮定すると、millis()関数はその期間も停止し、接続が継続するまで継続するということですか?いくつかのデータをプロットしてみたところ、経過時間を考えるとデータのピークの頻度が高すぎることがわかりました。それで、それがこのタイミングのミスマッチの理由であるかどうかを知りたいのですが、そうであれば、各サンプルが発生する時間を維持できるようにこれを修正するにはどうすればよいですか?

ここにいくつかのコンテキストを与えるために私のスケッチです:

#include <eHealth.h>    

unsigned long time;
// The setup routine runs once when you press reset:
void setup() {
  Serial.begin(9600);  
}

// The loop routine runs over and over again forever:
void loop() {

  float ECG = eHealth.getECG();
  time = millis();
  Serial.print(time);
  Serial.print(" ");
  Serial.print(ECG, 5); 
  Serial.println("");    

  delay(50);
}

公式のUnoボードを使用していますか?
Peter Bloomfield 2014年

1
作成された値ではなく実際のタイミング(ラインにタイムスタンプを付けるシリアルモニターが理想的)は、おそらく何が起こっているのかを理解するのに役立ちます。
Ignacio Vazquez-Abrams 2014年

3
の計算millis()は割り込み駆動であるため、delay()影響はありません。
microtherion 2014年

私は同じ問題を抱えていますが、それを複雑なコードに統合(millis())したときだけです。コードの複雑さは、コードの複雑さによって遅延がますます長くなるように、その精度に影響を与えると思います。これを回避する方法はありますか?分離したRTCモジュールを使用しているのでしょうか?
Josip7171 2016年

回答:


10

millis()割り込み駆動であるためdelay()、少なくともATmegaベースのボードでは影響を受けません。

それがmillis()完全に正確であると言っているのではありません。タイマーの各ティックは正確に1msではなく、1.024msです。このエラーは、修正が行われるまで徐々に蓄積されます。これは、TIMER0_OVF(タイマー0オーバーフロー)割り込みハンドラーの実装で確認できます。

不正確さのもう1つの原因は、正確に16MHzではない発振器/水晶自体です。それはかなり近いですが、温度があまり変化しない限り、比較的安定しています。

上記は、を使用すると約1msアウトになる可能性があることを意味しますmillis()。これはあなたの問題のようには聞こえません。

別の潜在的な問題は何getECG()をしているのでしょう-それは非常に遅いかもしれません。

float eHealthClass::getECG(void)
    {
        float analog0;
        // Read from analogic in. 
        analog0=analogRead(0);
        // binary to voltage conversion
        return analog0 = (float)analog0 * 5 / 1023.0;   
    }

analogRead() 遅いですが、このようなループに影響を与えるほど遅くはありません。

私が見たもう1つの問題は、クロック速度を変更しても、boards.txtを正しく変更しない場合です。これは、millis()実装で使用される定数が間違っていて、時間が間違っていることを意味します。

実際に50ミリ秒ごとに値を読み取りたい場合、これを実装するはるかに良い方法は、次のようにすることです

static long lastUpdate;

if (millis() - lastUpdate > 50)
{
    lastUpdate = millis();
    //Do stuff
}

取得しているタイムスタンプを確認する必要があります。実際に30が10として表示されている場合は、他に何か問題があります。


2
Unoの場合、クロックは水晶駆動ではなく、水晶よりも精度の低いセラミック共振器を使用することに注意してください。
jfpoilpret 2014年

@jfpoilpret知っておくと便利です。 回路図を見ると、これはCSTCE16M0V53-R0 Murata CERALOCKデバイスになります。
Chris O

レゾネーターは初期許容差(多くの場合0.5-2%)と温度安定性が低くなりますが、使用時にタイミングループを調整すると、温度が変動しない限り問題はありません。
Cyber​​gibbons 2014年

2
Millis()は引き続き1.024msごとに刻むタイマーで機能しますが、エラーメーター変数が高くなりすぎるたびにインクリメントする形でエラー補正を追加しました。それは実際にはRoman Blackのアルゴリズムだと思います。そのため、タイミングは正確に1msにかなり近くなるはずです。github.com/arduino/Arduino/blob/master/hardware/arduino/cores/…–
EternityForest

まだ興味がある人は、JRobertの回答に投稿したコメントを参照してください。自分の回答がないため、自分の回答で返信したくありませんでした。問題を言い換えたところです。
user3284376 2014年

2

eHealth.getECG()呼び出し時間のかなりの部分で割り込みがオフになっている場合、millis()のカウントが遅れる可能性があります。それ以外の場合は、millis()説明した3xエラーよりもはるかに正確な時刻を返します。

サンプリングした信号の周波数が予想よりも高いように見えましたが、これは、サンプルレートが意図したよりも低い場合に発生する可能性があります。20Hzのサンプルレートを想定していますか?ループは50ミリ秒よりかなり長くかかる可能性があります。これは、印刷された時間に表示されますが、それらは依然としてクロック時間を追跡するはずです。これを考慮しなかったがサンプルあたり50ミリ秒と想定すると、データの見かけ上の速度が向上します。

これが問題ではない場合、次のステップは、にいる間に出力を切り替え、loop()周波数計(一部の安価なDVMがこれを実行できる)または「スコープ」を使用して、結果の方形波の周波数を測定することです。空ので同じことをしますloop()。最初の実験は、実際のサンプリングレートまたは間隔になります。2番目はmillis()、(つまり、timer0の周波数)が期待どおりかどうかを示します。


1
私はそれをさらにいじってみましたが、問題はArduinoにあるのではなく、ほとんどの場合millis()関数は非常にうまく機能することに気づきました、値のいくつかは正確に8ms(遅延)あなたはそれが予想されることであると言いました。私が説明した3xエラーは、データを受信するために使用しているPython側にも当てはまります。その結果が何であるかについての考えは、私はPythonのpyserialを使用していて、地獄のように遅いです。
user3284376 2014年

私はあなたの実装について1/2 @以上の推測を与えるほど十分に知りませんが、Python側はサンプルを落とすのに十分遅いですか?
JRobert 2014年

0

こっちも一緒。割り込みがオフになっている場合、測定される時間は「リアルタイム」であると付け加えることができます。とにかく、なぜこの遅延が発生するのか理解できません。ループに時間がかかりすぎる場合は、いずれにしてもmillis()がリアルタイム値を返す必要があるためです(各値間の距離が長い場合のみ)。


1
「ここで同じ」とはどういう意味ですか?StackExchangeは(フォーラムとは異なり)順序を変更できるため、回答はそれ自体で成り立つ必要があります。したがって、「ここに同じ」とは、あなたの回答がその下に表示される返信/質問に応じて何でも意味する可能性があります。
Nick Gammon

この投稿はコメントとしてより適切ですが、(確かに)十分な評判はありません。
Greenonline、2015

申し訳ありませんが、私が何かに答えるとき、それがメインの投稿を参照していることは明らかですが、そうでない場合はコメントになります
user48711
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.