Qual a precisão do oscilador do arduino e do uso do timerOne?

A ideia deste tópico é entender melhor o que pode ser erro causado por falha do oscilador ( variação) ou falha no programa (erro de lógica) ao usar o timer do arduino como base de tempo para projetos ,medidas de pulsos, sincronismos, etc

Pessoal. a ideia aqui é discutir o oscilador e o timer do arduino, e agradeço se encontrem erros

ou equívocos da minha parte, que me corrijam e melhorem a informação.

O oscilador dos arduinos (Uno e mega) originais é de 16 MHz.

Eles são montados com cristais de quartzo. 16.000.000 ciclos por segundos.

 Variação da frequência destes cristais:

F-Deviation = (PPM/1.000.000)*F-Ideal.

Os cristais comerciais são encontrados na faixa de 20 a 50 PPM.

Ex: F-Deviation = (50/1000000) * 16000000 = 800 Hz. um erro de 0,005%

Referencia:

http://www.jameco.com/z/CY16LP-16-MHz-Crystal-50ppm-HC49-S_137891.h...

Isto significa uma variação de 4 segundos (pra mais ou pra menos) ao final de 24 horas 

24 horas = 24*60*60 segundos = 86400 segundos 86400 * 0,005% = 4,32 segundos de erro por dia.

Mas como é um cristal oscilador, ele tem uma característica de estabilidade, ou seja, este desvio é constante na razão da estabilidade da temperatura.

A variação de frequência é de aproximadamente 0,7 Hz, por grau centigrado, ou 0,000004375%, o que representa uma variação de 0,00378 segundos ao dia.

Os RTCs de mais alta precisão, como por exemplo o DS3231, utlizam cristais montados internamente no CI, ajustados para a frequencia central, e com PPM baixos na ordem de 2 PPM

e ainda usam o recurso de estabilidade térmica.

• Accuracy ±2ppm from 0°C to +40°C; 0,0002% Variação 0,017 segundos dia.

• with an integrated temperaturecompensated crystal oscillator (TCXO) .....

Referencia:

https://datasheets.maximintegrated.com/en/ds/DS3231.pdf

Com base nestas informações, podemos identificar o desvio de frequência do nosso arduino e usar este valor de desvio para corrigir erros na contagem do tempo.

A estabilidade da temperatura é um pouco mais complicada de fazer, mas ela é muito pequena e dependerá da precisão que alvejamos.

Você pode usar um sensor de temperatura encostado no cristal, e medira atemperatura nele, e depois compensar a contagem com o desvio calculado a partir desta temperatura.

Agora vamos falar da biblioteca TimerOne.

Esta é uma biblioteca que permite voce usar um recurso do arduino UNO/MEGA e outros, é o TIMER1 (não serve para o DUE).

Ela permite que você defina uma contagem de tempo usando o registrador TIMER1 do arduino.

Este TMR1 é programado pela biblioteca para receber o incrementos vindos do oscilador do arduino, ou seja um pulso a cada 62,5 NanoSegundos, através de prescaler definido no momento da inicialização do timer1.

Prescaler é um circuito que divide a contagem dos pulsos antes de aplica-los no timer.

Por exemplo, se o prescaler está definido como 16, a cada 16 pulsos na entrada, do circuito, um pulso será incrementado no registrador do timer.

Se estiver definido como 1, todos pulsos na entrada do circuito incrementarão o registrador.

O Timer1 tem os seguintes prescalers 1, 8, 64, 256 e 1024.    Reg TCCR1B do Atmega.

A definição da biblioteca para este prescaler é feita no momento em que se inicializa o timer1.

Este timer, nesta configuração, é incrementado, independente do processador do arduino, ele roda "stand alone" bastando os pulsos do oscilador.

Esta biblioteca permite também que você defina um valor, que ao ser atingido pelo timer1, um interrupt seja gerado, ou seja interrompe-se tudo que o processador está executando e executa uma função definida pelo usuário.

O Timer 1 é zerado e reinicia a contagem novamente independente do processador, ao gerar o interrupt.

Desta forma, você pode por exemplo gerar um interrupt a cada 100ms ou a cada seg, e acumular este tempo gerando uma base de tempo, como fosse um relógio.

Com esta linha: Timer1.initialize(100000); você diz para o timer gerar um interrupt a cada 100ms, ou com esta: Timer1.initialize(1000000); um interrupt a cada segundo.

Se você conseguir identificar o desvio do cristal do seu arduino, pode alterar estes valores para que então, apesar de não ser exato o valor do seu cristal, você consiga gerar uma contagem de um segundo com grande precisão.

Ex: meu arduino aumenta 4 segundos por dia, então ele gerou 4.000.000 usegundos a mais.

