Saltar al contenido

Conversión Análogo/Digital (A/D)

Hola controleros y controleras, bienvenidos nuevamente a otra entrada de nuestro curso de microcontroladores PIC, hoy vamos a aprender a utilizar la conversión análogo digital del PIC, el cual nos va a permitir leer señales físicas del mundo real en nuestros proyectos.

Antes que nada, te invito a que le des un vistazo a todo nuestro 👉  curso de PIC Gratuito.

También te invito a que te unas a la comunidad de CONTROLEROS y CONTROLERAS en YouTUBE para seguir aprendiendo de estos temas de microcontroladores, control, programación, instrumentación entre otros:

Convertidor Análogo/Digital ADC PIC

Los microcontroladores PIC16F887 poseen un conversor análogo/digital de 10 bits y 14 canales de entrada (AN0, AN1,…,AN13).

Una señal análoga es una señal continua que posee valores que van variando con el tiempo. A diferencia de una señal digital, que tiene valores discretos en cada punto de muestreo, una señal análoga presenta fluctuaciones constantemente. En la siguiente figura podemos ver un patrón analógico (representado como una onda sinosuidal) junto con un patrón digital (representado como líneas discretas).

analogo digital

Con el microcontrolador, lo que se hace, es aproximar una señal análoga por medio de pequeños cuadros rectángulos digitales, como  puede apreciarse en la figura de encima.

Entre más resolución tenga nuestro microcontrolador, mas pequeños pueden ser los rectangulos que se forman y más aproximado puede quedar nuestra señal análoga. En otras palabras aumentamos el muestreo de la señal para aproximarnos de mejor forma a la forma de onda original.

Resolución señal ADC

Para contextualizar la importancia del ADC del PIC, vamos a suponer por ejemplo que si se tiene un sensor de nivel capaz de generar una señal análoga, esto quiere decir que dicho sensor no solo está en la capacidad de indicar si el tanque esta lleno o vacío, sino que además indica la altura del nivel del tanque en todo momento donde la señal será proporcional al nivel del tanque.

Para poder detectar las señales análogas con un microcontrolador PIC debemos emplear el conversor A/D (ADC PIC) el cual toma la señal análoga y la transforma en un valor o número digital (binario).

En el caso del microcontrolador PIC16F887 el conversor A/D tiene 10 bits y la señal análoga de entrada puede estar entre 0V y 5V y su conversión a un número digital seria de 0 a 0v y de 1023 a 5v.

Sin embargo el conversor A/D de un microcontrolador PIC posee dos niveles de referencia VREF+ y VREF- que indican entre que valores estará comprendida la señal análoga de entrada.

Es importante destacar que el voltaje mínimo diferencial es de 2V, es decir la diferencia entre VREF+ y VREF- no puede ser mayor a 2V.

En la siguiente figura, puede notar que VREF- y VREF+ están ubicados en los pines 4 y 5 respectivamente.

vref
Pin Rojo(VREF+) Pin Verde (VREF-), Pines morados son las entradas Análogo Digitales

Resolución del Conversor ADC en PIC

La resolución de un microcontrolador PIC depende del voltaje de referencia que se establezca en el dispositivo.

Generalmente si no se define este voltaje de referencia el dispositivo usará el voltaje de alimentación como siendo la referencia (es decir 5v)

resolucion=\dfrac{V_{REF_+}-GND}{1024}

Así, por ejemplo, si VREF+=5V y VREF-=0V:

resolución= \dfrac{5V-0V}{1024} = 4.8mV

Por lo tanto, cuando la señal análoga sea 0V, a esta señal le corresponde un número de 0. Cuando sea 2.5V le corresponde un número de 512. Si es 5V, le corresponde un número de 1023. Claro está, que puede tomar cualquier valor entre 0-1023.

Si VREF+=5V y VREF-=0V se puede determinar en todo momento a que número digital aproximado corresponde cualquier señal análoga de entrada, con la fórmula:

\dfrac{V_{Entrada}}{4.8mV}=\dfrac{V_{Entrada}}{0.0048V}

Por ejemplo si la señal análoga es 2V, el número digital aproximado, es:

\dfrac{2V}{0.0048V}=416 bits

La tensión de referencia VREF+ puede implementarse con la tensión interna de alimentación VDD, o bien, con una externa que se pone en el pin RA3/AN3/ VREF+.

