05 – Aplicación de ADC.h – Voltímetro digital

Anteriormente, hemos visto como utilizar ADC.h para configurar y utilizar el módulo de conversión analógico-digital del PIC18F4550. Ahora, vamos a darle una aplicación práctica a las librerías ADC.h y XLCD.h construyendo un sencillo voltímetro digital de 0 a 5V cuyos valores se muestren en un display LCD 16×2.

Inicialmente vamos a definir nuestro diagrama esquemático:

lcd16x2withRW

Como puede observarse, utilizaremos AN0 (RA0) como canal para la conversión, esto significa que podemos utilizar el puerto B para controlar nuestro display, de manera que podemos utilizar la configuración por defecto de la librería XLCD.h. Si tiene dudas sobre como utilizar XLCD.h y ADC.h puede consultar la entrada 01 y 03 respectivamente de este blog.

Conversión de entero a ASCII

Sabemos que el módulo A/D de nuestro microcontrolador nos dará como resultado un número entero de 10 bits equivalente a la señal analógica de entrada. Esto significa que si nuestro voltaje de entrada puede variar en el rango de 0V a 5V, tendríamos valores enteros que van desde 0 a 1023. Entonces ¿Porqué es necesario convertir de entero a ASCII? Simple, nuestro display funciona con caracteres ASCII o mejor dicho con valores enteros que tengan un equivalente en ASCII, de manera que si por ejemplo queremos mostrar el número 1, debemos sumar 48, debido a que 49 en ASCII equivale al número 1; Y así debemos proceder con cualquier otro valor. Ahora los invito a revisar la siguiente tabla de códigos ASCII.

Al observar la tabla de códigos ASCII podemos determinar que los números del 0 al 9, se pueden representar en ASCII sumando siempre la constante 48. Entonces, una manera de mostrar nuestros valores enteros generados por el módulo A/D consiste en convertirlo en un valor que represente el voltaje de entrada y posteriormente descomponer cada uno de sus dígitos para convertirlos en ASCII enviándolos al display  consecutivamente:

  1. Imaginemos que nuestro canal AN0 recibe un voltaje de entrada de 1.75V, si aplicamos la ecuación correspondiente, sabremos que a la salida del módulo A/D tendremos 358.0928994. Ahora, tenemos que convertirlo en un valor equivalente al voltaje de entrada multiplicando primero por 5000 lo cual nos da: 1,790,464.498 y dividiendo posteriormente por 1023 cuyo resultado será: 1,750.209675, si tomamos sólo la parte entera podemos apreciar que representa los 1.75V de entrada.
  2. Ahora que tenemos la cifra 1750, procedemos a descomponerlo en sus dígitos individuales, posteriormente a cada uno se le suma 48 y ya los podemos enviar al display LCD.

Como se puede apreciar los dos procedimientos anteriores no son nada complicados a nivel de programación. Aclaro que estos algoritmos son fáciles de encontrar en libros e Internet, por lo que no son de mi autoría. El siguiente segmento de código muestra la implementación del algoritmo:


void interrupt ADCInterrupt()
{
 if(ADIF)
 {
 //Capturando el resultado
 resultado = ReadADC();

 //Algoritmo para descomponer el resultado en digitos enteros
 vAnalogico = (long)resultado * 5000;
 vAnalogico = vAnalogico / 1023;
 digito = vAnalogico / 1000;
 SetDDRamAddr(0x09);
 putcXLCD(digito + 48);
 SetDDRamAddr(0x0A);
 putrsXLCD(".");
 digito = (vAnalogico / 100) % 10;
 SetDDRamAddr(0x0B);
 putcXLCD(digito + 48);
 digito = (vAnalogico / 10) %10;
 SetDDRamAddr(0x0C);
 putcXLCD(digito + 48);
 SetDDRamAddr(0x0D);
 putrsXLCD("V");

 ADIF = 0;
 ConvertADC();
 }
}

El algoritmo es muy simple y mostrará en el display un valor de un entero y dos cifras decimales. Se utiliza para este ejemplo la conversión A/D por interrupción ya que es el método mas eficiente.

