Arduino UNO - Taxa de amostragem do conversor A/D

Taxa de amostragem
Este post faz parte da série Arduino UNO: Conversor A/D. Leia também os outros posts da série:

A plataforma Arduino traz em seu núcleo funções para leitura de sinais analógicos através da utilização do conversor analógico digital. O valor da taxa de amostragem é configurado internamente através das bibliotecas do Arduino. Desta forma não precisamos configurar os registradores internos do ATmega328 antes da leitura de um sinal analógico. Essa camada de abstração auxilia os iniciantes para a leitura de sinais analógicos, porém em aplicações que necessitam de uma otimização da leitura, é necessário entender o funcionamento do conversor A/D do microcontrolador ATmega328 e a correta configuração dos seus registradores para que atenda as necessidades do projeto.

 

Nesse artigo vamos abordar o funcionamento do conversor A/D do Arduino UNO que é baseado no ATmega328, entendendo a sua configuração e desenvolver alguns teste para avaliarmos qual a máxima taxa de amostragem que podemos obter garantindo a resolução máxima do conversor.

 

Conversor A/D do ATmega328

 

O Atmega328 possui internamente um conversor A/D de aproximação sucessivas de 10 bits de resolução com precisão de ± 2 LSBs. Possui até 8 canais de entradas multiplexados, dependendo do encapsulamento. No caso do Atmega328 PDIP, do Arduino UNO, apresenta apenas 6 canais, como pode-se verificar na placa. Por existir apenas 1 conversor A/D, só poderá ser selecionado 1 canal por vez para conversão, isso é feito através da configuração dos registradores internos. O diagrama de blocos  do conversor A/D  é exibido a seguir:

 

 bloco AD

 

 

Como pode ser observado na figura acima, o bloco do conversor A/D possui fonte separada para a parte analógica, o pino AVcc. Essa tensão não pode variar mais do que +/-0,3V de Vcc.

 

O Atmega328 possui tensão de referência interna de 1,1 V, que pode ser selecionada por software. Apresenta também um pino externo para uma tensão de referência diferente de VCC ou a referência interna de 1,1 V. O valor de tensão de entrada deve estar entre  0V e o valor de tensão de referência, não ultrapassando o valor de VCC.

 

Ao final da conversão pode ser gerada uma interrupção, caso a mesma esteja habilitada.

 

A conversão gera um resultado de 10 bits, necessitando assim de 2 registradores, ADCH e ADCL.

 

A seguir serão apresentados os registradores de configuração do conversor A/D do ATmega328:

 

ADMUX - ADC Multiplexer selection Register:

 

 ADMUX

 

 

 

Bit 7:6 – REFS1:0 – Reference Selection Bits

Esses bits configuram a fonte de tensão de referência para o A/D, conforme a tabela abaixo:

 

tabela  tensão de referência

 

Bit 5 – ADLAR: ADC left adjust Result

Configura a forma de exibição do resultado da conversão. ADLAR = 1, resultado justificado a esquerda, ADLAR = 0, justificado a direita. O resultado é exibido nos registradores ADCL e ADCH, conforme a configuração do ADLAR.

 

Bit4 – Não usado

 

Bits 3:0 – MUX3:0 – Analog Channel Selection Bits

Seleciona qual entrada analógica será conectada ao conversor, conforme tabela abaixo:

 

Taxa de amostragem

 nota: 1.  Sensor de temperatura

 

ADCSRA – ADC Control and Status Registe A

 

Taxa de amostragem

 

 

 

 

Bit 7 – ADEN: ADC Enable

Habilita o conversor A/D quando em nível lógico 1. Quando ADEN = 0 o conversor será desligado e caso isso ocorra enquanto uma conversão em progresso, a mesma será terminada antes de desligar o conversor A/D.

 

Bit 6 - ADSC: ADC Start conversion

No modo de conversão simples, ADCS = 1 fará iniciar a conversão, já no modo de conversão contínua será iniciada a primeira conversão. ADCS vai para nível lógico zero quando a conversão é finalizada. Se ADCS for escrito em nível lógico 1 ao mesmo tempo que ADEN, a primeira conversão levará 25 ciclos de clock ao invés dos 13 Ciclos de uma conversão.

 

Bit 5 – ADATE: ADC Auto Trigger Enable

Habilita o auto dispara, quando esse bit estiver em 1. O conversor iniciará uma conversão quando uma borda de subida ocorrer no sinal de disparo. O sinal de disparo é selecionado nos bits ADTS do registrador ADCSRB.

 