PASOS PARA TRABAJAR CON EL CONVERSOR A/D o ADC PIC

1. En el encabezado del programa incluir la siguiente línea, si se va a trabajar el conversor A/D a 10 bits ya que por defecto funciona a 8 bits.

#DEVICE ADC=10

2. En el programa principal

a. Configurar las entradas análogas.
b. Seleccionar el tipo de reloj del conversor A/D.
c. Especificar el canal a utilizar para la conversión.

a. 

SETUP_ADC_PORTS(Valor);

Esta función configura los pines del ADC para que sean entradas análogas, digitales o alguna combinación de ambos. Las  combinaciones permitidas varían de acuerdo al microcontrolador.

Las constantes (ALL ANALOG) todas las entradas como análogas y (NO_ANALOG) ninguna entrada como análoga son válidas para todos los microcontroladores.

b.

SETUP_ADC (Modo)

Selecciona el tipo de reloj del conversor A/D Modo puede ser:

ADC_CLOCK_DIV_2
ADC_CLOCK_DIV_8
ADC_CLOCK_DIV_32
ADC_CLOCK_INTERNAL

Este es el tiempo necesario para obtener el valor digital de la tensión analógica de entrada. Este tiempo depende de la fuente de reloj que se seleccione para la conversión. Para realizar una correcta conversión A/D, el reloj debe seleccionarse para asegurar un tiempo de 1.6us.

c.

SET_ADC_CHANNEL (Canal)

Especifica el canal a utilizar por la función

READ_ADC()

3. Leer el valor de la conversión

I=READ_ADC ()

Esta función lee el valor digital del conversor análogo a digital.

Configuraciones de ADC en PIC C

En la especificación del canal análogo tenemos varias opciones. Por ejemplo el PIC16F887 tiene 13 pines analgos/digital (ADC), que están pintados de morado en la figura de arriba y van desde AN0 hasta AN13.

Para designar cual pin del PIC queremos usar como puerto análogo, tenemos la siguiente tabla proporcionada por la librería del propio PIC dentro del compilador PIC C.

// Constants used in SETUP_ADC_PORTS() are:
#define sAN0            1       //| A0
#define sAN1            2       //| A1
#define sAN2            4       //| A2
#define sAN3            8       //| A3
#define sAN4            16      //| A5
#define sAN5            32      //| E0
#define sAN6            64      //| E1
#define sAN7            128     //| E2
#define sAN8        0x10000     //| B2
#define sAN9        0x20000     //| B3
#define sAN10       0x40000     //| B1
#define sAN11       0x80000     //| B4
#define sAN12      0x100000     //| B0
#define sAN13      0x200000     //| B5
#define NO_ANALOGS      0       // None
#define ALL_ANALOG   0x1F00FF    // A0 A1 A2 A3 A5 E0 E1 E2 B0 B1 B2 B3 B4 B5

En otras palabras, si queremos usar el puerto analogo AN0 que vendria a ser el PIN2 del PIC declaramos la instrucción:

setup_adc_ports(sAN0);     //Pongo el puerto AN0 como analogo

o opcionalmente digitando el numero en binario o hexadecimal o decimal:

//Pongo el puerto AN0 como analogo
setup_adc_ports(0b00000001);     //Binario
setup_adc_ports(0x01);           //Hexadecimal
setup_adc_ports(1);              //Decimal
Calculo de entradas ADC en PIC

Ahora, si por ejemplo queremos combinar varios pines como entradas ADC, por ejemplo, deseamos configurar estas entradas AN0, AN1, AN7 y AN13, debemos configurarla usando directamente los numeros en cualquier (escoge uno de los 3) representación (Binario, Hexadecimal o Decimal), para esto, les recomiendo usar la calculadora de Windows, y Colocarla en Formato Programador, y luego hacer la suma en Hexadecimal del numero que corresponde cada entrada analoga: AN0 (0x01), AN1(0x02), AN7( 0x80) y AN13(0x200000). En lo personal yo prefiero siempre trabajar en Hexadecimal.

//Pongo el puerto AN0,AN1,AN7 y AN13 como analogos
setup_adc_ports(0b001000000000000010000011);     //Binario
setup_adc_ports(0x200083);                       //Hexadecimal
setup_adc_ports(2097283);                        //Decimal

Voltaje de Referencia en microcontrolador PIC