El código completo es el siguiente:

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <plib/xlcd.h>
#include <plib/delays.h>
#include "../plib/adc.h"

//BITS DE CONFIGURACION.....
#pragma config PLLDIV = 5, CPUDIV = OSC1_PLL2, USBDIV = 2
#pragma config FOSC = HSPLL_HS, FCMEN = OFF, IESO = OFF
#pragma config PWRT = OFF, BOR = OFF, VREGEN = OFF
#pragma config WDT = OFF, WDTPS = 32768
#pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF
#pragma config STVREN = ON, LVP = OFF, ICPRT = OFF, XINST = OFF

#define _XTAL_FREQ 48000000

//Funciones requeridas por la librería XLCD
void DelayFor18TCY(void);
void DelayPORXLCD(void);
void DelayXLCD(void);

int resultado;
long int vAnalogico;
char digito;

void main()
{
 //Configurando LCD 4 bits mutilínea
 OpenXLCD(FOUR_BIT & LINES_5X7);
 //Esperar hasta que el display esté disponible.
 while(BusyXLCD());
 //Mover cursor a la derecha...
 WriteCmdXLCD(0x06);
 //Desactivando el cursor.
 WriteCmdXLCD(0x0C);

 SetDDRamAddr(0x00);
 putrsXLCD("VOLTAJE: ");
 
 //==========================================
 /*Configuración del módulo AD
 * Fosc = 64
 * Alineación = derecha
 * 16 TAD
 * Canal AN0
 * Interrupción habilitada
 * VREF+ y VREF- conectados a VDD y VSS respectivamente
 * Valor de ADCON1 = 14 (Canal AN0 analógico, el resto digitales)
 */
 OpenADC(ADC_FOSC_64 &
 ADC_RIGHT_JUST &
 ADC_16_TAD,
 ADC_CH0 &
 ADC_INT_ON &
 ADC_VREFPLUS_VDD &
 ADC_VREFMINUS_VSS,
 14);
 
 //Retardo de 50 Tcy
 Delay10TCYx(5);
 
 ADC_INT_ENABLE(); //Habilitación de la interrupción AD
 ei();
 
 //Iniciar la conversión
 ConvertADC();

 while(1)
 {}
}

void interrupt ADCInterrupt()
{
 if(ADIF)
 {
 //Capturando el resultado
 resultado = ReadADC();

 //Algoritmo para descomponer el resultado en digitos enteros...
 vAnalogico = (long)resultado * 5000;
 vAnalogico = vAnalogico / 1023;
 digito = vAnalogico / 1000;
 SetDDRamAddr(0x09);
 putcXLCD(digito + 48);
 SetDDRamAddr(0x0A);
 putrsXLCD(".");
 digito = (vAnalogico / 100) % 10;
 SetDDRamAddr(0x0B);
 putcXLCD(digito + 48);
 digito = (vAnalogico / 10) %10;
 SetDDRamAddr(0x0C);
 putcXLCD(digito + 48);
 SetDDRamAddr(0x0D);
 putrsXLCD("V");

 ADIF = 0;
 ConvertADC();
 }
}


void DelayFor18TCY(void)
{
 Delay10TCYx(120);
}

void DelayPORXLCD(void)
{
 Delay1KTCYx(180);
 return;
}

void DelayXLCD(void)
{
 Delay1KTCYx(60);
 return;
}

Acá podemos ver la simulación:

demo ADC_XLCD

El siguiente video muestra la implementación del circuito:

Volveré posteriormente con ejemplos de uso de interrupciones, lo cual nos servirá como preámbulo para la implementación de temporizadores. !!!Hasta la pronto¡¡¡

Acerca de jjguevara09

Me gusta la electrónica
Esta entrada fue publicada en Microcontroladores PIC y etiquetada , , , . Guarda el enlace permanente.