Bit 4 – ADIF: ADC Interrupt Flag

Sinaliza o final de uma conversão e os registradores de dados são atualizados.

 

Bit 3 – ADIE: ADC Interrupt Enable

Habilita a interrupção no final da conversão. Porém os nit I do registrador SREG deve estar ligado, para que ocorra a interrupção.

 

Bit 2:0 – ADPS2:0: ADC Prescaler Select Bits

Configura o fator de divisão entre o clock do sistema e a entrada de clock do ADC. Os valores possíveis são exibidos na tabela abaixo:

 

Taxa de amostragem

 

ADCSRB – ADC Control and Status Register B

 

Taxa de amostragem

 

Bit 2:0 – ADTS2:0: ADC Auto Trigger Source

Seleciona a fonte de disparo caso o bit ADATE esteja habilitado. A fontes possíveis são exibidas na tabela a seguir:

 

Taxa de amostragem 

Vamos ver a seguir os modos de operação do coversor A/D do ATmega328.

 

 

Modos de operação

 

O conversor AD do Atmega328 possui dois modos de operação: conversão simples e conversão contínua.

 

Conversão simples

 

No modo de conversão simples é necessário a inicialização de cada conversão. Quando a conversão é finalizada os registradores de dados são preenchidos e o bit ADIF é colocado em 1. Para iniciar uma conversão deve-se ligar o bit ADSC. Esse bit permanecerá em 1 enquanto a conversão está em processo, e passará para 0 no final da conversão.

 

Conversão contínua

 

No modo de conversão contínua, você iniciará a primeira conversão e o conversor iniciará automaticamente as próximas conversões, logo após ser completada a anterior.

 

Clock

 

O clock recomendado para o conversor AD do Atmega328 é de 50KHz a 200 KHz para uma resolução de 10 bits. O bloco prescaler controla do clock do conversor A/D, assim o clock do conversor A/D será uma fração do clock do oscilador principal, conforme o fator do prescaler.

 

Os valores são selecionados no registrador ADCSA nos bits ADPS2:0. No caso da placa Arduino UNO que roda como um cristal de 16 MHz, o clock do conversor A/D pode assumir os seguintes valores:

 

  • 16 MHz / 2 = 8 MHz
  • 16 MHz / 4 = 4 MHz
  • 16 MHz / 8 = 2 MHz
  • 16 MHz / 16 = 1 MHz
  • 16 MHz / 32 = 500 kHz
  • 16 MHz / 64 = 250 kHz
  • 16 MHz / 128 = 125 kHz

 

Como mencionado anteriormente o clock do conversor A/D deve estar estar entre 50 KHz e 200 KHz para garantir a precisão de 10 bits na resolução. Assim, observando os valores anteriores só se pode usar o prescaler de 128. Caso esteja trabalhando com um cristal de 20 MHz, e for selecionado o prescaler de 128 o clock do conversor AD será 156 KHz.

 

Uma conversão normal necessita de 13 pulsos de clock no conversor A/D. A primeira conversão necessita de 25 pulsos de clock, conforme exibido nas figuras abaixo. Dessa forma o valor de amostragem do conversor A/D depende do pulsos de clock de cada conversão, ou seja, o valor do clock deve ser dividido por 13 para calcular  a quantidade de amostras por segundo.

 

Primeira conversão:

Taxa de amostragem 

 

Conversão Normal:

 Taxa de amostragem

 

A configuração do conversor A/D do Arduino está no arquivo wiring.c, e encontra-se da seguinte forma:

 

 

Conforme exibido na configuração acima, o prescaler com 128, provendo um clock de 125 KHz para o ADC, já que o Arduino roda com um cristal de 16MHz.  Com um clock de 125 KHz a taxa de amostragem será: 125 KHz / 13 = 9600 amostras por segundo.

 

Uma opção para o aumento da taxa de amostragem é a troca  oscilador principal para uma frequência de 12 MHz, ondé é possível chegar ao valor de 187 KHz de clock, que resultará em uma taxa de amostragem de 187 KHz/13 = 14384 amostras por segundo. Caso se tenha um clock de 200 KHz, que é o máximo recomendado, a taxa de amostragem máxima que será conseguida com o conversor A/D do ATmega328 será: 200 KHz/13 = 15384 amostras por segundo, ou seja, o AD do Atemga328 conseguirá no máximo 15KHz de amostragem com 10 bits de resolução.

 

Resolução

 

O conversor A/D do Atemega328 possui 10 bits de resolução, ou seja, os valores entre 0 e Vref serão convertidos entre 0 e 1023.

equação ad