Existe una instrucción en el compilador que nos permite configurar el VREF de un microcontrolador PIC en el compilador CCS C Compiler:

setup_adc_ports(ALL_ANALOG, reference)

reference: corresponde a la referencia de voltaje para con la cual queremos configurar el ADC. Las opciones válidas dependen del dispositivo utilizado; por eso debes buscar en el archivo .h del dispositivo para ver todas las opciones. Las opciones típicas en el 16F877A, 16F887 y 18F4550 incluyen:

OpcionesDescripción
VSS_VDDRango de 0 a Vdd
VREF_VREFRango de VREF- a VREF+
VREF_VDDRango de VREF- a Vdd
VSS_VREFRango de 0 a VREF+

por ejemplo si deseamos un voltaje de referencia típico de 3.3v, simplemente en el PIN RA3/AN3/ VREF+ conectamos el voltaje de referencia, o sea 3.3v.

Y configuramos el comando de la siguiente forma:

setup_adc_ports(ALL_ANALOG,VSS_VREF);

Termocupla tipo K con PIC

Termopar tipo K con PIC

EJEMPLO CONVERSOR ADC PIC

Hacer un termómetro digital en el PIC16F887 utilizando un sensor de temperatura lineal (LM35) conectándolo en el pin RA0.

Utilice la conversión análogo digital ADC PIC para poder leer la temperatura del sensor y visualice la temperatura en un LCD16x2.

Solución

Como se muestra en proteus, cuando el sensor LM35 marca 25°C, es porque el sensor está enviándole al PIC un voltaje de 0.25V.

Con base a este dato se puede hacer la conversión de BITS a °C (Recordando que cuando el PIC lee el puerto análogo digital, lo que almacena es un numero en bits de 0 – 1024). Utilizando un regla de tres, se puede determinar que.

BITS=\dfrac{(0.25V)(1024bits)}{5V}=51.2bits

Conociendo el número de bits que arroja el sensor a los 25 °C se procede a calcular un factor para transformar los bits a °C .

T=\dfrac{25C*Valor_{leido}bits}{51.2bits}=Valor_{leido}*0.4883

ADC

Demostración Práctica

Código de Implementación:

A continuación se presenta el código para que lo copies y lo pegues en tu compilador y puedas reproducirlo. Recuerda que para ver el código debes compartir o darle me gusta al contenido de este post para que más personas se beneficien de esta información.

#INCLUDE <16f887.h>
#device adc=10
//#USE DELAY(CLOCK=4000000) // Reloj interno 4MHz
#use delay(clock=4000000,crystal)//Crystal Externo 4MHz
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,NOPUT,NOLVP
#INCLUDE <LCD.C>

#BYTE PORTA= 5
#BYTE PORTD= 8

long bits;     //Variable almacena los bits
float tem;     //Almacena la temperatura

void main()
{
   set_tris_a(0b00000001);          //Pongo el RA0 como entrada
   set_tris_d(0);                   //Pongo el PuertoD como Salida
   setup_adc_ports(all_analog);     //Pongo todo el puerto a analogo
   setup_adc(adc_clock_internal);   //Selecciono reloj interno para conversion
   lcd_init();                      //Inicializo el LCD
   lcd_putc("\f");                  //Borro el LCD
   
   while(1)
   {
       set_adc_channel(0);          //Selecciono el canal 0 (RA0)
       delay_ms(1);                 //llamo retardo de 1 ms
       bits=read_adc();             //Guarde el dato del LM en tempe
       
       tem=bits*0.4882;              //Conversion de bits a temperatura
       lcd_gotoxy(1,1);             //Ubiquese en la posicion 1,1
       lcd_putc("LA TEMPERATURA");
       lcd_gotoxy(2,2);             //Ubiquese en la posicion 2,2
       printf(lcd_putc,"ES C= %f    ",tem);  //Muestra el valor numerico de la conversionconversion
       delay_ms(1000);  
   }
}

Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:

👉 Invitar a Sergio a un Café ☕️

Que esten muy bien, nos vemos en la siguiente entrada.

Entradas relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Comentarios (14)

Tengo un error en: #DEVICE ADC=10
como lo soluciono?

Responder

Hola
Espero que se encuentren con bien. Yo deseo aplicar este tema del ADC, pero con el sensor acs 712, (sensor de efecto hall), si bien, ya lo hice, pero no me muestra una lectura.
¿Me podrían ayudar por favor?