4.000.000 /86400 = 46 u segundos por segundo.

Então defina a linha assim: Timer1.initialize(1000046); e deverá ter um "relógio bem preciso".

Rui

Exibições: 3573

Responder esta

Respostas a este tópico

Boa noite Rui, 

Suas colocações são esclarecedoras e concordo com várias que citou. 

- Os cristais podem ter algum erro de precisão na frequência. Como a frequência é estável para uma mesma temperatura podemos assim calibrar os timers e relógios.

- Existe o desvio de frequência devido à variação de temperatura. Como disse, no RTC DS3231, o prórprio relógio já faz essa compensação de temperatura. Só acho que para fazer a compensação de frequência do clock de um Arduino, deve dar muito trabalho e precisará de um frequencímetro de precisão ( que já tenha essa compensação de temperatura).  

- Sobre o desvio de contagem que existe nos Timers do Arduino, já li que eles variam aleatóriamente ( isso que eu entendi). Depende do programa, das interrupções e dos contadores. Vou procurar onde eu achei isso. 

Me lembro que o desvio pode variar de 0 a 4 microsegundos. 

Ótimo tópico Rui, deixo aqui um link que detalha melhor o uso e pode ajudar na leitura, abraços o/

Oi pessoal, boa tarde.

Eu estava procurando uma forma de medir o oscilador do arduino, resolvi fazer um pequeno code

que ajuda a determinar a frequência do oscilador.

Ai consegui fazer um code realmente muito pequeno e simples.

Bom,  simples o code, mas é um pouco complicada a explicação.

Para medir a saída precisa usar ou um osciloscópio ou um analisador lógico. 

Está configurado para a sair 1 mHz  no port 9. (16 mHz / 16).

Usei um UNO para testar o code, mas deve funcionar em Mini, Mega, etc....

No inicio do code tem uma breve explicação do uso dos registradores usados.

http://pastebin.com/Qv8KKMTQ

Rui

Oi JGAM, bom dia.

Qual code voe usou pra gerar estes resultados de pulsin()  e de interrupt?

Rui

Oi Rui, essa tabela não foi feita por mim.

Peguei-a nesse exemplo:

http://arduino.datamaster2003.com/f-measurements.htm

Abraços

Gustavo

Rui bom dia, 

Veja esse sensor de RPM ( para mim isso não é um sensor de RPM) . 

Cada medição é diferente da outra. 

http://circuitdigest.com/microcontroller-projects/tachometer-using-...

Usei o Proteus para simular o code, o resultado foi o esperado.

Abs.

CK

Bom dia Carlos, simulador ...

Não dá para comparar com a realidade. 

Por isso não uso simuladores.

Abraços. 

Gustavo

Bom dia J.Gustavo,

Vou testar na pratica real e posto aqui, mas uma das coisas que funciona perfeitamente e é confiável no Proteus, é o Osciloscópio.

Não obstante farei os testes com um Minipa e posto.

Abraços.

Oi Pessoal, boa tarde.

A discussão sobre o oscilador do Atmega (arduino) tem se mostrado bem interessante.

Como sei que um cristal oscilador tem um estabilidade grande, resolvi encontrar
uma forma de medir esta frequência, e comprovar esta minha convicção.

Este projeto vem ajudar à aqueles que possam querer usar o  oscilador do seu arduino, fazendo com ele

um relógio e corrigir o desvio do oscilador do seu arduino, como mencionei no inicio deste tópico.

Pré-requisitos para esta medida:

 1 Não ter nenhuma influencia do código na medida.
 2 Usar meios fáceis e de baixo custo para identificar esta medida.
 3 Code simples para evitar bugs.

Com este pensamento, consegui fazer um code muito pequeno e simples para gerar
uma frequência definida, utilizando o oscilador do arduino.

Este code usa um timer do Atmega (Timer1) de 16 bits, que roda independente do
processador.

Este timer pode ser configurado para receber dados ou do oscilador interno do Atmega,
ou de uma fonte externa de pulsos.

Ele tem também um recurso chamado de "prescaler" que simplificando, é um
divisor, (também independente do processador), que divide o pulso antes de enviar
ao Timer1, por 1, 8, 64, 256 e 1024.

Ainda não consegui comprovar no datasheet, mas a cada subida do sinal do oscilador,
a contagem no Counter do Timer1 é incrementado por 1, sendo assim, para um oscilador de
16mHz, ele conta até 8 Mega Pulsos quando o prescaler for 1.

Com o prescaler de 64, o counter chega até 125 K pulsos.   8.000.000 / 64 = 125.000.

Ao chegar no máximo do registrador, 0xFFFF, ele gera um pulso no port 9.

