arduino:延迟微秒()

电器工程 Arduino 计时器
2022-01-13 10:10:33

delayMicroseconds() 函数是如何工作的。据我了解,timer0 的预分频器设置为 64。对于 16MHz 时钟,每次计数为 4.0uS。我对达到 1uS 间隔的数学有点困惑?

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()并在之后启用它们,但这会再次通过编译代码的启用/禁用持续时间影响时序准确性。