delayMicroseconds()関数の仕組み 私が理解したところによると、timer0のプリスケーラーは64に設定されています。16MHzクロックの場合、カウントあたり4.0uSを与えます。私は数学で1uS間隔に到達するのに少し混乱していますか?
delayMicroseconds()関数の仕組み 私が理解したところによると、timer0のプリスケーラーは64に設定されています。16MHzクロックの場合、カウントあたり4.0uSを与えます。私は数学で1uS間隔に到達するのに少し混乱していますか?
回答:
この関数のソースコードはかなり文書化されており、Linuxシステムの/usr/share/arduino/hardware/arduino/cores/arduino/wiring.cにあります。Windowsシステムには、wiring.cファイルへの同様のパスがあります。ファイルを見つけてそれをブラウジングする努力をしてください。現時点では、この単一の機能にのみ焦点を当てていますが、他の機能には依存していません。
コードを調べると、それはタイマーではなく、命令サイクルに関するものであることがわかります。このコードは、コンパイラーの最適化がライブラリの開発者とまったく同じであることに大きく依存しています。その作者の仮定!各命令によって「消費された」CPUサイクルの数は、Atmel AVR命令セットのドキュメントに詳しく記載されています。
最初に、遅延値が1に等しいかどうかがチェックされます。この場合、マイクロ秒のCPU時間をすでに費やしているルーチンから戻るだけです。
次に、遅延値に4を掛けます(<<=2
)。__asm__
4 CPUサイクルループに-ループコンパイル。4サイクル×4 = 16サイクル。16MHz /(4×4)= 1MHz、これは1 usのサイクルタイム、つまり私たちが求めている解像度です。
最後の-2マイクロ秒(ループが開始される前)は、コンパイラーによって導入されたオーバーヘッドの修正です。__asm__
Cから-codeを呼び出すには、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
);
}
ところで:コンパイルされたコードはかなり正確ですが、次の点に注意してください:Arduinoでは、ほとんどの人が気づいていない時間割り込みが構成されています。実行中に割り込みを受けたdelayMicroseconds()
場合、タイミングがずれdelayMicroseconds()
ます。もちろん、呼び出す前に割り込みを停止delayMicroseconds()
し、後で有効にすることもできますが、これも有効化/無効化のためのコンパイル済みコードの持続時間によってタイミングの精度に影響を与えます。
micros()
は、「16 MHz Arduinoボード(DuemilanoveやNanoなど)では、この関数の解像度は4マイクロ秒です(つまり、返される値は常に4の倍数です)。」