Arduino: лучшее микросекундное разрешение, чем у micros ()?

11

В документации micros () указано, что возвращаемое значение всегда будет кратно 4.

Есть ли способ получить микросекундный клик с более высоким разрешением, предпочтительно до уровня 1 микросекунда?

Сброс до уровня AVR является приемлемым.

Марк Харрисон
источник
1
Почему вы настаиваете на том, чтобы начинать свой заголовок с тега, когда я сделал это совершенно английским вопросом?
Стивенвх
4
Извиняюсь, Стивен, я искренне думал (и думаю), что это хороший способ выразить вопрос кратко и ясно. Об этом было много дискуссий, и в некоторых случаях Джефф соглашался, что это хороший способ спросить. Обсуждение здесь; тепловые карты - это то, что убедило меня в том, что для такого стиля вопросов стоит подчеркнуть операционную среду. meta.stackexchange.com/questions/10647/writing-good-titles/… Но, из уважения к вашим превосходным ответам, я был бы рад изменить его обратно, если вы считаете, что это лучше.
Марк Харрисон
Можно ли использовать его для функции pulsein ()? Мне нужно измерить длину импульса с разрешением менее 1 мксек.
Это место зарезервировано для ответов на вопрос сверху. Если у вас есть что спросить, начните свой вопрос.
Олин Латроп

Ответы:

9

Да, в зависимости от базовой частоты вашего Arduino. Например, здесь приведены входные частоты и периоды счетчика таймера после предварительного масштабирования для счетчика-таймера 2 ATMega2560 и базовая тактовая частота 16 МГц. Таймер имеет встроенные опции значений «prescaler», которые определяют частоту / период, показанные в этой таблице:

    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. Существует встроенный счетчик, который идет от 0 до 255, потому что таймер 8 бит. Когда счетчик достигает значения, назначенного TCNT2, он запускает прерывание. Это прерывание называется TIMER2_OVF_vect.

учитывая эту информацию, результирующая частота прерываний будет: 16 МГц / (предварительное масштабирование * (255 - TCNT2))

Вы можете заставить таймер работать на полных 16 МГц (62,5 нсек), хотя это намного быстрее, чем вам нужно; 2 МГц с начальным счетом (255-2) даст вам частоту прерываний 1 МГц. Разделите это на 2 в вашем ISR:

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 является основным ресурсом; эта статья даст вам (и дал мне!) хороший старт.

JRobert
источник
4

Марк, я решил написать новый набор функций, основанный на таймере Arduino Atmega328 Timer2 и использующий прерывания переполнения, чтобы получить точность до 0.5us. Мой код доступен для скачивания и использования здесь:

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

Вот краткое описание: «Я написал« libary », чтобы получить точность 0.5us для функции замены« micros () », чтобы я мог получать воспроизводимые результаты, читая сигнал PWM или PPM, с точностью до 1us. Я искал все вокруг Интернет и не мог найти что-то сопоставимое (или это было легко использовать, и поддерживал способность Arduino писать сигналы ШИМ через Servo Libary), поэтому я думаю, что это мой первый крупный вклад в мир Arduino и радиоуправления ».

Габриэль Стейплс
источник
3

Если допустимо снижение до уровня AVR (как вы упомянули в своем вопросе), вы можете установить таймер и даже получить отметки от часов AVR.

Вам нужно обратиться к таблице данных вашего AVR, потому что она отличается в разных ATMegas и ATTinys. Но процедура всегда одна и та же. Что вам нужно сделать, это:

  • решить, какой прескалер использовать (например, установить его на 1, т. е. не использовать предварительное масштабирование, если требуется фактическая тактовая частота процессора), см. документацию 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
источник
Спасибо, FeeJai. Могу ли я установить эти прерывания в контексте эскиза Arduino?
Марк Харрисон
1
Я не знаком с фреймворком Arduino. Но если он не настроит все таймеры внутри, вы, конечно, можете. В противном случае вы все равно можете прочитать регистры таймера и рассчитать сами.
FeeJai
Да, вы программируете на полном C ++ в Arduino и можете использовать все регистры и символы, такие как TIMSKи TOIE0т. Д. (Скопируйте настройку таймера из таблицы данных atmega328p). Похоже, вы не можете использовать макрос ISR (), вместо этого используйте arduino.cc/en/Reference/AttachInterrupt .
Joeforker