CONVERTIDOR A/D DE BAJO COSTE |
DESCRIPCIÓN |
Esta aplicación se puede usar en cualquier dispositivo AVR con comparador analógico y muestra como puedes hacer un convertidor A/D usando un dispositivo AVR, una resistencia externa y un condensador externo. Esta solución utiliza la interrupción por desbordamiento del Timer/Contador0 además de la interrupción del comparador analógico. El uso de las interrupciones libra el MCU mientras la conversión se está produciendo. |
Para minimizar el uso de componentes externos, este convertidor A/D utiliza la carga de un condensador (controlado por el pin 2 del Puerto D) a través de la resistencia durante la conversión. |
La tensión a través del condensador seguirá una curva exponencial de tensión frente a tiempo. Para ajustar el rango de tensión a 2/5Vdd, la curva exponencial es una buena aproximación de una línea recta. |
Esto le hace posible medir el tiempo que toma antes que el voltaje por el condensador iguale el voltaje al que será convertido. Para hacer esto nosotros usamos el comparador analógico. El comparador dará una interrupción cuando el voltaje por el condensador suba por encima de la medida de tensión. La salida es dividida en 64 niveles diferentes. |
Para asegurar la correcta temporización, la constante de tiempo de la red RC deben satisfacer que 512*(1/f) = -R*C*ln(1-2/5). Para que el convertidor A/D opere propiamente, el condensador debe ser completamente descargado entre cada conversión. Esto se realiza permitiendo que la descarga tomar un mínimo de 200us. |
Inicialización |
1. Llamar a convert_init |
2. Habilitar las interrupciones globales (con sei) |
Conversión A/D |
1. Llamar a AD_convert |
2. Esperar que la conversión se complete (t a set)(menos que 521 ciclos) |
3. Leer dato del resultado |
.include "1200def.inc" | |
;***** Constantes | |
.equ preset = 192 | ;Constante de Preset del T/C0 (256-64) |
;***** Registros globales de convertidor A/D | |
.def result = r16 | ;Resultado y dato intermedio |
.def temp = r17 | ;Registro de salida |
;* |
;* COMIENZO DE PROGRAMA - LA EJECUCIÓN COMIENZA AQUÍ |
;* |
.cseg |
.org $0000 | |
rjmp RESET | ;Salto relativo a la subrutina Reset |
.org OVF0addr | |
rjmp ANA_COMP | ;Salto relativo por desbordamiento del Timer0 |
.org ACIaddr | |
rjmp ANA_COMP | ;Salto relativo a la subrutina ANA-COMP |
;* |
;* ANA_COMP - rutina de interrupción del comparador analógico |
;* |
;* Esta rutina se ejecuta cuando ocurre uno de los dos eventos siguientes: |
;* 1. Interrupción por desbordamiento del Timer/contador0 |
;* 2. Interrupción del Comparador Analógico |
;* Ambos eventos indican el final de una conversión. El desbordamiento del Timer si |
;* la señal está fuera de rango, y el Comparador Analógico si está en el rango. |
;* El offset debe ser corregido, y el flag t se pondrá a set. |
;* Debido a los ciclos necesarios para el manejo de interrupción, es necesario restar |
;* 1 más de los que se sumaron anteriormente. |
;* |
;* Número total de words : 7 |
;* Número total de ciclos : 10 |
;* Registros bajos usados : 0 |
;* Registros altos usados : 2 (result,temp) |
;* Flags de estado : 1 (flag t) |
;* |
ANA_COMP: |
in result,TCNT0 | ;Cargar el valor del Timer |
clr temp | ;Detener el timer0 |
out TCCR0,temp | |
subi result,preset+1 | ;Corregir la salida del A/D |
cbi PORTD,PD2 | ;Comienzo de descarga |
set | ;Poner a set el flag de conversion completa |
reti | ;Volver de la interrupción |
;* |
;* convert_init - Subrutina para la inicialización del convertidor A/D |
;* |
;* Esta rutina inicializa el convertidor A/D. Establece el Timer y el comparador |
;* analógico. La interrupción del comparador analógico se inicia por un flanco de |
;* subida en AC0. Para habilitar el convertidor A/D, el flag de interrupción global |
;* debe estar a set (con SEI). |
;* |
;* El flag de conversión completa (t) es borrado. |
;* |
;* Número total de words : 6 |
;* Número total de ciclos : 10 |
;* Registros bajos usados: 0 |
;* Registros altos usados : 1 (result) |
;* Flags de estado usados: 0 |
;* |
convert_init: |
ldi result,$0B | ;Iniciar el comparador |
out ACSR,result | ;y habilitar la interrupción del comparador |
ldi result,$02 | ;Habilitar la interrupción del Timer |
out TIMSK,result | |
sbi PORTD,PD2 | ;Poner la carga y descarga del convertidor |
;como salida | |
ret | ;Volver de la subrutina |
;* |
;* AD_convert - Subrutina para empezar la conversión A/D |
;* |
;* Esta subrutina comienza la conversión. Carga el valor del offset en el timer0 |
;* e inicia el timer. También inicia la carga del condensador. |
;* |
;* Número total de words : 7 |
;* Número total de ciclos : 10 |
;* Registros bajos usados : 0 |
;* Registros altos usados : 1 (result) |
;* Flags de estado usados : 1 (flag t) |
;* |
AD_convert: |
ldi result,preset | ;Borrar contador |
out TCNT0,result | ;y cargar el valor del offset |
clt | ;Borrar el flag de conversión completa (t) |
ldi result,$02 | ;Iniciar el timer0 con el prescaler f/8 |
out TCCR0,result | |
sbi PORTB,PB2 | ;Comienzo de la carga del condensador |
ret | ;Retorno de subrutina |
;* | |
;* Programa ejemplo | |
;* |
;* Este programa puede usarse como ejemplo de como establecer correctamente el |
;* convertidor A/D. |
;* NOTA! Para asegurar el funcionamiento correcto, asegurarse que el periodo de |
;* descarga del condensador sea mayor que 200us antes de cada conversión. |
;* Los resultados de la conversión están presentes en el Puerto B. |
;* Para asegurar la descarga adecuada tenemos que añadir un bucle de retardo. |
;* Este bucle es de 11000 ciclos. Dará un retardo de 550us con un oscilador |
;* a 20MHz (11ms con un oscilador a 1MHz). |
;* |
RESET: | |
rcall convert_init | ;Inicializar el convertidor A/D |
sei | ;Habilitar las interrupciones globales |
ldi result,$ff | ;Establecer el Puerto B como salida |
out DDRB,result | |
Delay: | |
clr result | ;Borrar el contador result |
ldi temp,$f0 | ;Reset del contador temp |
loop1: | |
inc result | ;Incrementar cuenta del contador result |
brne loop1 | ;Analizar si ha finalizado un bucle interno |
inc temp | ;Incrementar cuenta del contador temp |
brne loop1 | ;Analizar si el retardo ha finalizado |
rcall AD_convert | ;Comenzar la conversión |
Wait: | |
brtc Wait | ;esperar hasta que la conversión se complete |
out PORTB,result | ;Escribir resultado en el Puerto B |
rjmp Delay | ;Repetir conversión |