Arduino:比 micros() 更好的微秒分辨率?

电器工程 Arduino 定时
2022-01-27 04:18:57

micros() 文档指出,返回值始终是 4 的倍数。

有没有办法获得更高分辨率的微秒点击,最好是 1 微秒级别?

下降到 AVR 级别是可以接受的。

3个回答

是的,取决于您的 Arduino 的基本时钟频率。例如,这里是 ATMega2560 的计数器 2 和 16MHz 的基本时钟速率在预分频后的计数器定时器输入频率和周期。定时器内置“预分频器”值选项,用于确定频率/周期,如下表所示:

    TCCR2B bits 2-0    Prescaler    Freq [KHz], Period [usec] after prescale
          0x0          (TC stopped)      --         --
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000

为了获得更好的时序分辨率,您可以使用一个名为 TCNT2 的值。因为定时器是 8 位的,所以内置计数器从 0 到 255。当计数器达到 TCNT2 分配的值时,它会触发中断。此中断称为 TIMER2_OVF_vect。

鉴于此信息,产生的中断率将是:16MHz / (预分频器 * (255 - TCNT2))

您可以让计时器以全速 16MHz(62.5nSec)运行,但这比您需要的要快得多;初始计数为 (255-2) 的 2MHz 将为您提供 1MHz 的中断率。在您的 ISR 中将其除以 2:

extern uint32_t MicroSecClock = 0;

ISR(TIMER2_OVF_vect) {// this is a built in function that gets called when the timer gets to the overflow counter number
  static uint_8 count;            // interrupt counter

  if( (++count & 0x01) == 0 )     // bump the interrupt counter
    ++MicroSecClock;              // & count uSec every other time.

  digitalWrite(53,toggle);// pin 53 is arbitrary
  TCNT2 = 253;                    // this tells the timer when to trigger the interrupt. when the counter gets to 253 out of 255(because the timer is 8 bit) the timmer will trigger an interrupt
  TIFR2 = 0x00;                   // clear timer overflow flag
};

MCU 的数据表是基本资源;这篇文章会给你(也给了我!)一个良好的开端。

如果下降到 AVR 级别是可以接受的(正如您在问题中提到的那样),您可以设置一个计时器,甚至获取 AVR 时钟的滴答声。

您需要参考 AVR 的数据表,因为它在不同的 ATMegas 和 ATTinys 中有所不同。但是程序总是一样的。你需要做的是:

  • 决定使用哪个预分频器(例如将其设置为 1,即如果您想要实际的 CPU 时钟速度则不进行预分频),请参阅 TCCR 文档
  • 设置定时器溢出中断、中断处理程序并全局激活中断
  • 激活定时器/计数器控制寄存器中的定时器TCCR

这样可以从定时器寄存器中获取准确的滴答声,但是您需要手动计算溢出。这在技术上是尽可能精确的。

这是过时的 AT90S2313 的一些示例代码,但它为您提供了很好的基本提示:

/* uC: AT90S2313 */
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
  // set up timer 0
  TCCR0 = (1<<CS01); // Prescaler 8

  // enable overflow interrupt
  TIMSK |= (1<<TOIE0);

  // activate interrupts
  sei();

  while(1)
  {
     /* Do whatever you like */
  }
}


ISR (TIMER0_OVF_vect)
{    
   /*
      This gets called everytime there in an overflow in the timer register  
   */
}

马克,我决定编写一组新的函数,基于 Arduino Atmega328 Timer2,并使用溢出中断,以达到 0.5us 的精度。我的代码可在此处下载和使用:

http://electricrcaircraftguy.blogspot.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html

这里有一个简短的描述:“我写了一个“库”来在“micros()”替换函数上获得 0.5us 的精度,这样我就可以在 1us 内获得读取 PWM 或 PPM 信号的可重复结果。我在周围搜索了互联网上找不到类似的东西(或者易于使用,并保持了 Arduino 通过伺服库编写 PWM 信号的能力),所以我认为这是我对 Arduino 和无线电控制世界的第一个重大贡献。”