Arduino: lepsza rozdzielczość mikrosekundowa niż micros ()?

11

Dokumentacja micros () zauważa, że ​​zwracana wartość zawsze będzie wielokrotnością 4.

Czy jest jakiś sposób na uzyskanie mikrosekundowego kliknięcia w wyższej rozdzielczości, najlepiej do poziomu 1 mikrosekundy?

Zejście do poziomu AVR jest dopuszczalne.

Mark Harrison
źródło
1
Dlaczego nalegasz na rozpoczęcie tytułu od tagu, kiedy zrobiłem z niego pytanie w języku angielskim?
stevenvh
4
Przepraszam Steven, szczerze myślałem (i myślę), że to dobry sposób na zwięzłe i jasne wyrażenie pytania. Dyskutowano na ten temat, a Jeff w niektórych przypadkach zgodził się, że to dobry sposób na zapytanie. Dyskusja jest tutaj; mapy termiczne przekonały mnie, że w przypadku tego rodzaju pytań warto podkreślić środowisko operacyjne. meta.stackexchange.com/questions/10647/writing-good-titles/... Ale z szacunku dla twoich doskonałych odpowiedzi chętnie go zmienię, jeśli uważasz, że jest to najlepsze.
Mark Harrison
Czy można go używać do funkcji pulsin ()? Muszę zmierzyć długość impulsów w rozdzielczości mniejszej niż 1 usec.
To miejsce jest zarezerwowane dla odpowiedzi na pytanie u góry. Jeśli masz coś do zadania, zacznij swoje własne pytanie.
Olin Lathrop,

Odpowiedzi:

9

Tak, w zależności od podstawowej częstotliwości zegara Twojego Arduino. Na przykład tutaj są częstotliwości wejściowe licznika czasu i okresy po wstępnym skalowaniu, licznik 2 licznika ATMega2560 oraz podstawowa częstotliwość 16 MHz. Timer ma wbudowane opcje wartości „prescaler”, które określają częstotliwość / okres, pokazane w tej tabeli:

    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

Aby uzyskać lepszą rozdzielczość czasową, użyj wartości o nazwie TCNT2. Istnieje wbudowany licznik, który zmienia się od 0 do 255, ponieważ zegar ma 8 bitów. Kiedy licznik osiągnie wartość przypisaną przez TCNT2, wyzwala przerwanie. To przerwanie nosi nazwę TIMER2_OVF_vect.

biorąc pod uwagę te informacje, wynikowa częstotliwość przerwań wyniesie: 16 MHz / (prescaler * (255 - TCNT2))

Możesz sprawić, aby zegar działał z pełną częstotliwością 16 MHz (62,5 nSek), ale jest to o wiele szybsze niż potrzebujesz; 2 MHz z początkową liczbą (255-2) dałoby Ci częstotliwość przerwań 1 MHz. Podziel to przez 2 w swoim 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
};

Arkusz danych MCU jest podstawowym zasobem; ten artykuł da ci (i dał mi!) dobry początek.

JRobert
źródło
4

Mark, postanowiłem napisać nowy zestaw funkcji, oparty na Arduino Atmega328 Timer2 i używając przerwań przepełnienia, aby uzyskać precyzję do 0,5us. Mój kod jest dostępny do pobrania i wykorzystania tutaj:

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

Oto krótki opis: „Napisałem„ bibliotekę ”, aby uzyskać precyzję 0,5us na funkcji zastępowania„ micros () ”, dzięki czemu mogę uzyskać powtarzalne wyniki odczytu sygnału PWM lub PPM z dokładnością do 1us. Internet i nie mógł znaleźć czegoś porównywalnego (lub który był łatwy w użyciu i utrzymywał zdolność Arduino do zapisywania sygnałów PWM poprzez Servo Libary), więc myślę, że to mój pierwszy znaczący wkład w świat Arduino i Radio Control. ”

Gabriel Staples
źródło
3

Jeśli obniżenie poziomu AVR jest dopuszczalne (jak wspomniałeś w swoim pytaniu), możesz ustawić minutnik, a nawet uzyskać tyknięcie zegara AVR.

Musisz odwołać się do arkusza danych AVR, ponieważ różni się on w różnych ATMegas i ATTinys. Ale procedura jest zawsze taka sama. Co musisz zrobić, to:

  • zdecyduj, którego preskalera użyć (na przykład ustaw go na 1, tj. bez wstępnego skalowania, jeśli chcesz rzeczywistą prędkość zegara procesora), zapoznaj się z dokumentacją TCCR
  • skonfiguruj przerwanie przepełnienia timera, procedurę obsługi przerwań i aktywuj przerwania globalnie
  • aktywować licznik w Rejestrze Sterowania Licznikiem / Licznikiem TCCR

W ten sposób można uzyskać dokładne tiki z rejestru timera, jednak trzeba przeliczyć przepełnienia ręcznie. Jest to tak precyzyjne, jak to możliwe dzięki technologii.

Oto przykładowy kod przestarzałego AT90S2313, ale daje on dobre wskazówki, co robić w zasadzie:

/* 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
źródło
Dziękuję FeeJai. Czy mogę ustawić te przerwania w kontekście szkicu Arduino?
Mark Harrison
1
Nie znam frameworka arduino. Ale jeśli nie skonfiguruje wszystkich timerów wewnętrznie, na pewno możesz. W przeciwnym razie możesz nadal czytać rejestry liczników i samemu się obliczać.
FeeJai
Tak, jesteś w pełni programowania C ++ w Arduino i mogą korzystać ze wszystkich rejestrów i symboli, takich jak TIMSK, TOIE0etc (kopia konfiguracji timera z arkusza ATmega328P). Wygląda na to, że nie możesz użyć makra ISR (), zamiast tego użyj arduino.cc/en/Reference/AttachInterrupt .
joeforker