Com 16mhz e com prescaler de 64, o pulso acontece cada vez que o valor atinge 125.000.

Com base nesta informações elaborei este code:

    void setup()
    {

        DDRB = 0x02;          // define port 9 como saída
        TCCR1A = 0x40;      // Waveform Generation Mode 4
        TCCR1B = 0x0B;      // Prescaler 64 125 kHz
     }
     //---------------------------
     void loop ()
     {
     }

Este code faz com que o Timer1 opere independente do processador.

O code funcionou muito bem.  Objetivo 1 atingido atingida.. 

Feito isto veio a segunda parte.

Como comprovar o tempo no port 9 do atmega?

Um osciloscópio mostraria a frequência, mas é bem caro, e pouca gente tem a  habilidade para usa-lo.
Um analisador lógico também poderia ser usado, mas também tem o uso mais complexo.

Então para conseguir os objetivo 2 e 3, usei 2 recursos de custo relativamente pequeno.

Um RTC DS3231 e outro arduino, usei um Mini, mas pode ser qualquer outro arduino.

Este outro arduino roda um programa normal e não interferirá nos valores do timer do outro arduino.

Este code conta os pulsos gerados pelo outro arduino que recebe no port 2, usando pra isto um interrupt 0.

Usa também por interrupt para identificar  um pulso gerado pelo DS3231 no pino SQW.
Eu programei o DS3231 para gerar um pulso a cada segundo.

Como o DS3231 é muito preciso, este pulso será também muito preciso.

Segue o segundo programa:


  #define Pulse_Osc 2                         // Port para entrada de pulsos
  #define Pulse_RTC 3                        // Port para pulso SQW do RTC
  unsigned long Count_Osc;
  //-----------------------------
  void setup()
  {
  Serial.begin(9600); // inicializa Serial
  pinMode(Pulse_Osc,INPUT);             // Define port como entrada
  pinMode(Pulse_RTC,INPUT);            // Define port como entrada
  attachInterrupt(0, Count, FALLING);   // Define interrupt, função chamada e nível de interrupt
  attachInterrupt(1, RTC, FALLING);     // Define interrupt, função chamada e nível de interrupt
  }
  //-----------------------------
  void loop()
  {
  }
  //-----------------------------
  void Count()                                   // Função chamada a cada pulso de entrada
  {
  Count_Osc++;                               // Contagem dos pulso recebidos
  }
  //-----------------------------
  void RTC()                                    // Função chamada a cada pulso SQW do RTC
  {
  Serial.println(Count_Osc);              // Imprime o valor da contagem
  Count_Osc = 0;                            // Zera o valor da contagem
  }

Deixei estes programa rodando por 30 minutos, 1800 eventos, e encontrei os seguintes valores:

     Oscilador UNO
     Medidor MINI
     Valor medido 124.955
     Valor do oscilador = 15.994.240 (Calculada 124.955 * 128 = 15.994.240)
     Desvio 5.760 ciclos = 0,036%

Neste arduino o cristal está oscilando ligeiramente abaixo da frequência central.

Este valor 124.955 ocorreu na maioria das vezes, e por este motivo considerei como centro da meta.


Aconteceram desvios de 6 pulsos para cima e 4 para baixo, ou seja uma variação de

0,0024% para cima e 0,0016% para baixo.

Com isto considero a solução segura , pois o arduino que mede a informação está isento de interferências

externas, e de custo bem baixo, com materiais que acredito que a maioria dos amigos tem para suas montagens.

Portanto considero que atingi os pré-requisitos que estabeleci no inicio.

Vou anexar um arquivo com os dados e um gráfico que elaborei com base nas 1800 medidas

salvas por 30 minutos.

Fiz outro teste invertendo os arduino, e obtive os seguintes resultados:

     Oscilador MINI
     Medidor UNO
     Valor medido 125.098
     Valor do oscilador = 16.012.544 (Calculada 125.098 * 128 = 16.012.544)
     Desvio 12.544 ciclos = 0,0784%

Neste arduino o cristal está oscilando ligeiramente acima da frequência central.

Qualquer critica será bem vinda.

Rui

Anexos

Oi RV,

Acho que este post esta sendo muito valioso e ilustrativo para muitos, estou gostando e fazendo os testes aqui, já fiz o primeiro usando o Proteus, e o resultado foi o esperado, não tenho o Minipa aqui onde me encontro, mas na semana que vem vou testar somente para desencargo de consciência, porque tenho certeza que vai sair igual.

Quanto ao segundo teste, vou elaborar o hardware aqui e posto os resultados, sempre é bom ter material tão bom para estudar.

Parabéns como sempre pela dedicação.

Abs.

CK

 

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço