delayMicrosecondsをより正確にできますか?


8

私はDMXデータをビットバンにしようとしています、そしてそれは4usパルスを必要とします。Arduinoの遅延がどれほど優れているかを確認するために確認している結果にはあまり運がありません...かなりひどいようです。

ここに私がした簡単な小さなテストがあります:

unsigned long ptime;

void setup() {
  Serial.begin(9600);
}

void loop() {
  ptime = micros();
  delayMicroseconds(4);
  Serial.println(micros() - ptime);

  delay(1000); //just to keep the serial monitor from going nuts
}

そして結果:

8 4 8 4 4 4 4 4 8 8 8 8 4 8 8 4 4 8 4 4 4 8 8 8 4 8 4

精度の悪さにちょっとショックを受けました。それは私が遅らせたかった時間の2倍ですが、2で割ることができるところにさえ一貫していません!

正確で一貫した結果を得るために何かできることはありますか?


なぜUARTに直接アクセスする代わりにビットバンギングをするのですか?
Ignacio Vazquez-Abrams

だから私は複数の出力を持つことができます。
bwoogie 2017

Megaには4つのUARTがあります。プログラミングのために1つを永久に保持している場合でも、3つのユニバースを提供します。
Ignacio Vazquez-Abrams

私はちょうどそれは私が現在利用できる持っているものだから、最終的なプロジェクトはATMEGA328を持っていますメガでテストしています
bwoogie

1
ここでの問題は、測定方法です。
Gerben

回答:


7

前の回答で説明したように、実際の問題はの精度でdelayMicroseconds()はなく、の解像度です micros()

ただし、実際の質問に答えるには、より正確な代替手段がdelayMicroseconds()あります_delay_us()。AVR-libcの関数はサイクルに正確であり、たとえば

_delay_us(1.125);

それが言うことを正確に行います。主な注意点は、引数はコンパイル時の定数でなければならないということです。あなたはする必要があります#include <util/delay.h>。この機能にアクセスするために。

また、何らかの正確な遅延が必要な場合は、割り込みをブロックする必要があることにも注意してください。

編集:例として、PD2(Megaのピン19)で4 µsのパルスを生成する場合、次のようにします。まず、次のコードに注意してください

noInterrupts();
PORTD |= _BV(PD2);   // PD2 HIGH
PORTD &= ~_BV(PD2);  // PD2 LOW
interrupts();

0.125 µsの長いパルス(2 CPUサイクル)を生成しますLOW。これは、ポートを設定する命令の実行にかかる時間だからです。次に、不足している時間を遅延で追加します。

noInterrupts();
PORTD |= _BV(PD2);   // PD2 HIGH
_delay_us(3.875);
PORTD &= ~_BV(PD2);  // PD2 LOW
interrupts();

また、サイクルに正確なパルス幅があります。digitalWrite()この関数の呼び出しには約5 µsかかるため、これをで実現できないことは注目に値します。


3

テスト結果は誤解を招く可能性があります。 delayMicroseconds()実際にはかなり正確に遅延します(2または3マイクロ秒を超える遅延の場合)。/usr/share/arduino/hardware/arduino/cores/arduino/wiring.c(Linuxシステムの場合、または他のシステムの同様のパス)でソースコードを調べることができます。

ただし、の分解能micros()は4マイクロ秒です。(例えば、およそgarretlabページmicros()。)したがって、あなたは読書見ることはありませんとの間に 4マイクロ秒と8マイクロ秒。実際の遅延は4マイクロ秒のほんの数サイクルである可能性がありますが、コードはそれを8として報告します。

delayMicroseconds(4);(ループを使用するのではなく、コードを複製することにより)10または20の呼び出しを続けて実行し、の結果を報告し micros()ます。


4の10件の遅れで、私は32個の28年代の混合物を取得しています...しかし、= 40 4×10
bwoogie

