delayMicroseconds() 函数是如何工作的。据我了解,timer0 的预分频器设置为 64。对于 16MHz 时钟,每次计数为 4.0uS。我对达到 1uS 间隔的数学有点困惑?
arduino:延迟微秒()
电器工程
Arduino
计时器
2022-01-13 10:10:33
1个回答
这个函数的源代码有很好的文档记录,可以在 Linux 系统的 /usr/share/arduino/hardware/arduino/cores/arduino/wiring.c 中找到。Windows 系统将具有类似的 wiring.c 文件路径。努力找到文件并浏览它。现在只关注这个单一的功能,它不依赖任何其他功能。
通过检查代码,您会注意到它与计时器无关,而是与指令周期有关。代码在很大程度上依赖于编译器优化,这对您和库的开发人员来说是完全相同的。这是作者的假设!Atmel AVR 指令集文档中详细记录了每条指令“烧毁”的 CPU 周期数。
首先检查延迟值是否等于 1,在这种情况下,只是从已经花费超过一微秒 CPU 时间的例程返回。
然后延迟值乘以四 ( <<=2
)。-loop 编译成一个 4 CPU 周期的__asm__
循环。4 个周期 × 4 = 16 个周期。16MHz/(4×4) = 1MHz,需要 1us 周期时间,即我们所追求的分辨率。
最后的 -2 微秒(在循环开始之前)再次修正了编译器引入的开销。从 C调用__asm__
-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()
并在之后启用它们,但这会再次通过编译代码的启用/禁用持续时间影响时序准确性。
其它你可能感兴趣的问题