Arduino Nano计时器

CL2*_*L22 6 avr atmega timer arduino atmel

我想了解更多有关Arduino Nano计时器的信息.

  1. 那里有什么计时器?
  2. 他们会产生中断吗?
  3. 什么代码会为它们附加中断处理程序?
  4. 如何delay()delayMicroseconds()实施...
    • 他们使用定时器中断吗?(如果是这样,我怎么能在此期间执行其他代码?)
    • 或者他们反复轮询直到计时器达到某个值?
    • 或者他们增加值X次?
    • 或者他们以另一种方式做到了吗?

ang*_*rge 18

考虑Arduino Nano定时器的最佳方法是考虑底层芯片中的定时器:ATmega328.它有三个定时器:

  • 定时器0:8位,PWM片内引脚11和12
  • 定时器1:16位PWM片内引脚15和16
  • 定时器2:8位PWM片内引脚17和5

所有这些定时器都可以产生两种中断:

  • 当定时器值(加到定时器的每个节拍中)达到定时器寄存器中的比较值时,会发生"值匹配"中断.
  • 定时器值达到最大值时发生定时器溢出中断

不幸的是,没有Arduino函数可以将中断附加到计时器上.要使用定时器中断,您需要编写稍多的低级代码.基本上,您需要声明一个这样的中断例程:

ISR(TIMER1_OVF_vect) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

这将声明一个服务timer1溢出中断的函数.然后,您需要使用寄存器启用定时器溢出中断TIMSK1.在上面的示例中,这可能如下所示:

TIMSK1 |= (1<<TOIE1);
Run Code Online (Sandbox Code Playgroud)

要么

TIMSK1 |= BV(TOIE1);
Run Code Online (Sandbox Code Playgroud)

这将设置TOIE1TIMSK1寄存器中的(生成timer1溢出中断)标志.假设您的中断已启用,ISR(TIMER1_OVF_vect)则每次timer1溢出时都会调用您的中断.


Arduino delay()函数在源代码(wiring.c)中如下所示:

void delay(unsigned long ms)
{
    uint16_t start = (uint16_t)micros();

    while (ms > 0) {
        if (((uint16_t)micros() - start) >= 1000) {
            ms--;
            start += 1000;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以内部它使用的micros()功能确实依赖于timer0计数.Arduino框架使用timer0来计算毫秒数,实际上,timer0 count是millis()函数获取其值的位置.

delayMicroseconds()另一方面,该功能使用某些适时的微处理器操作来产生延迟; 使用哪个功能取决于处理器和时钟速度; 最常见的存在nop()(无操作)只需一个时钟周期.Arduino Nano使用16 MHz时钟,这是源代码的样子:

// For a one-microsecond delay, simply return. The overhead
// of the function call yields a delay of approximately 1 1/8 µs.
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 proceeding commands.
us -= 2;
Run Code Online (Sandbox Code Playgroud)

我们从中学到了什么:

  • 1μs延迟什么都不做(函数调用是延迟)
  • 较长的延迟使用左移操作来计时延迟.