Responder

Hola! disculpa de casualidad tendras el diagrama utilizado para esa practica? es que me dejaron hacer uno similar he implemntarlo en la protoboard u.u

Responder

Si deseo leer 10 señales, para luego solo mostrar el promedio de esos 10 en el LCD, como se podría hacer ? Saludos

Responder

Puedes hacer un FOR y modificar el canal ADC.
bits = 0
for(int i=0;i<10 Responder

hola sergio! un saludo ante todo, y gracias por tus videos, que son de mucha ayuda.
bueno tengo una consulta!
he tenido problemas al querer fusionar 2 de tus códigos, el de conversión análogo-digital y el de control de velocidad de motor.
lo que quiero hacer es poder controlar la velocidad de un motor con la lectura de temperatura. pienso que se debe a los fusibles, pero no estoy seguro de ello. gracias ante todo por la molestia

Responder

Hola Armando, no creo que sean los fuses. Creo más bien que es el valor del duty cicle y la configuración de la frecuencia del PWM. Si lo configuras a 1Khz entonces debes mandar un duty cicle entre 0 y 1000. Para eso en el código deberás establecer una conversión. Definir cual va a ser tu máxima temperatura admisible. Supongamos que el máximo sea 60C y el mínimo 20C, entonces haces una interpolación para que cuando este en 20C te entregue un duty de 0, cuando esté en 40C te entregue un duty de 500 y cuando esté en 60C te entregue un duty de 1000.

Responder

Hola Sergio tengo un problema con la lectura de un sensor de Oxigeno, muestra los datos correctos y despues de 3 pantallazos se pasa a cero, a que se debe esto existe forma de eliminar este dato errado? Muchas gracias

Responder

Te refieres a tres pantallazos en el LCD? Estás implementando el mismo código visto aquí en la entrada?

Responder

Hola Sergio, gracias por responder, si estoy usando este codigo solo que modifique el factor de transformación para tener una correcta lectura. Quiero añadir que estoy usando un Amplificador Operacional a la salida del sensor para tener una señal con una entrada de valor más alto. El problema es que en el LCD se visualiza tres pantallazos correctos, ejm 21% 23% 21% y despues muestra 0%, existe forma de corregir este error? Quizás sea necesario diseñar algún filtro o desde la programación se puede despreciar este valor cero que aparece siempre.

Responder

Que raro. Por programación puedes quitarlo sentándote a pensar en la lógica. Por ejemplo lees el dato y lo comparas con el anterior, si su diferencia es mayor o menor a una tolerancia, por decir a un 20%) entonces desconsidera el dato leído y continua con el dato anterior.
Otra forma es hacer un filtro de promedio movil. Lees varias veces el sensor y vas sumando todo en una variable, al final tomas esa variable y la divides por el número de muestras que has hecho.

//Voltaje del Sensor MPC5010DP
   aux=0;
   for(i=0;i<20;i++){
      aux = aux + (read_adc()*5.0/1023.0);
      delay_ms(5);
   }
   Vout=aux/20.0;
Responder

Hola Sergio: En la introducción:
Convertidor Análogo/Digital ADC PIC
Una señal análoga es una señal continua, seria preferiblemente expresar: Una señal análoga es una señal variable o que varía de cero a un valor máximo de voltaje positivo y un valor máximo negativo en el tiempo.
Luego dices: por ejemplo una señal de 0 a 5V es una señal análoga y puede tomar valores (1V, 2V, 2.5 V, etc.). Se diría para mejor comprensión: Tomemos por ejemplo una señal análoga que varía de cero (0) a cinco (5) voltios. Esta señal llegará a tomar valores de +1V, +2V, +2,5V etc, hasta llegar a +5V y después retorna hasta cero voltios. Seguidamente obtiene los valores desde cero (0) hasta -5 Voltios de igual manera. (Dibujar una señal análoga explicando los puntos referentes.
Gracias

Responder

Gracias Alfonso por los comentários. He modificado el texto para ampliar un poco mejor la definición. Saludos

Responder

Que excelente pagina… Una pregunta quiero hacer un termometro pero que me marque positivos y negativos pero en un display de 7 segmentos que el mayor sea 9 grados y -9 grados pero no encuentro como hacerle. Espero me puedas ayudar, gracias saludos.

Responder