INICIO WEB

                        

                       

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

123.gif (858 bytes)

.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
                  
                                         

ARRIBA