O clock máximo recomendado para essa resolução é 200 KHz, que dára uma taxa de amostragem de aproximadamente 15KHz. No application Note AVR120:Characterization and Calibration of the ADC on an AVR, encontramos a seguinte declaração:

 

“The ADC accuracy also depends on the ADC clock. The recommended maximum ADC clock frequency is limited by the internal DAC in the conversion circuitry. For optimum performance, the ADC clock should not exceed 200 kHz. However, frequencies up to 1 MHz do not reduce the ADC resolution significantly.
Operating the ADC with frequencies greater than 1 MHz is not characterized.”

 

Isso significa que pode-se aumentar o clock acima de 200 KHz até 1MHz sem obter degradação na precisão do valor convertido. Para verificar esta afirmação, vamos testar a aquisição para alguns valores de prescaler, ou seja, aumentando o clock do conversor A/D.

 

Leitura padrão do A/D no Arduino

 

Para testarmos a taxa de amostragem que vem configurada por padrão no Arduino vamos utilizar o código a seguir, que consiste em os valores de conversão marcando o tempo de inicio e o tempo de fim da leitura, exibindo o valor e o tempo decorrido para cada leitura.

 

 

Taxa de amostragem 

 

Conforme exibido acima, o tempo decorrido em cada leitura está entre 108 us e 116 us. Se pegarmos o valor de 0,116 ms teremos uma frequência de amostragem de aproximadamente 8600 Hz, bem próximo de 9600 calculado anteriormente.

 

Conversão com clock de 250 KHz

 

Agora vamos mudar o prescaler do clock para 64, aumentando a frequência do clock para 250 KHz, já que estamos usando um cristal de 16MHz. Esse clock já está acima do valor recomendado.  Para facilitar a configuração foram criadas constantes para facilitar a correta escrita no registrador ADCSRA, conforme é exibido no código abaixo:

 

 

Taxa de amostragem 

 

Agora o intervalo de leitura está na ordem de 60us, o que nos dá uma frequência de aproximadamente 16KHz. O que já era esperado já que foi dobrado a frequência do clock.

 

Variando o valor do pontenciomentro de 0 a 100%, nota-se que o valor da conversão está entre 0 a 1023, desta forma a resolução para esse clock ainda encontra-se em 10 bits.

 

Aumentando o clock para 500 KHz

 

Agora vamos mudar o prescaler para 32, dessa forma o ADC estará rodando com uma frequência de 500KHz.

 

Taxa de amostragem

 

O intervalo de leitura agora caiu para 32 us o que dá uma taxa de amostragem de aproximadamente 31K amostra por segundo. Variando o valor do potenciômetro verifica-se que a conversão ainda está sendo feita corretamente.

 

 

O que acontece a 1 MHz

 

Por ultimo vamos configurar o prescaler para 16 assim o ADC estará funcionando a 1MHz.

 

Taxa de amostragem

 

O intervalo de leitura agora está na faixa de 20 us o que dá uma taxa de amostragem de aproximadamente 50K amostra por segundo.Variando potenciômetro verifica-se que o  valor de conversão ainda se encontra com 10 bits de resolução.

 

 

Conclusão

 

O correto uso do conversor A/D é essencial para a amostragem de sinais analógicos. Conhecer as configurações e os limites de hardware possibilita a otimização e confiabilidade do sinal lido e desta informação. Nesse artigo conhecemos os registradores do conversor AD do ATmega328 e testamos a sua  taxa de amostragem. Percebeu-se que não houve prejuízo nos valores de conversão quando houve o aumento do clock do conversor AD, porém para diminuir possíveis erros ocasionados por ruídos na conversão (e quando não há a necessidade de uma alta taxa de amostragem) é aconselhado trabalhar em uma frequência menor. Pode-se também aumentar a frequência de amostragem para valores acima de 1 MHz e trabalhar com uma resolução de 8 bits, configurando o ajuste à esquerda do resultado.

 

A partir do exemplo apresentado você poderá fazer teste de aquisições em frequências de amostragens diferentes do padrão que vem configurado na biblioteca do Arduino. Teste em seus projetos e nos contes suas experiências. No próximo artigo vamos testar o sensor de temperatura interno do Atmega328.

 

Saiba mais

 

 

Arduino - Primeiros Passos

Arduino UNO

Arduino - Entradas Analógicas

 

Referências

 

Função analogRead()

Advanced Arduino ADC – Faster analogRead()

http://forum.arduino.cc/index.php/topic,6549.0.html

AVR120: Characterization and Calibration of theADC on an AVR

 