たとえば、5の10遅延で何が得られますか?:)また、ビットバンギングの場合digitalWrite()、実行に数マイクロ秒かかるかなりダイレクトなポートアクセス、つまりを使用する必要がある場合があります。
ジェームズウォルドビー-jwpat7 2017年

40&44 ...しかし、切り上げではないでしょうか。ここで何が欠けていますか?
bwoogie 2017

「切り上げ」とはどういう意味delayMicroseconds()ですか?四捨五入するよりも良いとは思いません。¶不正確な原因について、ルーチンがインライン化される場合、タイミングは周囲のコードに依存します。あなたは見るためにアセンブリまたは分解リストを読むことができます。(Arduino Mega 2560のPORTBと同等の質問に対する私の回答の「アセンブリリストの作成」セクションを参照してください。これはいずれにしても、ビットバンギングプロジェクトに関連している可能性があります
James Waldby-jwpat7

2

Arduinoの遅延がどれほど優れているかを確認しています...かなりひどいようです。

micros()有してよく文書 4マイクロ秒の解像度を。

タイマー0のプリスケーラーを変更することで、解像度を向上させることができます(もちろん、これは数値をスローしますが、それを補正することができます)。

あるいは、プリスケーラが1のタイマー1またはタイマー2を使用して、62.5 nsの分解能を実現します。


 Serial.begin(9600);

とにかく遅くなるだろう。


8 4 8 4 4 4 4 4 8 8 8 8 4 8 8 4 4 8 4 4 4 8 8 8 4 8 4

出力はmicros()、タイミングを開始した正確なタイミングに応じて、2つの「ティック」と1つのティックを取得するという事実と相まって、4 µsの解像度と正確に一致しています。


あなたのコードは測定エラーの興味深い例です。delayMicroseconds(4);4 µs近く遅延します。しかし、それを測定しようとするあなたの試みは誤りです。

また、割り込みが発生すると、間隔が少し伸びます。正確な遅延が必要な場合は、割り込みをオフにする必要があります。


1

オシロスコープで測定すると、次のことがわかりました。

delayMicroseconds(0)= delayMicroseconds(1)= 4μsの実際の遅延。

したがって、35μsの遅延が必要な場合は、次のものが必要です。

delayMicroseconds(31);

0

正確で一貫した結果を得るために何かできることはありますか?

Arduinoの実装は非常に一般的であるため、一部のアプリケーションでは効果的でない場合があります。短い遅延にはいくつかの方法があり、それぞれ独自の不足があります。

  1. nopを使用します。それぞれが1つの命令なので、16分の1です。

  2. tcnt0を直接使用します。プリスケーラーが64に設定されているため、それぞれ4usです。プリスケーラーを変更して、16番目のus分解能を達成できます。

  3. ティックを使用すると、systickのクローンを実装し、遅延の基準として使用できます。より細かい解像度と精度を提供します。

編集:

次のブロックを使用して、さまざまなアプローチの時間を計りました。

time0=TCNT0;
delay4us();             //65
//t0delayus(4*16);          //77
//_delay_us(4);             //65
//delayMicroseconds(4);     //45
time1=TCNT0 - time0;        //64 expected

その前に、timer0プリスケーラーを1:1にリセットしていたので、各TCNT0ティックは1/16マイクロ秒です。

  1. delay4us()はNOP()から構築されます。65ティックまたは4マイクロ秒を少し超える遅延が発生しました。
  2. t0delayus()は、timer0遅延から構築されます。77ティックの遅延が発生しました。delay4us()より少し悪い
  3. _delay_us()はgcc-avr関数です。delay4us()と同等のパフォーマンス
  4. delayMicroseconds()は45ティックの遅延を生成しました。arduinoがそのタイミング関数を実装した方法では、他の割り込みがある環境でない限り、過小評価される傾向があります。

それが役に立てば幸い。


予想される結果は64ではなく65ティックTCNT0です。これは、読み取りに1 CPUサイクルかかるためです。
エドガーボネット2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.