PIC - ADC - ¿Valor negativo? - ¿Configuración incorrecta?

Estoy tratando de leer una entrada analógica con mi PIC18F66K22 usando ADC. Pero el valor supuestamente de 10 bits a menudo llega a valores como 63.241. Descubrí que un valor negativo (imprimir como sin firmar) da como resultado el mismo comportamiento.

Creo que podría haber algún problema con la configuración de mi ADC. Mi PIC tiene una frecuencia de reloj predeterminada (8Mhz). El rango de ADC debe ser de 0v a 2,5v, pero no tiene que ser tan preciso.

Parece que no puedo encontrar la configuración correcta de ADC, creo. Estoy usando el compilador XC8 con la adc.hbiblioteca que lo acompañaba en MPLAB X IDE.

A continuación se muestra el código (hice una nueva prueba de proyecto, con código simplificado). Primero, el adc.c, creo que la configuración es incorrecta y un error en la lectura debería ser fácil de ver.

#include <adc.h>
#include "adc.h"

void adcSetup()
{
   OpenADC (
           ADC_FOSC_8          &
           ADC_RIGHT_JUST       &
           ADC_20_TAD,
           ADC_CH4              &
           ADC_INT_OFF          &
           ADC_REF_VDD_VDD      &
           ADC_REF_VDD_VSS,
           ADC_CH4
           );
   ENABLE_AN4_ANA();
   SetChanADC(ADC_CH4);
}

//TODO ADC with interrupts

unsigned int adcGet(void)
{
   ConvertADC();
   while(BusyADC()){}
   return ReadADC();
}

también mi main.c, los otros archivos xport no son tan interesantes y parecen funcionar bien. No estoy tan seguro de mi conversión de uint a 'c-string' en la funciónvoid buttonHandle(void)

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <p18f66k22.h>
#include <delays.h>
#include <usart.h>

#include "defines.h"
#include "configuration-bits.h"
#include "xport.h"
#include "adc.h"

#define __delay_us(x) _delay((unsigned long)((x)*(8000000/4000000UL)))
#define __delay_ms(x) _delay((unsigned long)((x)*(8000000/4000UL)))

volatile char RxBuf[] = "                                        ";
volatile int RxI = 0;
volatile bool RxMessage = false;
volatile bool ButtonPressed = false;

void SetupRegisters(void);
void SetupInterrupts(void);
void interrupt HighISR(void);
void interrupt low_priority LowISR(void);
void delay_ms(unsigned int x);
void buttonHandle(void);
void messageHandle(void);

void SetupInterrupts(void)
{   
    INTCONbits.GIE  = 1;                //Global interrupt enable
    RCONbits.IPEN   = 1;                //Enable priority interrupts
    INTCONbits.GIEH = 1;                //Global interrupt enable High
    INTCONbits.GIEL = 1;                //Global interrupt enable Low
    INTCONbits.PEIE = 1;                //Peripheral Interrupt Enable bit
    INTCONbits.PEIE_GIEL = 1;           //Peripheral Interrupt Enable?

    INTCON3 =   0b00000000;             //Clear intcon. INT1 and INT2 are now low priority
    INTCON3bits.INT1E = 1;              //Enable int1 (BUTTON)
}

void SetupRegisters(void)
{
            //76543210
    TRISA = 0b10101110;     //7:RFID en2 6:x 5:POWER_LEVEL(analog) 4:PWRKEY 3:SW_CHRG 2:SW_FAULT 1:EXT_INP
    TRISBbits.TRISB1 = 1;   //BUTTON INPUT
    TRISEbits.TRISE3 = 0;   //XPort RESET
    TRISGbits.TRISG3 = 1;   //LDO pwrgd (input)
    TRISGbits.TRISG4 = 0;   //LDO shdn  (ldo to toggle xport)
}

/* Main */
int main() {
    //---Set up Registers/interrupts of PIC---
    //See defines.h for al macros for LED_IN and other pin-renames.
    SetupRegisters();       //Registers...
    SetupInterrupts();      //Interrupts (button/uart)
    adcSetup();             //ADC for power-detection (POWER-LEVEL)

    //---Set up peripherals---
    xportSetup();           //Using xport as debugging help.
    xportEnable();          //Switch ldo to enable it.

   while(true){
        if(RxMessage){
            messageHandle();
        }else if(ButtonPressed){
            buttonHandle();
            ButtonPressed = false;
        }
    }
   return 0;
}


