Convertidor analogico digital de los microcontroladores AVR
1. CONVERTIDOR ANALOGICO DIGITAL
Las características del convertidor analógico digital del Atmega16 son las siguientes:
- Resolución de 10 bits: la salida tiene n=10 bits.
- 8 canales, pero solo realiza la conversión de datos provenientes de un canal en cada
momento.
- Si el voltaje de referencia es el que viene por defecto, es decir, 5 voltios, entonces:
- El tamaño del paso es de 5v/1024 = 4.88mv
- Exactitud es de +_ 2LSB, es decir, 9.76mv
- El ritmo del reloj del ADC puede ser diferente del ritmo de la CPU.
- El ADC está provisto de un prescalizador que decide el ritmo del reloj del ADC.
REGISTROS IMPORTANTES DEL ADC
Estos registros son los siguientes:
- ADCMUX
- ADCH/ADCL
- ADCCSRA
- SFIOR
ADMUX
- Permite seleccionar el canal del ADC.
- Configurar la justificación de los resultados del ADC.
- Seleccionar la referencia del ADC.
Los voltajes de referencia pueden ser:
- AREF, es el que viene por defecto. Voltaje interno apagado.
- AVCC, le colocamos un capacitor externo en el pin AREF.
- Voltaje interno de 2.56v y un capacitor externo en el pin AREF.
Normalmente se usa el modo AVCC, pero también se puede usar el modo AREF cuando la
señal analógica tiene un rango dinámico diferente.
La selección del canal del ADC también corre a cargo de este registro. Pero estos mismos bits
también permiten seleccionar la ganancia de las entradas diferenciales. Esta ganancia puede
ser de 1, 10 o 200.
Una bandera del registro ADCMUX nos permite elegir la forma en que vamos a expresar el
resultado obtenido. Las posibilidades se pueden ver en la siguiente figura:
2. Es importante leer en primer lugar el byte menos significativo y luego el más significativo.
ADCCSRA
Es un registro que nos permite
- habilitar la interrupción del ADC
- monitorizar las banderas del ADC
- seleccionar los bits del prescalizador
- configurar el modo de operación del ADC
Es de precisar que el ADC presenta dos modos de operación:
- manual: habilitamos el bit ADSC para iniciar la conversión.
- auto-disparo: un evento previamente configurado inicia la conversión del
convertidor.
En caso de usar el prescalizador, es de precisar que lo que se hace es dividir el reloj de la
CPU y usarla como el reloj del ADC.
SFIOR
Lo más relevante de este registro es que nos permite elegir el evento que provocara el inicio
de la conversión del ADC en el modo auto-disparo. Cabe decir que es una gran variedad de
eventos, algunos de los cuales son:
- comparador analógico.
- Interrupciones externas
- Eventos de los timers (desbordamiento, interrupciones).
PASOS PARA USAR EL ADC
Paso 1: configurar el ADC usando los registros ADCMUX, ADCCSRA y SFIOR.
- Se selecciona el canal
- Se selecciona el voltaje de referencia
- Se configura la justificación del resultado de la conversión.
- Habilitar o deshabilitar el auto-disparo del ADC
- Habilitar o deshabilitar la interrupción del ADC.
3. - Selección del prescalizador.
Paso 2: Iniciar la operación del ADC.
- Ponemos en alto la bandera ADSC del registro ADCCSRA.
Paso 3: Extraer el resultado
- Esperamos hasta que la bandera ADSC se pone a 0.
- Después leemos primero el byte ADCL y después ADCH.
EJEMPLO: escribir un programa que sea capaz de realizar la conversión de una señal
sinusoidal y mostrar el resultado en unos LEDs.
Paso 1: configuro el ADC.
- Canal: ADC0
- Tensión de referencia: AVCC =5V
- Justificación derecha o izquierda del resultado: izquierda, tomamos los 8 bits más
significativos, es decir, ADCH.
- Habilitar o deshabilitar el auto-disparo del ADC: deshabilitado.
- Habilitar o deshabilitar la interrupción del ADC: deshabilitado.
- Prescalizador: 2 (conversión más rápida).
El programa completo es el siguiente:
#include<avr/io.h>
int main (void){
unsigned char result;
DDRB = 0xFF; // set port B for output
// Configure the ADC module of the ATmega16
ADMUX = 0b01100000; // REFS1:0 = 01 -> AVCC as reference,
// ADLAR = 1 -> Left adjust
// MUX4:0 = 00000 -> ADC0 as input
ADCSRA = 0b10000001; // ADEN = 1: enable ADC,
// ADSC = 0: don't start conversion yet
// ADATE = 0: disable auto trigger,
// ADIE = 0: disable ADC interrupt
// ASPS2:0 = 001: prescaler = 2
while(1){ // main loop
// Start conversion by setting flag ADSC
ADCSRA |= (1 << ADSC);
// Wait until conversion is completed
while (ADCSRA & (1 << ADSC)){;}
// Read the top 8 bits, output to PORTB
result = ADCH;
PORTB = ~result;
}
return 0;
}
4. USANDO LA INTERRUPCION DEL ADC
Este enfoque es muy diferente del anterior. En el caso anterior hemos usado el polling para
saber cuándo realizar la lectura del ADC. Para lo cual, hemos estado controlando el estado
de una bandera, concretamente la bandera ADSC del registro ADCCCSRA.
En este caso, el ADC lanza una interrupción cuando se completa la conversión de los datos.
Para usar esta interrupción debemos habilitarla previamente en el registro ADCCSRA,
concretamente a través de la bandera ADIE.
Dentro del ISR es donde escribimos el código que nos permite leer el resultado de la
conversión del ADC, leyendo en primer lugar el ADCL y después el ADCH.
Ese modo es muchas veces combinado con el auto-disparo visto antes.
El mismo problema anterior pero con interrupciones es el siguiente:
#include<avr/io.h>
#include<avr/interrupt.h>
volatile unsigned char result;
ISR(ADC_vect){
result = ADCH; // Read the top 8 bits, and store in variable result
}
int main (void){
DDRB = 0xFF; // set port B for output
// Configure the ADC module of the ATmega16
ADMUX = 0b01100000; // REFS1:0 = 01 -> AVCC as reference,
// ADLAR = 1 -> Left adjust
// MUX4:0 = 00000 -> ADC0 as input
ADCSRA = 0b10001111; // ADEN = 1: enable ADC,
// ADSC = 0: don't start conversion yet
// ADATE = 0: diable auto trigger,
// ADIE = 1: enable ADC interrupt
// ASPS2:0 = 002: prescaler = 2
sei(); // enable interrupt system globally
while(1){ // main loop
ADCSRA |= (1 << ADSC); // start a conversion
PORTB = ~result; // display on port B
}
return 0;
}