DESCRIPCIÓN
El convertidor analógico digital es capaz de convertir una señal de voltaje variable en valores digitales a una resolución de 8 o 10 bits. Ademas, se puede llegar hasta a 50K muestras por segundo, lo que es ideal para proyectos de adquisición de datos como Datalogger, etc. A continuación se muestra las características y se describe los registros involucrados con el convertidor ADC y se realizaran ejemplos.
- Resolución programable por software en modo de 8 y 10 bits.
- 13 canales de entradas multiplexadas.
- Rango del voltaje de entrada para el ADC 0-Vcc.
- Referencia de voltaje interna o externa.
- Modo de conversión ADC (continua o individual).
- Inicio de conversión ADC por Auto-Disparo en fuentes de Interrupción.
- Interrupción ADC al completar la conversión.
En las siguientes imágenes se detallaran los registros involucrados al ADC
Hay que seguir los siguientes pasos para una correcta conversión AD
Todo parece sencillo hasta que se llega al paso 2, y es aquí donde hay una gran pregunta y varias dudas al respecto; ¿Por qué es necesario el Tiempo de Adquisición?, ‘¿Cuánto es el Tiempo de Adquisición mínimo? Y ¿Cuál es el Tiempo de Conversión que debo utilizar? Primero realizaremos una breve descripción.
El módulo interno A/D del PIC incorpora un condensador de muestreo como muestra la imagen de arriba. Entonces antes de dar inicio a una conversión A/D hay que asegurarnos de que el condensador haya sido cargado con la tensión suministrada en el canal seleccionado, esto viene a ser como el tiempo de adquisición. Existen 2 formas de generar este tiempo.
- Por Software: se establece por código un tiempo simbólico igual al tiempo de adquisición y luego se inicia una conversión A/D.
- Automático: se configura un Tiempo de Adquisición que se establecerá de forma automática entre, la orden de inicio de conversión y muestreo de la señal para iniciar la conversión. Este tiempo se puede configurar a través de los bits ACQT[2:0] del registro ADCON2.
Según la hoja de datos (datasheet) del PIC18F4550 dice que para este PIC lo siguiente
- Tacq = Tiempo de Adquisición.
- Tad = Tiempo de Conversión (por cada bit, para 8 o 10 bits).
Tacq >= 2.45uS
0.7uS < Tad < 1.3uS
Luego de saber cuál es el Tacq mínimo y Tad por cada bit, es necesario saber cuánto debe ser el tiempo total requerido para una correcta conversión A/D. Para una resolución de 10 bits.
Tiempo Total = Tacq + Tconversion + Tdescarga.
Tiempo Total = 2.45uS + 10*(1.3uS) + 3uS
Tiempo Total = 19.45uS ≈ 20uS
El tiempo de descarga es necesario para dar inicio a un nuevo muestreo por el canal A/D
En la siguiente imagen se muestra una tabla del Tad respecto a la Fosc, esto nos indica cual debe ser el divisor de la Fosc para respetar el Tiempo de Adquisición y Conversión.
EJEMPLO N°1 – CONVERTIDOR ANALÓGICO DIGITAL DE 8 BITS
En el siguiente ejemplo mostraremos el voltaje de una resistencia variable (potenciometro) que esta conectada al pin RA0, y a través de unos leds ubicados en el puerto D se podrá visualizar su valor digital binario. Tambien, utilizaremos el oscilador interno del PIC18F4550 configurado a 8Mhz, configuraremos el Tiempo de conversión con los bits ADCS[2:0] = 001 esto seria igual a FOSC÷8 = 1us. Este tiempo sera el que utilice el tiempo de conversión, mientras que el tiempo de adquisición sera 4TAD = 4×1us = 4us, este nuevo valor sera el tiempo de adquisición para dar inicio el tiempo de conversión AD. A continuación se muestra el circuito de conexión y el código de este ejemplo.
Código principal MAIN
#include
#include "fuses.h"
void main(void) {
TRISD = 0x00;
TRISB = 0x00;
OSCCONbits.IRCF = 0b111; //Configura oscilador interno (FOSC = 8Mhz)
OSCCONbits.SCS = 0b10; // Oscilador del sistema = Fosc interno
ADCON1bits.PCFG = 0b1110; // Configura el Puerto como Entrada Analógica.
ADCON1bits.VCFG = 0b00; // Selecciona Voltajes de Referencia (5v-0v).
ADCON0bits.CHS = 0b0000; // Selecciona el Canal Analógico.
ADCON2bits.ACQT = 0b010; // Tiempo de Adquisición 4Tad.
ADCON2bits.ADCS = 0b001; // Tiempo de Conversión Fosc/8.
ADCON2bits.ADFM = 0; // Justificación Izquierda (modo-8bits).
ADCON0bits.ADON = 1; // Habilita el Módulo AD.
while (1) {
ADCON0bits.GO_DONE = 1; // Inicia la COnversió AD.
while (ADCON0bits.GO_DONE); // Espera a que termine la conversión AD.
LATD = ADRESH; // Lectura de valor AD.
}
}
EJEMPLO N°2 – ADC DE 10BITS + SENSOR LM35
En este nuevo ejemplo se configura el ADC a 10bits de resolución, y, los demás parámetros de configuración se mantienen igual al ejemplo anterior. Sin embargo, ahora se utiliza el sensor de temperatura LM35 (datasheet), revisando su hoja de datos, el fabricante nos dice que el factor de conversión de temperatura a voltaje es igual a 10mv por cada 1°C. Ademas, el sensor LM35 tiene un rango de temperatura de -55°C a +150°C co una precisión de 0.5°C. Por ultimo, hay que tener en cuenta que el valor leído del sensor LM35 es de voltaje y es necesario realizar varios cálculos para poder transformarlo en un numero y en grados. A continuación se muestra el circuito de conexión de este segundo ejemplo y también el código de mismo.
Código principal MAIN
#define _XTAL_FREQ 8000000L
#include
#include "fuses.h"
unsigned int value_adc = 0;
unsigned char counter_digito = 0;
double temp = 0.0;
unsigned char lm35 = 0;
void main(void) {
OSCCONbits.IRCF = 0b111; //Configura oscilador interno (FOSC = 8Mhz)
OSCCONbits.SCS = 0b10; // Oscilador del sistema = Fosc interno
//ADC = 10bits, Tad = 1us, Tacq = 4us, Vref = 5v-0v, RA=ANALOG
ADCON1bits.PCFG = 0b1110; // Configura el Puerto como Entrada Analógica.
ADCON1bits.VCFG = 0b00; // Selecciona Voltajes de Referencia (5v-0v).
ADCON0bits.CHS = 0b0000; // Selecciona el Canal Analógico.
ADCON2bits.ACQT = 0b010; // Tiempo de Adquisición 4Tad.
ADCON2bits.ADCS = 0b001; // Tiempo de Conversión Fosc/8.
ADCON2bits.ADFM = 1; // Justificación derecha (modo-10bits).
ADCON0bits.ADON = 1; // Habilita el Módulo AD.
//Configura TIMER1 = 10ms (multiplexar display 7 segmentos de 2 digitos)
T1CON = 0b10010000;
TMR1H = 0xD8; //Registro TMR1 = 55535
TMR1L = 0xEF;
T1CONbits.TMR1ON = 1; //Timer1 ON
PIR1bits.TMR1IF = 0; //Borra flag de TIMER1
PIE1bits.TMR1IE = 1; //Habilita interrupción TIMER1
INTCONbits.PEIE = 1; //Habilitara interrupción periféricas
INTCONbits.GIE = 1; //Habilita interrupción global
TRISD = 0x00;
while (1) {
ADCON0bits.GO_DONE = 1; //Inicia la COnversió AD.
while (ADCON0bits.GO_DONE); // Espera a que termine la conversión AD.
value_adc = ADRESH; // Lectura de valor AD.
value_adc = (value_adc << 8) + ADRESL;
temp = value_adc;
temp = (temp * 500.0) / 1023.0;
lm35 = (char) temp;
}
}
void interrupt ISR_TIMER_1(void) {
if (PIE1bits.TMR1IE && PIR1bits.TMR1IF) {
TMR1H = 0xD8;
TMR1L = 0xEF;
switch (counter_digito) {
case 0:
LATD = (counter_digito << 4) + (lm35 / 10);
counter_digito = 1;
break;
case 1:
LATD = (counter_digito << 4) + (lm35 % 10);
counter_digito = 0;
break;
}
PIR1bits.TMR1IF = 0;
}
}
Código FUSES
// CONFIG1L
#pragma config PLLDIV = 1 // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1 // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)
// CONFIG1H
#pragma config FOSC = INTOSCIO_EC// Oscillator Selection bits (Internal oscillator, port function on RA6, EC used by USB (INTIO))
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = ON // Internal/External Oscillator Switchover bit (Oscillator Switchover mode enabled)
// CONFIG2L
#pragma config PWRT = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOR = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 3 // Brown-out Reset Voltage bits (Minimum setting 2.05V)
#pragma config VREGEN = OFF // USB Voltage Regulator Enable bit (USB voltage regulator disabled)
// CONFIG2H
#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = ON // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = OFF // MCLR Pin Enable bit (RE3 input pin enabled; MCLR pin disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
// CONFIG5L
#pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks)
BryanCG98
Que pasa si al correr el codigo me sale un error donde me dice que counter_digito no puede ser usado como char?
admin
Hola, seguro es el tipo compilador, prueba con otros tipos de variables. ten presente el tamaño de variable (8,16,32 bits). Saludos!!!