Outros artigos da série

Arduino UNO - Sensor de temperatura interno >>
Este post faz da série Arduino UNO: Conversor A/D. Leia também os outros posts da série:
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Fábio Souza
Engenheiro com experiência no desenvolvimento de projetos eletrônicos embarcados. Hoje é diretor de operações do portal Embarcados, onde trabalha para levar conteúdos de eletrônica, sistemas embarcados e IoT para o Brasil. Também atua no ensino eletrônica e programação pelo Brasil. É entusiastas do movimento maker, da cultura DIY e do compartilhamento de conhecimento, publica diversos artigos sobre eletrônica e projetos open hardware, como o projeto Franzininho Participou da residência hacker 2018 no Redbull Basement. Quando não está ministrando palestras, cursos ou workshops, dedica seu tempo “escovando bits” ou projetando placas eletrônicas.

34
Deixe um comentário

avatar
 
21 Comment threads
13 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
12 Comment authors
Fábio SantosCarlosFernando FrançaMatheus TieppoFelipe Fontenele Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Fábio Santos
Visitante
Fábio Santos

Olá Fábio, bom dia! Estou com um problema e não consigo um código que consiga satisfazer as seguintes condições: Utilizar Arduino como base (permitindo usar a serial) void setup() { } void loop() { } Problema: Desenvolver através da configuração/manipulação dos registradores (sem funções do Arduino) * Única exceção, uso da Serial nativa do Arduino "Serial.begin(9600);" no setup "Serial.println(texto/valor);" para imprimir algo no terminal Configurar o timer 1 para disparar o ADC a cada 1ms * Sinal analógico na entrada A0 * Potenciômetro (conectado ao Vcc e GND) * Realizar a média de 16 amostras do ADC * Minimizar ruídos… Leia mais »

Eduardo Siridakis
Visitante
Eduardo Siridakis

Eu quero amostrar um sinal a uma taxa de 30 kHz e gostaria de conseguir pelo menos uns 3 segundos de amostragem contínua. Sendo assim eu preciso armazenar 90000 amostras e a memória do atmega328p é só de 2 kB o que impossibilita que eu armazene tudo antes de transmitir :/

Eduardo Siridakis
Visitante
Eduardo Siridakis

Olá, seu artigo está sendo muito útil para um projeto que estou realizando, mas encontrei um gargalo maior que o tempo de conversão A/D. Por mais que consigamos uma conversão em cerca de 20us, o tempo para enviar o dado para o monitor serial do arduino é muito maior que isso. Eu gostaria de amostrar um sinal a pelo menos 30kHz e apresentar as amostras no monitor serial, de forma que eu possa copiá-las depois e usar os dados no Matlab. O problema é que mesmo com o prescaler de 16 e usando um baud rate de 1 M eu… Leia mais »

Gustavo Gran
Visitante
Gustavo Gran

Bom dia, meu caro, não sou do fórum, mas posso te ajudar com o seu problema.

Você precisa que o sinal seja enviado em tempo real? Porque você pode criar um vetor com tamanho baseado no número de amostras que vc quer fazer a aquisição do sinal. Após ter coletado todas as amostras no período de amostragem correto, aí sim você printa na tela os valores.

Acredito que dessa forma você atingirá seu objetivo, espero ter ajudado!

Eduardo
Visitante
Eduardo

Olá, seu artigo está sendo muito útil para um projeto que estou realizando, mas encontrei um gargalo maior que o tempo de conversão A/D. Por mais que consigamos uma conversão em cerca de 20us, o tempo para enviar o dado para o monitor serial do arduino é muito maior que isso. Eu gostaria de amostrar um sinal a pelo menos 30kHz e apresentar as amostras no monitor serial, de forma que eu possa copiá-las depois e usar os dados no Matlab. O problema é que mesmo com o prescaler de 16 e usando um baud rate de 1 M eu… Leia mais »

Bruno
Visitante
Bruno

Fábio, Boa noite! Meu nome é Bruno e minha pergunta não está relacionada a esse poste. Mas tenho que desenvolver um projeto para o meu Mestrado e, acredito que você possa me ajudar. Gostaria de trocar o cristal de 16 MHz do meu arduino UNO por uma frequência de 10 MHz (Clock externo). Esse clock vem de um relógio atômico de césio. No manual do ATMEGA 328P (9.8 - External Clock - pagina 35) diz que tem que alterar CKSEL para 0000 e o SUT fuse para 00. Como faço isso?
Desde já agradeço.

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Olá Bruno,

