Arduino: migliore risoluzione dei microsecondi rispetto ai micros ()?


11

La documentazione di micros () osserva che il valore restituito sarà sempre un multiplo di 4.

Esiste un modo per ottenere un clic di microsecondi a risoluzione più elevata, preferibilmente fino al livello di 1 microsecondo?

Scendendo al livello AVR è accettabile.


1
Perché insisti per iniziare il tuo titolo con un tag quando ho fatto una domanda perfettamente inglese?
Stevenvh,

4
Mi scuso Steven, ho sinceramente pensato (e penso) che sia un buon modo per esprimere la domanda in modo succinto e chiaro. Ci sono state molte discussioni al riguardo e Jeff ha concordato in alcuni casi che era un buon modo di chiedere. La discussione è qui; le mappe di calore sono ciò che mi ha convinto che per questo stile di domande vale la pena sottolineare l'ambiente operativo. meta.stackexchange.com/questions/10647/writing-good-titles/… Ma, per rispetto delle tue eccellenti risposte, sarei felice di cambiarlo se pensi che sia il migliore.
Mark Harrison,

È possibile usarlo per la funzione pulsein ()? Devo misurare la lunghezza degli impulsi in termini di risoluzione di 1 usec.

Questo spazio è riservato per le risposte alla domanda in alto. Se hai qualcosa da porre, inizia la tua domanda.
Olin Lathrop,

Risposte:


9

Sì, a seconda della frequenza di clock di base del tuo Arduino. Ad esempio, ecco le frequenze di ingresso e i periodi del contatore del timer dopo il pre-ridimensionamento, per il contatore del timer 2 di un ATMega2560 e una frequenza di clock di base di 16 MHz. Il timer ha incorporato opzioni di valore "prescaler" che determinano la frequenza / periodo, mostrato in questa tabella:

    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

Per una migliore risoluzione di temporizzazione, si utilizza un valore chiamato TCNT2. C'è un contatore incorporato che va da 0 a 255 perché il timer è di 8 bit. Quando il contatore raggiunge il valore assegnato da TCNT2 innesca un interrupt. Questo interrupt si chiama TIMER2_OVF_vect.

date queste informazioni, la frequenza di interruzione risultante sarebbe: 16MHz / (prescaler * (255 - TCNT2))

È possibile far funzionare il timer alla piena 16MHz (62.5nSec) anche se è molto più veloce del necessario; 2MHz con un conteggio iniziale di (255-2) darebbe una frequenza di interruzione di 1MHz. Dividilo per 2 nel tuo 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
};

La scheda tecnica per il tuo MCU è la risorsa di base; questo articolo ti darà (e mi ha dato!) un buon vantaggio.


4

Mark, ho deciso di scrivere un nuovo set di funzioni, basato su Arduino Atmega328 Timer2, e usando interruzioni di overflow, per ottenere una precisione a 0,5us. Il mio codice è disponibile per il download e utilizzare qui:

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

Ecco una breve descrizione: "Ho scritto un" libary "per ottenere una precisione di 0,5us su una funzione di sostituzione" micros () ", in modo da poter ottenere risultati ripetibili leggendo un segnale PWM o PPM, entro 1us. Ho cercato in tutto il Internet e non è stato possibile trovare qualcosa di paragonabile (o che fosse facile da usare, e ha mantenuto la capacità dell'Arduino di scrivere segnali PWM tramite Servo Libary), quindi penso che questo sia il mio primo importante contributo al mondo di Arduino e Radio Control. "


3

Se scendere al livello AVR è accettabile (come indicato nella domanda), è possibile impostare un timer e persino ottenere i segni di spunta dell'orologio dell'AVR.

Devi fare riferimento alla scheda tecnica del tuo AVR perché differisce tra i diversi ATMegas e ATTINY. Ma la procedura è sempre la stessa. Quello che devi fare è:

  • decidere quale prescaler utilizzare (ad esempio impostarlo su 1, cioè non prescaling se si desidera la velocità effettiva del clock della CPU), fare riferimento alla documentazione TCCR
  • impostare un interrupt di overflow del timer, un gestore di interrupt e attivare gli interrupt a livello globale
  • attivare il timer nel registro controllo timer / contatore TCCR

In questo modo è possibile ottenere i tick esatti dal registro timer, tuttavia è necessario contare manualmente gli overflow. Questo è il più preciso possibile dalla tecnologia.

Ecco alcuni esempi di codice per l'AT90S2313 obsoleto, ma ti dà buoni suggerimenti su cosa fare in sostanza:

/* 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  
   */
}

Grazie a FeeJai. Posso impostare questi interrupt nel contesto di uno schizzo di Arduino?
Mark Harrison,

1
Non ho familiarità con il framework arduino. Ma se non imposta tutti i timer internamente, puoi sicuramente farlo. Altrimenti puoi ancora leggere i registri del timer e calcolare te stesso.
FeeJai

Sì, stai programmando in C ++ completo in Arduino e puoi usare tutti i registri e i simboli come TIMSK, TOIE0ecc. (Copia il setup del timer dal foglio dati atmega328p). Sembra che non puoi usare la macro ISR (), invece usa arduino.cc/en/Reference/AttachInterrupt .
joeforker,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.