Programando AVR na IDE e placa Arduino - ADC
Nas postagens anteriores mostrei como configurar portas, como os Timers trabalham gerando pulsos e PWM. Neste agora vou mostrar como o ADC (Analog to Digital Converter) trabalha e colocar ele para funcionar em conjunto com um PWM. Pegando um sinal analógico em um porta e controlando o brilho de um LED.
Se você chegou aqui direto, é aconselhável ler o post sobre portas e sobre PWM primeiro, para entender como fazer o controle de registradores e como o PWM trabalha.
Para os exemplos será necessário além do Arduino Uno um hardware adicional, composto de um resistor (330 ohms), um LED e um potenciômetro podendo ser de 5k a 100k ohms.
Existe dois modos de se trabalhar com ADC no ATMega 328P, Single Mode e Free Running. Em Single Mode é necessário via código inicializar a conversão manualmente cada vez que for necessário converter o valor analógico. Já no Free Running ele passa a converter interruptamente sempre iniciando uma assim que a anterior terminar.
Para trabalhar em Single Mode, primeiro o registrador a ser setado é o ADMUX, detalhado na pagina 257 do datasheet. Nele precisamos setar como será a tensão de referência do ADC, mais detalhes sobre essa tensão está na página 257 do datasheet. O hardware do Arduino é construído com um capacitor de 100nF no pino AREF conforme figura abaixo:
A página 257 do datasheet , tabela 24.3 mostra que para este caso é necessário setar o bit REFS0 do registrador ADMUX:
Além desse bit, precisamos setar qual porta analógica vamos trabalhar, a pagina 258 do datasheet, tabela 24.4 tem a configuração binária dos bits do registrador, chamados de canais:
Vamos trabalhar com a porta ADC1 que na pinagem do Arduino corresponde ao pino A1, na pinagem AVR ao pino PC1. Os pinos PC0 ao PC5 são todos ADC. Sendo necessário setar o bit MUX0 do registrador ADMUX para trabalhar com a porta PC1.
Assim a configuração do registrador ADMUX fica como abaixo:
ADMUX |= (1 << REFS0) | // AVCC com capacitor externo AREF pin (1 << MUX0); // Configura o canal ADC1
No registrador ADCSRA detalhado na pagina 258 do datasheet vamos setar o bit ADEN para habilitar o ADC e os bits ADPSx para o prescaler. O prescaler é necessário para utilizar o clock do micro controlador como clock do ADC. No caso vamos usar um prescaler 64 que irá trabalhar em 250khz (16mhz / 64) conforme tabela abaixo. Detalhes sobre o prescaler pode ser encontrado na pagina 249 do datasheet.
Assim a configuração do registrador ADCSRA fica como abaixo:
ADCSRA |= (1 << ADEN) | // Habilita DAC (1 << ADPS2) | // Define a taxa de conversão do ADC para prescaler 64 (16MHz / 64 = 250kHz) (1 << ADPS1); // Define a taxa de conversão do ADC para prescaler 64 (16MHz / 64 = 250kHz)
No loop infinito precisamos inicializar a conversão a cada ciclo usando o bit ADSC do registrador ADCSRA
ADCSRA |= (1 << ADSC); // Inicializa conversão
No registrador ADC teremos o valor da conversão em 10 bits, como cada registrador do AT 328P possui 8 bits, o ADC fica composto pelo ADCL e ADCH. Esses registradores estão detalhados na pagina 259 do datasheet (24.9.3 ADCL and ADCH – The ADC Data Register).
As configurações do PWM para gerar o controle de brilho do led já foram detalhadas na postagem anterior e o valor de OCR0A será alimentado com o valor do registrador ADC dividido por 4, já que ADC trabalha em 10 bits (0-1023) e OCR0A em 8 bits (0-255).
O código para Single Mode fica como abaixo:
int main(void) { /// *** Config PWM *** /// DDRD |= (1 << DDD6); // Habilita porta PD6 (Arduino pin6) para PWM TCCR0B |= (1 << CS00) | // Prescaler 64 (1 << CS01); // Prescaler 64 TCCR0A |= (1 << COM0A1) | // Limpa OC0A na comparação OCR0A (1 << WGM00) | // Habilita waveform para fast PWM (1 << WGM01); // Habilita waveform para fast PWM /// *** Config ADC *** /// ADMUX |= (1 << REFS0) | // AVCC com capacitor externo AREF pin (padrão Arduino) (1 << MUX0); // Configura o canal ADC1 ADCSRA |= (1 << ADEN) | // Habilita DAC (1 << ADPS2) | // Define a taxa de conversão do ADC para prescaler 64 (16MHz / 64 = 250kHz) (1 << ADPS1); // Define a taxa de conversão do ADC para prescaler 64 (16MHz / 64 = 250kHz) while (1) { ADCSRA |= (1 << ADSC); // Inicializa conversão OCR0A = (ADC / 4); // Grava o valor para o PWM } return 0; }
Para trabalhar em Free Running o código é bem parecido com a diferença que precisamos habilitar o Free Running com o bit ADATE do registrador ADCSRA.
ADCSRA |= (1 << ADATE) | // Habilita auto-trigger (Free Running)
Não é preciso mais deixar a inicialização da conversão (bit ADSC), dentro do loop. Sendo necessário apenas uma inicialização, a partir daí o conversor sempre irá fazer nova conversão após o termino da primeira.
O código para Free Running fica como abaixo:
int main(void) { /// *** Config PWM *** /// DDRD |= (1 << DDD6); // Habilita porta PD6 (Arduino pin6) para PWM TCCR0B |= (1 << CS00) | // Prescaler 64 (1 << CS01); // Prescaler 64 TCCR0A |= (1 << COM0A1) | // Limpa OC0A na comparação OCR0A (1 << WGM00) | // Habilita waveform para fast PWM (1 << WGM01); // Habilita waveform para fast PWM /// *** Config ADC *** /// ADMUX |= (1 << REFS0) | // AVCC com capacitor externo AREF pin (padrão Arduino) (1 << MUX0); // Configura o canal ADC1 ADCSRA |= (1 << ADEN) | // Habilita DAC (1 << ADPS2) | // Define a taxa de conversão do ADC para prescaler 64 (16MHz / 64 = 250kHz) (1 << ADPS1) | // Define a taxa de conversão do ADC para prescaler 64 (16MHz / 64 = 250kHz) (1 << ADATE) | // Habilita auto-trigger (Free Running) (1 << ADSC); // Inicializa conversão while (1) { OCR0A = (ADC / 4); // Grava o valor para o PWM } return 0; }
Movimentando o potenciômetro o led irá diminuir e aumentar o brilho.
Referência:
Códigos de exemplo do livro AVR Programming:
Comentários
Postar um comentário