4 respuestas a 05 – Aplicación de ADC.h – Voltímetro digital

  1. eduardo dijo:

    buenos días, para solicitar su ayuda, al montar el código en el pic, el lcd prende y parpadea un seg y se desactiva los puertos RB0 AL RB3 no mostrando nada. por favor me podría indicar que esta mal en al código, gracias

    codigo:
    #include
    #include
    #include
    #include
    #include
    #include

    //BITS DE CONFIGURACION…..
    #pragma config PLLDIV = 5, CPUDIV = OSC1_PLL2, USBDIV = 2
    #pragma config FOSC = HSPLL_HS, FCMEN = OFF, IESO = OFF
    #pragma config PWRT = OFF, BOR = OFF, VREGEN = OFF
    #pragma config WDT = OFF, WDTPS = 32768
    #pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF
    #pragma config STVREN = ON, LVP = OFF, ICPRT = OFF, XINST = OFF

    #define _XTAL_FREQ 48000000

    //Funciones requeridas por la librería XLCD
    void DelayFor18TCY(void);
    void DelayPORXLCD(void);
    void DelayXLCD(void);

    int resultado;
    long int vAnalogico;
    char digito;

    void main()
    {
    //Configurando LCD 4 bits mutilínea
    OpenXLCD(FOUR_BIT & LINES_5X7);
    //Esperar hasta que el display esté disponible.
    while(BusyXLCD());
    //Mover cursor a la derecha…
    WriteCmdXLCD(0x06);
    //Desactivando el cursor.
    WriteCmdXLCD(0x0C);

    SetDDRamAddr(0x00);
    putrsXLCD(“VOLTAJE: “);

    //==========================================
    /*Configuración del módulo AD
    * Fosc = 64
    * Alineación = derecha
    * 16 TAD
    * Canal AN0
    * Interrupción habilitada
    * VREF+ y VREF- conectados a VDD y VSS respectivamente
    * Valor de ADCON1 = 14 (Canal AN0 analógico, el resto digitales)
    */
    OpenADC(ADC_FOSC_64 & ADC_RIGHT_JUST & ADC_16_TAD,
    ADC_CH0 & ADC_INT_ON & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS,14);

    //Retardo de 50 Tcy
    Delay10TCYx(5);

    ADC_INT_ENABLE(); //Habilitación de la interrupción ADC
    //ei();

    //Iniciar la conversión
    ConvertADC();

    while(1)
    {}
    }

    void interrupt_ADCInterrupt()
    {
    if(PIR1bits.ADIF);
    {
    //Capturando el resultado
    resultado = ReadADC();

    //Algoritmo para descomponer el resultado en digitos enteros
    vAnalogico = (long)resultado * 5000;
    vAnalogico = vAnalogico / 1023;
    digito = vAnalogico / 1000;
    SetDDRamAddr(0x09);
    putcXLCD(digito + 48);
    SetDDRamAddr(0x0A);
    putrsXLCD(“.”);
    digito = (vAnalogico / 100) % 10;
    SetDDRamAddr(0x0B);
    putcXLCD(digito + 48);
    digito = (vAnalogico / 10) %10;
    SetDDRamAddr(0x0C);
    putcXLCD(digito + 48);
    SetDDRamAddr(0x0D);
    putrsXLCD(“V”);

    PIR1bits.ADIF = 0;
    ConvertADC();
    }
    }

    void DelayFor18TCY(void)
    {
    Delay10TCYx(120);
    }
    void DelayPORXLCD(void)
    {
    Delay1KTCYx(180);
    return;
    }
    void DelayXLCD(void)
    {
    Delay1KTCYx(60);
    return;
    }

    Me gusta

  2. jjguevara09 dijo:

    Hola,
    Primeramente, asumiendo que has colocado los include correctamente, te sugiero descomentar la sentencia //ei(); y probar. Además de estos pequeños detalles tu código se ve bien. Este tipo de circuitos es muy susceptible a problemas de reloj, por lo que debes asegurarte que has conectado un cristal de 20MHZ, si no es así debes alterar los bits de configuración de acuerdo al cristal que tienes, actualizar_XTAL_FREQ y hacer los cálculos para ajustar los retardos.

    Suerte,

    Me gusta

  3. ariel dijo:

    Buenas podria hacer un tutorial de control de 4 servomotores con adc y timer por favor

    Me gusta

  4. ariel dijo:

    Buenos dias podria hacer un tutorial de control de servomotor com timer y adc para cualquier salida sim modulo pwm

    Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s