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


11

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

有什么方法可以获得更高分辨率的微秒点击,最好降至1微秒级别?

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


1
当我提出完全是英文的问题时,为什么还要坚持用标签开头?
stevenvh 2011年

4
抱歉,史蒂文,我真诚地认为(并认为)这是一种简洁明了地表达问题的好方法。对此进行了很多讨论,Jeff在某些情况下同意这是一种很好的提问方式。讨论在这里;热图使我确信,对于这些类型的问题,必须强调操作环境。meta.stackexchange.com/questions/10647/writing-good-titles / ... 但是,出于对您出色答案的尊重,如果您认为最好,我很乐意将其改回。
马克·哈里森

是否可以将其用于pulsein()函数?我需要以不到1微秒的分辨率测量脉冲长度。

此空间保留用于顶部回答问题。如果您有什么要问的,请提出自己的问题。
Olin Lathrop

Answers:


9

是的,取决于您的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的数据表是基本资源;本文将为您(并给我!)提供良好的起点。


4

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

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

这里是一个简短的描述:“我编写了一个“ libary”,以便在“ micros()”替换函数上获得0.5us的精度,这样我就可以在1us内读取PWM或PPM信号获得可重复的结果。互联网,找不到可比的东西(或易于使用,并保持了Arduino通过Servo Libary编写PWM信号的能力),因此我认为这是我对Arduino和Radio Control的第一项重大贡献。”


3

如果降到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  
   */
}

感谢FeeJai。我可以在Arduino草图的上下文中设置这些中断吗?
马克·哈里森

1
我对arduino框架不熟悉。但是,如果它没有在内部设置所有计时器,那么您当然可以。否则,您仍然可以读取计时器寄存器并自己计算。
FeeJai 2011年

是的,您正在使用Arduino中的完全C ++编程,并且可以使用所有寄存器和符号,例如TIMSKTOIE0(从atmega328p数据表中复制计时器设置)。看来您不能使用ISR()宏,而应使用arduino.cc/en/Reference/AttachInterrupt
joeforker
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.