Arduino: melhor resolução de microssegundo que micros ()?

11

A documentação micros () observa que o valor de retorno sempre será um múltiplo de 4.

Existe alguma maneira de obter um clique de microssegundo de resolução mais alta, de preferência até o nível de 1 microssegundo?

Descer para o nível AVR é ​​aceitável.

Mark Harrison
fonte
1
Por que você insiste em iniciar seu título com uma tag quando eu fiz uma pergunta perfeitamente em inglês?
stevenvh
4
Desculpas Steven, sinceramente, pensei (e acho) que é uma boa maneira de expressar a pergunta de maneira sucinta e clara. Houve muita discussão sobre isso, e Jeff concordou em alguns casos que era uma boa maneira de perguntar. A discussão está aqui; os mapas de calor são o que me convenceu de que, por esse estilo de perguntas, vale a pena enfatizar o ambiente operacional. meta.stackexchange.com/questions/10647/writing-good-titles/… Mas, por respeito às suas excelentes respostas, ficaria feliz em mudar de volta, se você achar melhor.
Mark Harrison
É possível usá-lo para a função pulsein ()? Preciso medir o comprimento dos pulsos em arquivos de resolução superiores a 1 usec.
Este espaço é reservado para respostas à pergunta no topo. Se você tem algo a perguntar, comece sua própria pergunta.
precisa

Respostas:

9

Sim, dependendo da taxa de clock básica do seu Arduino. Por exemplo, aqui estão as frequências de entrada do contador e os períodos após a pré-escala, para um contador 2 do ATMega2560 e uma taxa básica de clock de 16 MHz. O timer incorporou opções de valor "prescaler" que determinam a frequência / período, mostradas nesta tabela:

    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

Para uma melhor resolução de temporização, use um valor chamado TCNT2. Há um contador de compilação que varia de 0 a 255 porque o timer é de 8 bits. Quando o contador atinge o valor atribuído pelo TCNT2, ele aciona uma interrupção. Essa interrupção é chamada TIMER2_OVF_vect.

com essas informações, a taxa de interrupção resultante seria: 16 MHz / (pré-calibrador * (255 - TCNT2))

Você pode fazer com que o timer funcione a 16MHz (62,5nSec), embora isso seja muito mais rápido do que você precisa; 2 MHz com uma contagem inicial de (255-2) forneceriam uma taxa de interrupção de 1 MHz. Divida isso por 2 no seu 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
};

A folha de dados para o seu MCU é o recurso básico; este artigo dará a você (e me deu!) um bom avanço.

JRobert
fonte
4

Mark, decidi escrever um novo conjunto de funções, com base no Arduino Atmega328 Timer2, e usando interrupções de estouro, para obter precisão de 0,5us. Meu código está disponível para download e uso aqui:

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

Aqui está uma breve descrição: "Eu escrevi uma" biblioteca "para obter precisão de 0,5us em uma função de substituição" micros () ", para que eu possa obter resultados repetíveis lendo um sinal PWM ou PPM, dentro de 1us. Internet e não consegui encontrar algo comparável (ou que fosse fácil de usar, e mantivesse a capacidade do Arduino de gravar sinais PWM via Servo Libary), então acho que esta é minha primeira grande contribuição ao mundo do Arduino e do Radio Control ".

Gabriel Staples
fonte
3

Se descer para o nível do AVR for aceitável (como você mencionou na sua pergunta), você poderá configurar um cronômetro e até obter os tiques do relógio do AVR.

Você precisa consultar a folha de dados do seu AVR, pois difere entre os diferentes ATMegas e ATTinys. Mas o procedimento é sempre o mesmo. O que você precisa fazer é:

  • decida qual pré-calibrador usar (por exemplo, defina-o como 1, ou seja, sem pré-calibrar se você deseja a velocidade real do clock da CPU), consulte a documentação do TCCR
  • configurar uma interrupção de estouro de timer, um manipulador de interrupções e ativar interrupções globalmente
  • ativar o timer no registro de controle de timer / contador TCCR

Dessa forma, é possível obter os ticks exatos no registro do timer, no entanto, você precisa contar os estouros manualmente. Isso é o mais preciso possível pela tecnologia.

Aqui está um exemplo de código para o AT90S2313 desatualizado, mas fornece boas dicas sobre o que fazer basicamente:

/* 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
fonte
Obrigado FeeJai. Posso definir essas interrupções no contexto de um esboço do Arduino?
Mark Harrison
1
Não estou familiarizado com a estrutura do arduino. Mas se ele não configurar todos os temporizadores internamente, você certamente poderá. Caso contrário, você ainda poderá ler os registros do temporizador e se calcular.
FeeJai
Sim, você está programando em plena C ++ em Arduino e pode usar todos os registros e símbolos, tais como TIMSK, TOIE0etc (cópia configuração do temporizador do ATmega328P folha de dados). Parece que você não pode usar a macro ISR (); em vez disso, use arduino.cc/en/Reference/AttachInterrupt .
22811 joeforker