Arduino: bessere Mikrosekundenauflösung als Mikros ()?

11

In der Dokumentation zu micros () wird darauf hingewiesen, dass der Rückgabewert immer ein Vielfaches von 4 ist.

Gibt es eine Möglichkeit, einen Mikrosekundenklick mit höherer Auflösung zu erzielen, vorzugsweise bis auf 1 Mikrosekunde?

Das Herunterfallen auf den AVR-Wert ist akzeptabel.

Mark Harrison
quelle
1
Warum bestehen Sie darauf, Ihren Titel mit einem Tag zu beginnen, wenn ich es zu einer perfekt englischen Frage gemacht habe?
Stevenvh
4
Entschuldigung Steven, ich dachte aufrichtig (und denke), es ist eine gute Möglichkeit, die Frage kurz und klar auszudrücken. Es gab viele Diskussionen darüber und Jeff stimmte in einigen Fällen zu, dass dies eine gute Art zu fragen war. Die Diskussion ist hier; Die Heatmaps haben mich überzeugt, dass es sich für diese Art von Fragen lohnt, die Betriebsumgebung zu betonen. meta.stackexchange.com/questions/10647/writing-good-titles/… Aber aus Respekt für Ihre hervorragenden Antworten würde ich es gerne wieder ändern, wenn Sie der Meinung sind, dass es das Beste ist.
Mark Harrison
Ist es möglich, es für die Funktion pulsein () zu verwenden? Ich muss die Impulslänge in einer Auflösung von weniger als 1 usec messen.
Dieser Bereich ist für Antworten auf die Frage oben reserviert. Wenn Sie etwas zu fragen haben, beginnen Sie Ihre eigene Frage.
Olin Lathrop

Antworten:

9

Ja, abhängig von der Grundtaktrate Ihres Arduino. Hier sind zum Beispiel die Eingangsfrequenzen und Perioden des Zählertimers nach der Vorskalierung für den Zählertimer 2 eines ATMega2560 und eine Grundtaktrate von 16 MHz. Der Timer verfügt über integrierte "Prescaler" -Wertoptionen, die die Frequenz / Periode bestimmen (siehe Tabelle):

    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

Für eine bessere Timing-Auflösung verwenden Sie einen Wert namens TCNT2. Es gibt einen eingebauten Zähler, der von 0 bis 255 reicht, da der Timer 8 Bit ist. Wenn der Zähler den von TCNT2 zugewiesenen Wert erreicht, löst er einen Interrupt aus. Dieser Interrupt heißt TIMER2_OVF_vect.

Angesichts dieser Informationen wäre die resultierende Interrupt-Rate: 16 MHz / (Vorteiler * (255 - TCNT2))

Sie könnten den Timer mit den vollen 16 MHz (62,5 nSec) laufen lassen, obwohl dies viel schneller ist als nötig. 2 MHz mit einer Anfangszählung von (255-2) ergeben eine Interruptrate von 1 MHz. Teilen Sie das in Ihrem ISR durch 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
};

Das Datenblatt für Ihre MCU ist die grundlegende Ressource. Dieser Artikel gibt Ihnen (und gab mir!) einen guten Vorsprung.

JRobert
quelle
4

Mark, ich habe beschlossen, einen neuen Satz von Funktionen zu schreiben, der auf dem Arduino Atmega328 Timer2 basiert und Überlauf-Interrupts verwendet, um eine Genauigkeit von 0,5 us zu erreichen. Mein Code kann hier heruntergeladen und verwendet werden:

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

Hier ist eine kurze Beschreibung: "Ich habe eine" Bibliothek "geschrieben, um eine Genauigkeit von 0,5 us für eine" micros () "- Ersatzfunktion zu erhalten, damit ich wiederholbare Ergebnisse beim Lesen eines PWM- oder PPM-Signals innerhalb von 1us erhalten kann. Ich habe überall in der Welt gesucht Internet und konnte nichts Vergleichbares finden (oder das war einfach zu bedienen und behielt die Fähigkeit des Arduino bei, PWM-Signale über die Servo Libary zu schreiben), daher denke ich, dass dies mein erster wichtiger Beitrag zur Welt von Arduino und Radio Control ist. "

Gabriel Staples
quelle
3

Wenn es akzeptabel ist, auf den AVR-Pegel zu fallen (wie Sie in Ihrer Frage erwähnt haben), können Sie einen Timer einrichten und sogar die Ticks der AVR-Uhr abrufen.

Sie müssen sich auf das Datenblatt Ihres AVR beziehen, da es sich innerhalb der verschiedenen ATMegas und ATTinys unterscheidet. Das Verfahren ist jedoch immer das gleiche. Was Sie tun müssen, ist:

  • Entscheiden Sie, welcher Prescaler verwendet werden soll (z. B. setzen Sie ihn auf 1, dh ohne Prescaling, wenn Sie die tatsächliche CPU-Taktrate wünschen). Weitere Informationen finden Sie in der TCCR-Dokumentation
  • Richten Sie einen Timer-Überlauf-Interrupt und einen Interrupt-Handler ein und aktivieren Sie Interrupts global
  • Aktivieren Sie den Timer im Timer / Counter Control Register TCCR

Auf diese Weise können die genauen Ticks aus dem Timer-Register abgerufen werden. Sie müssen die Überläufe jedoch manuell zählen. Dies ist technisch so präzise wie möglich.

Hier ist ein Beispielcode für den veralteten AT90S2313, der Ihnen jedoch gute Hinweise gibt, was Sie grundsätzlich tun sollten:

/* 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
quelle
Danke FeeJai. Kann ich diese Interrupts im Kontext einer Arduino-Skizze setzen?
Mark Harrison
1
Ich bin mit dem Arduino-Framework nicht vertraut. Aber wenn nicht alle Timer intern eingerichtet sind, können Sie dies auf jeden Fall. Ansonsten können Sie die Timer-Register noch lesen und selbst berechnen.
FeeJai
Ja, Sie programmieren in voller C ++ in Arduino und kann alle Register und Symbole wie verwenden TIMSK, TOIE0etc (Kopieren Timer - Setup aus dem ATmega328P Datenblatt). Es sieht so aus, als könnten Sie das Makro ISR () nicht verwenden, sondern stattdessen arduino.cc/en/Reference/AttachInterrupt .
Joeforker