void interrupt high_priority HighIsr(void)    //High priority interrupt
{
    if(PIR3bits.RC2IF){//USART INTERRUPT
        RxBuf[RxI] = RCREG2;
        if(RxBuf[RxI] == ';'){//TODO or full
            RxMessage = true;
        }
        RxI++;
    }else{
        xportSendText("High - unhandled interrupt");
    }
}

void interrupt low_priority LowIsr(void)    //Low priority interrupt
{
    if(INT1IF){                 //Button interrupt
        ButtonPressed = true;   //Set flag (handled in main)
        INT1IF = false;         //clear interrupt flag afterwards  to avoid hardware bounce re-interrupt
    }else{                      //Warning for unhandled interrupt
        xportSendText("[ERROR] Low - unhandled interrupt!");
    }
}

void delay_ms(unsigned int xc)
{
    do
    {
        xc--;
        __delay_ms(1);
    }
    while(xc  > 0);
}

void buttonHandle(void){
    delay_ms(100);
    if(!BUTTON){
    xportSendText("Button pressed");

    //ADC DEBUG
    char buffer[] = "                   ";
    sprintf (buffer, "ADC: %u", adcGet());
    xportSendText(buffer);

    //RX DEBUG
    xportSendText("RxBuf: ");
    xportSendText(RxBuf);

    //XPORT debug
    xportDebug();
    }
}

void messageHandle(void){
    xportSendText(RxBuf);                                           //Send/Handle the buffer
    strcpy(RxBuf, "                                        ");      //Empty the buffer!
    RxI = 0;                                                        //Start buffer at pos 0 again;
    RxMessage = false;                                              //Reset the flag
}

Básicamente estoy recibiendo texto uart en una interrupción. E imprimiendo el debug/adc cuando se ha establecido un indicador de botón (por la interrupción del botón)

Este es mi resultado después de presionar el botón varias veces: ingrese la descripción de la imagen aquíComo puede ver, el adc no es muy persistente. Aunque lo tenía conectado a la fuente de alimentación (que no debería (y no) caer tanto).

No me citen en esto (han pasado varios años desde la última vez que trabajé en una foto), pero recuerdo algo sobre la necesidad de cambiar el pin de un pin GPIO a un pin ADC con algún tipo de registro (o tal vez fue al revés). Desearía poder desenterrar algún código ADC antiguo para ayudar, pero no puedo encontrar ninguno. ¡Lo siento!
Tienes razón en eso, aunque ENABLE_AN4_ANA();debería hacer ese truco. Pero sí, realmente podría ser una pequeña cosa como esa.
Noté que su adc.c #incluye adc.h dos veces. Probablemente ese no sea el problema: los archivos de encabezado deben tener protectores a su alrededor para manejar múltiples #inclusiones, pero tampoco creo que fuera intencionado.
Bueno, hay una biblioteca <adc.h> que viene con el compilador/estudio. Pero también hice un "adc.h" con "adc.c". Estoy de acuerdo en que el nombre es de alguna manera inconveniente, pero ¿debería funcionar de todos modos?

Respuestas (2)

Sé que existen ejemplos y bibliotecas para tratar de ahorrar trabajo, pero a menudo encuentro útil no usarlos al principio mientras verifico que mi comprensión y la hoja de datos son correctas y que el chip no está roto. (Por lo general, el problema es mi comprensión).

Entonces, sin usar la biblioteca:

  • Establezca todos los registros ADC y puertos en lo que se supone que deben ser según la hoja de datos de acuerdo con lo que desea hacer.
  • Asegúrate de que funcione
  • Luego depurar la biblioteca

Probablemente encontrará que la biblioteca es correcta y que se está perdiendo algo que se vuelve obvio en ese momento, pero de vez en cuando, hay una biblioteca que está mal o al menos mal escrita/documentada.

AaronD, @FuaZe: Tienen razón, mi respuesta fue incorrecta. Debo asegurarme de estar completamente despierto antes de responder preguntas :) He eliminado mi respuesta.
¡No tiene sentido! ¡Cualquier ayuda es bienvenida!

Todavía no entiendo por qué no funcionó en primer lugar... Podría haber sido la forma en que lo imprimí. Podría haber sido la biblioteca.

Aunque lo hice configurando los registros manualmente, esto funciona (mejor) para mí.

static unsigned int result = 0;
ANCON0bits.ANSEL4 = 1;      //AN4 to analog channel.
ADCON2 = 0b10111110;        //Select channel
ADCON1 = 0b00110000;
ADCON0 = 0b00010011;        //Start AN4 conversion

while(ADCON0 & 2){}         //ADC busy

result = ADRESH;
result = result<<8;
result = result | ADRESL;
ADCON0 &= 0b11111110;       // Turn converter off
return (result/85);