Conversión ADC PIC18F4620

-2

Necesito ayuda para comprender cómo codificar las conversiones de ADC para el PIC18F4620.
Si alguien pudiera proporcionar un código de ejemplo con comentarios, sería genial. También si alguien me puede explicar cómo hacer el sondeo de ADC. He intentado el siguiente código:

int main(void) 
{ 
    int sensor;
    ADCON1 = 0b00000111; //VSS,VDD ref. AN0 through AN7 analog only 
    ADCON0 = 0x0100; //clear ADCON0 to select channel 0 (AN0) 
    ADCON2 = 0b00001000; //ADCON2 setup: Left justified, Tacq=2Tad, Tad=2*Tosc (or Fosc/2) 
    ADCON0bits.ADON = 0x01; //Enable A/D module 
    while(1) { 
        ADCON0bits.GO_DONE = 1; //Start A/D Conversion 
        while(ADCON0bits.GO_DONE != 0); //Loop here until A/D conversion completes 
        { 
            sensor = ADRESH; 
        } 
     } 
} 

Pero los valores devuelven una constante 0.

    
pregunta Justgilyim

1 respuesta

2

Con algunas búsquedas, encontré este proyecto , que tiene un ejemplo de código que usa el ADC. Aquí están las partes relevantes del código:

#include <xc.h>
#include <delays.h>

#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF

// Function prototypes
void setup(void);
unsigned int read_analog_channel(unsigned int);

void main(void) {
    setup(); // Configure the PIC
    unsigned int analog_val;
    while(1) {
        analog_val = read_analog_channel(0);
        LATDbits.LATD1 = 1;  // Set RD1 high
        Delay1KTCYx(analog_val);
        LATDbits.LATD1 = 0;  // Set RD1 low
        Delay1KTCYx(1000);   // 500ms delay
    }
}

void setup(void) {
    // Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    // Set Fosc = 8MHz, which gives Tcy = 0.5us
    OSCCON = 0b01110000;

    // Set up ADC (section 19 of the PIC18F4620 Data Sheet)
    // Enable AN0-7 as analog inputs
    ADCON1 = 0b00000111;
    // Left justified result, manual acquisition time,
    // AD clock source = 8 x Tosc
    ADCON2 = 0b00000001;
}

// Read voltage from the specified channel.
// This function takes approximately 35us.
unsigned int read_analog_channel(unsigned int n) {
    unsigned int voltage;

    ADCON0 = n << 2;
    ADCON0bits.ADON = 1;
    Delay10TCYx(3); // 15us charging time
    ADCON0bits.GO = 1;
    while (ADCON0bits.GO); // Await result (11us approx)

    // Return the result (a number between 0 and 1023)
    voltage = ADRESH;
    voltage = (voltage << 2) + (ADRESL >> 6);
    return voltage;
}

Sin embargo, sería mejor echar un vistazo por qué su código no funcionó. Le da el mismo valor a ADCON1 . ADCON2 es diferente, pero eso solo cambia las velocidades de reloj y cosas como estas, nada que no debería funcionar.

Luego para ADCON0 , el ejemplo que doy es ligeramente diferente porque le permite usar una función para diferentes canales analógicos, por lo que ADCON0 se cambia en read_analog_channel() . Una nota menor en tu código: cuando le das a ADCON0 el valor 0x0100 , le das un valor que es más alto que un byte. Debido al x , el literal se lee como hexadecimal. Estás intentando colocar dos bytes en un registro. Sin embargo, eso significa que solo se selecciona el byte inferior, 0x00 , por lo que se borra el registro. Pero sería bueno cambiar esta línea en ADCON0 = 0b00000001 o algo así. El último bit debe establecerse porque habilita el módulo (lo que hace con ADCON0bits.ADON = 0x01 ). Consulte la hoja de datos para obtener más información (pág. 223).

Pero ahora su bucle while:

while(ADCON0bits.GO_DONE != 0); //Loop here until A/D conversion completes 
{ 
    sensor = ADRESH; 
} 

Este código es correcto, pero confuso. Los elogios ( { y } ) hacen que parezca que estás recorriendo esa parte del código, mientras que en realidad estás haciendo esto:

while(ADCON0bits.GO_DONE != 0); //Loop here until A/D conversion completes 
sensor = ADRESH; 

O esto, si te ayuda a entender:

while(ADCON0bits.GO_DONE != 0) //Loop here until A/D conversion completes 
{
} 
sensor = ADRESH; 

Debido al punto y coma ( ; ) que pusiste después de la primera línea.

Entonces lo último es la forma en que lees el resultado de ADRESH . No es donde se carga el resultado, es solo una parte del resultado (puede leer más sobre esto en la hoja de datos). El resultado completo se almacena en el par de registros ADRESH:ADRESL . Entonces, para obtener el resultado, necesitamos hacer un poco de aritmética:

sensor = ADRESH;
sensor = (sensor << 2) + (ADRESL >> 6);

Breve historia corta , hay algunos detalles en su código que no son tan claros, y aquí está su código en una versión más limpia:

int main(void) 
{ 
    word sensor; // Should be a word (16 bits), not an int (32 bits)
    ADCON1 = 0b00000111; //VSS,VDD ref. AN0 through AN7 analog only 
    ADCON0 = 0b00000001; //select channel 0 (AN0), enable module
    ADCON2 = 0b00001000; //ADCON2 setup: Left justified, Tacq=2Tad, Tad=2*Tosc (or Fosc/2) 
    while(1) 
    { 
        ADCON0bits.GO_DONE = 1; //Start A/D Conversion 
        while(ADCON0bits.GO_DONE != 0); //Loop here until A/D conversion completes 
        sensor = ADRESH;
        sensor = (sensor << 2) + (ADRESL >> 6);
        // Now here you should do something with the value of sensor; 
        // send it over USART, put it on an LCD or something like that.
    } 
} 

Luego, sobre el sondeo de ADC: este es básicamente el término para verificar periódicamente el ADC. Ya estás haciendo esto, porque el sondeo está en un bucle de tiempo: el sensor ya está controlado todo el tiempo.

A veces, solo desea comprobarlo de vez en cuando, y no necesita utilizar la velocidad máxima del PIC. En ese caso, simplemente agrega un retraso en el bucle.

    
respondido por el Keelan

Lea otras preguntas en las etiquetas