Take the 2-minute tour ×
Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It's 100% free, no registration required.

I'm trying to read an analog input on a PIC18F65J11, and I'm having trouble. I don't think the pin is set up correctly because I'm getting a 0 for the value I read in, and the input is measured to be about 1V (but can get up to 3V). I want to use Here is my code:

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

/**CONFIGURATION **************************************************/
/* Device Configuration */
#pragma config XINST = OFF  // Turn off extended CPU instructions
#pragma config FOSC = HSPLL // HS oscillator will PLL that multiplies oscillator frequency by 4 (system clock is running at 16 MHz)
#pragma config FOSC2 = ON   // System clock selected by FOSC1:FOSC0 (used #config to set FOSC to HSPLL) 
#pragma config DEBUG = ON   // Background debugger enabled; RB6 and RB7 are dedicated to In-Circuit Debug.
#pragma config WDTEN = OFF  // Disable watchdog timer.
#pragma config WDTPS = 8    // Watchdog timer poscaler select bits is 1:8 (not important b/c watchdog timer disabled).
#pragma config STVREN = OFF // Reset on stack overflow/underflow disabled.
#pragma config CP0 = OFF    // Program memory is not code-protected
#pragma config IESO = ON   // Oscillator Switchover mode disabled.
#pragma config FCMEN = OFF  // Fail-Safe Clock Monitor disabled.
#pragma config CCP2MX = DEFAULT // ECCP2/P2A multiplexed with RC1 instead of RE7 pin (doesn't matter b/c not using ECCP, which is pwm output)

int myVoltage;

void main(void) 
{
    myVoltage = 0;

    // Configure clock registers (FOSC is set to HSPLL)
    OSCCONbits.SCS1 = 0;    // SCS1:SCS0 = 00 means use primary
    OSCCONbits.SCS0 = 0;    // clock source (CPU divider output) if FOSC2 is on (FOSC2 is indeed on from the #pragma config above)
    OSCCONbits.IRCF2 = 1;   // IRCF2:IRCF0 = 110 means the internal oscillator is set to 4 MHz
    OSCCONbits.IRCF1 = 1;
    OSCCONbits.IRCF0 = 1;
    OSCCONbits.IDLEN = 0;   // on SLEEP instruction, device enters sleep mode instead of idle mode
    OSCTUNEbits.PLLEN = 1;  // enable PLL (4x multiplier), so system clock is 4 * 4 MHz = 16 MHz
    // Basically, I've just set it to use primary oscillator, told it the oscillator is 
    // 4 MHz, and told it to enable PLL so that my system clock is 16 MHz.

    // Initialize Port A
    TRISA &= 0;             // set Port A as outputs
    LATA &= 0;              // all pins outputting 0
    TRISAbits.RA0 = 1;      // set pin AN0 as input to read voltage

    while(1) {
        OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_12_TAD, ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_VDD, 0);
        Delay10TCYx( 5 );
        ConvertADC();               // initiate conversion of sensor1 @ AN0
        while(BusyADC());           // waiting to complete conversion
        myVoltage = ReadADC();      // read the result of sensor1 @ AN0
        CloseADC();
        printf("%i volts \n\r", myVoltage);
    }
}

What am I doing wrong or missing? I suspect it's the OpenADC() part that may be wrong. I've got it using Fosc/8, result in least significant bits, 12 Tad, channel 0 (AN0 pin), interrupt off, VDD as the highest limit, and 0 so that all analog pins are analog.

share|improve this question
    
All ADCs need a reference voltage. I'm not familiar with this hardware so I'm not sure if the reference voltage is internal (in which case make sure it is enabled and non-zero) or external (in which case make sure you are applying an appropriate reference voltage. –  Fred Hamilton Feb 22 '13 at 1:57
    
Something to check is that you've got Avss and Avdd connected, you need that even though you're using Vdd as the reference. –  PeterJ Feb 22 '13 at 2:01
    
I had AVdd connected to 3.3V and AVss to GND already. Hardware-wise, I think there shouldn't be a problem. –  Jack Feb 22 '13 at 18:07

1 Answer 1

I found out the problem was that my reference was not set correctly in the OpenADC() function. I needed ADC_REF_VDD_VSS instead of ADC_VREFPLUS_VDD. Here is the correct way to read an A/D value. This part goes inside the while(1) loop shown in the question.

// Constraints: A/D acquisition time must be >= 2.4 us (data sheet p264, Equation 20-3), conversion time (Tad) must be >= 0.7 us (data sheet p385, Table 26-26)
// Given that our Fosc = 4 MHz, which means Tosc = 1/Fosc = 1/4 MHz = 0.25 us,
// we must have at least 4 * Tosc = 1 us of conversion time (Tad).
// This is why we choose ADC_FOSC_4.
// Since Tad = 1 us, and we need a minimum acquisition time of of 2.4 us,
// we choose acquisition time to be 4 * Tad, which is ADC_4_TAD
// Use channel 0 (ADC_CH0) to read AN0
OpenADC(ADC_FOSC_4 & ADC_RIGHT_JUST & ADC_4_TAD, ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS, 0);
Delay10TCYx( 5 );        // allow for time to open adc (don't know if need this much)
ConvertADC();            // initiate conversion of sensor1 @ AN0
while(BusyADC());        // waiting to complete conversion
myVoltage = ReadADC();  // read A/D value. math needs to be done to convert to voltage
CloseADC();
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.