Você deverá mudar os fuses, conforme a frequência desejada. acho que esse artigo pode ajudar: http://www.instructables.com/id/How-to-change-fuse-bits-of-AVR-Atmega328p-8bit-mic/step2/Understanding-Fuse-bits-from-datasheet/

Rhonei Patric
Visitante
Rhonei Patric

Boa noite, este código pode ser utilizado para alterar o Prescaler do arduino Mega?

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Sim, pode usar para o ATmega2560.

Abraços

Rhonei Patric
Visitante
Rhonei Patric

Eu consigo amostrar um sinal com uma taxa menor que 9600Hz? Quero saber qual a menor taxa de amostragem que eu consigo ler um sinal sem perder informações.

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Se você estiver trabalhando com o Cristal de 16 MHZ, não. Terá que alterar o clock principal para reduzir a taxa.

Rhonei Patric
Visitante
Rhonei Patric

Se eu alterar a taxa de amostragem do conversor A/D com a programação do artigo, quando eu rodar outro programa a conversão será feita na taxa modificada ou na taxa padrão do arduino?

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Olá Rhonei, sempre que atualizar o programa ele vai usar as configurações do programa atual.

Rhonei Patric
Visitante
Rhonei Patric

Hum, ai para eu voltar para a configuração padrão tenho que reconfigurar a programação do clock, certo?

Outra dúvida, existe melhoria do arduino MEGA em relação ao arduino UNO nesse aspecto?
Estou fazendo aquisição da tensão de saída de um conversor cc-cc buck junto com o simulink porém a simulação está muito lenta, estou em dúvida se isso é devido à amostragem do arduino, e se isso poderia ser melhorado utilizando um arduino MEGA

Diego Fraga
Visitante
Diego Fraga

Fábio, pode me explicar o código a seguir e dizer qual a referencia é usada quando uso o arduino UNO? long EnergyMonitor::readVcc() { long result; //not used on emonTx V3 - as Vcc is always 3.3V - eliminates bandgap error and need for calibration //http://harizanov.com/2013/09/thoughts-on-avr-adc-accuracy/ #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__) ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB1286__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on the ATmega2560 http://openenergymonitor.org/emon/node/2253#comment-11432 #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__)… Leia mais »

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Olá Diego,

Conforme a operação:
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

O bit REFS0 está setado e RRFS1 está em zero. Dessa forma a tensão de referência está selecionada para AVcc. No caso do Arduino é 5V.

Está com algum problema no código?

Abraços

Diego Fraga
Visitante
Diego Fraga

Obrigado Fábio,

Esse código faz parte de uma biblioteca que estou usando e ainda sou leigo no assunto, ainda não compreendo muita coisa, principalmente no que concerne as configurações do arduino, mas estou tentando aprender.

E, parabéns pelo "post", as informações abordadas (e seu comentário) foram esclarecedoras e serão muito úteis em meu código.

Valeu!

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Opa Diego, qualquer dúvida fique a vontade para perguntar.

Sucesso nos estudos.

Abraços

Fernando França
Visitante

Bom dia Fábio. Excelente artigo, parabéns. Estou projetando um medidor inteligente para qualidade de energia como trabalho de conclusão e pensei em utilizar o ATMega 328P como µC para minha parte de aquisição de dados. Entretanto as normas do Prodist (ANEEL), estabelecem que instrumentos de medição devem considerar para fins de distorção da componente fundamental até a 25ª harmônica. Ou seja, 60 x 25 = 1500 Hz. Sendo então pela frequência de Nyquist 3 KHz de amostragem. Com os 10 bits de resolução dele, parece que estou dentro e seu artigo me deixou otimista quanto ao comportamento do ADC. Mas… Leia mais »

Carlos
Visitante
Carlos

Boa tarde, também estou pensando nesse mesmo assunto para o meu TCC. Acredito que com a frequencia de amostragem não haverá problemas, mas a minha maior dúvia é quanto à resolução: medir -180 a 180Vpp transformados para 0 a 5V, com 10 bits de resolução leva à uma precisão de décimo de volt, que não sei se é aceitável, visto que a amplitude das últimas harmônicas deve ser muito pequena e provavelmente afetaria na questão dos fatores de distorção.

Matheus Tieppo
Visitante
Matheus Tieppo

Boa Tarde Fabio, gostaria de saber se é possível ler e gravar no sd 4000 amostrar por segundo de uma senoide 60 hz.

desde já agradeço

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Com esse Arduino você ficará limitado. Talvez você consiga essa taxa de amostragem o Arduino Due ou outra arquitetura.

Abraços