arduino:delaymicroseconds()

delayMicroseconds()関数はどのように機能しますか。私が理解したところによると、timer0のプリスケーラは64に設定されています。16MHzクロックの場合、カウントあたり4.0uSになります。 1uS間隔に到達するための計算に少し混乱していますか?

コメント

  • ドキュメントによると "この関数は、3マイクロ秒以上の範囲で非常に正確に機能します。 delayMicrosecondsがより短い遅延時間で正確に実行されることを保証することはできません。" micros()のドキュメントには " 16 MHz Arduinoボード(DuemilanoveやNanoなど)では、この関数の解像度は4マイクロ秒です(つまり、返される値は常に4の倍数です)。"
  • electronics.stackexchange.com/q/22584/2191
  • も参照してください。

回答

この関数のソースコードはかなりよく文書化されており、/ usr / share / arduino / hardwareにあります。 Linuxシステムでは/arduino/cores/arduino/wiring.c。 Windowsシステムには、wiring.cファイルへの同様のパスがあります。ファイルを見つけて閲覧するように努力してください。今のところ、この単一の関数に焦点を当てるだけで、他の機能に依存しません。

コードを調べると、タイマーではなく、命令サイクルがすべてであることがわかります。このコードは、ライブラリの開発者とまったく同じコンパイラ最適化に大きく依存しています。その作者の仮定!各命令によって「消費」されたCPUサイクル数は、 AtmelAVR命令セットドキュメントに詳しく記載されています。

最初に、遅延値は次のとおりです。 1に等しいかどうかがチェックされ、その場合は、CPU時間のマイクロ秒を超えてすでに費やされたルーチンから戻るだけです。

次に、遅延値に4を掛けます(<<=2)。 __asm__ループは、4CPUサイクルのループにコンパイルされます。 4サイクル×4 = 16サイクル。 16MHz /(4×4)= 1MHz、これには1 usのサイクル時間がかかり、必要な解像度です。

最後の-2マイクロ秒(ループが開始される前)は、コンパイラの修正です。オーバーヘッドが導入されました。 Cから__asm__コードを呼び出すには、CPUレジスタを保存するための追加の命令が必要です。

通常のArduino @ 16MHzの場合、次のコードのみがコンパイルされます。

/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ void delayMicroseconds(unsigned int us) { // calling avrlib"s delay_us() function with low values (e.g. 1 or // 2 microseconds) gives delays longer than desired. //delay_us(us); // for the 16 MHz clock on most Arduino boards // for a one-microsecond delay, simply return. the overhead // of the function call yields a delay of approximately 1 1/8 us. if (--us == 0) return; // the following loop takes a quarter of a microsecond (4 cycles) // per iteration, so execute it four times for each microsecond of // delay requested. us <<= 2; // account for the time taken in the preceeding commands. us -= 2; // busy wait __asm__ __volatile__ ( "1: sbiw %0,1" "\n\t" // 2 cycles "brne 1b" : "=w" (us) : "0" (us) // 2 cycles ); } 

BTW:コンパイルされたコードはかなり正確ですが、次の点に注意してください。Arduinoには、ほとんどの人が気付かないタイミング割り込みが設定されています。 delayMicroseconds()の実行中に割り込みを受信すると、delayMicroseconds()のタイミングが間違ってしまいます。もちろん、delayMicroseconds()を呼び出す前に割り込みを停止し、後で有効にすることもできますが、これも、有効/無効にするためにコンパイルされたコードの期間によってタイミングの精度に影響を与えます。

コメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です