PIC18F13K22 ADC Values Below Expected Result

Thread Starter

razor367

Joined Sep 12, 2016
26
Setup:
Vdd: +4.75VDC (from USB, 0.1uf across Vcc and GND bridging PIC)
Vsig: Variable (+3VDC for this example)
ADCin: Have tested two configurations, direct in from regulated supply and with 4.7ohm resistor in series
ADC result is 10 point average of measurements taken within 1 second.

The value returned via debugging for 3VDC is ~27 instead of the expected result of ~647 (Vsig*1024/Vdd). For a reason yet unknown, this value will also return as ~350 and ~515 at the same Vsig on different runs (power cycle the Vsig and make no changes to the program, program state, or circuit). The 500 level value seems to return consistently after several "startup" runs. The value is stable to +-3, but not accurate. I have a multimeter in line with Vsig to verify that the supply is indeed at the correct voltage.

A full table looks like this (note the result both over and undershoots expected):
Code:
Vsig  Expected  Actual
0.5   107.79     209
1.0   215.58     266
1.5   323.37     324
2.0   431.16     382
2.5   538.95     440
3.0   646.74     500
3.5   754.53     540
The clock is configured correctly as I have fired LEDs against a watch and the time cycles match. I am thinking that the bias is program related, but the fluctuation is circuit related. I have been teaching myself how to work with microcontrollers, circuits, and programming, but this is the first issue that has really stumped me.

Below is the functional code, I have omitted averaging to cut down on space usage:
C:
// PIC18F13K22 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1H
#pragma config FOSC = IRCCLKOUT // Oscillator Selection bits (Internal RC oscillator, CLKOUT function on OSC2)
#pragma config PLLEN = OFF      // 4 X PLL Enable bit (PLL is under software control)
#pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 19        // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled, RA3 input pin disabled)
// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config BBSIZ = OFF      // Boot Block Size Select bit (512W boot block size)
#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 not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 not code-protected)
// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 not write-protected)
// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks)

void ConfigureOscillator(void){
    OSCCONbits.HFIOFS   =0b1; //HFINTOSC Frequency Stable Bit unsure pg18
    OSCCONbits.OSTS     =0b0; //Oscillator Start up and time out pg18
    OSCCONbits.IRCF     =0b111; //Internal Oscillator Frequency Select pg18
    OSCCONbits.SCS      =0b00; //clock set to primary clock pg18
    OSCTUNEbits.PLLEN   =0b1;
}

/** * Initialize the Analog to Digital Converter. pg213*/
void init_adc(void){
    TRISAbits.TRISA2    =0b1;  // set pin as input
    ADCON0bits.CHS      =0b0010; // set pin as analog
    ADCON1bits.PVCFG    =0b00; // set v+ reference to Vdd
    ADCON1bits.NVCFG    =0b0;  // set v- reference to GND
    //ADCON1bits.CHSN     =0b000; // set negative input to GND
    ADCON2bits.ADFM     =0b1;  // right justify the output
    ADCON2bits.ACQT     =0b110; // 16 TAD
    ADCON2bits.ADCS     =0b101; // use Fosc/16 for clock source
    ADCON0bits.ADON     =0b1;  // turn on the ADC
}

/** * Preform an analog to digital conversion. * at Param channel The ADC input channel to use. * at Return The value of the conversion. */
uint16_t adc_convert(uint8_t channel){
    ADCON0bits.CHS      =channel;  // select the given channel
    ADCON0bits.GO       =0b1;      // start the conversion
    while(ADCON0bits.DONE);         // wait for the conversion to finish
    return(ADRESH<<8)|ADRESL;      // return the result
}
 
Last edited by a moderator:

AlbertHall

Joined Jun 4, 2014
12,625
The value returned via debugging for 3VDC is ~27 instead of the expected result of ~647 (Vsig*1024/Vdd).
I think I have sussed this. You are using the internal clock at 16MHz and have set the ADC conversion clock to Fosc/16 and that would be just fine BUT you also have "OSCTUNEbits.PLLEN=0b1;" which multiplies the clock frequency by four and now the ADC is compromised.
Replace "ADCON2bits.ADCS =0b101;// use Fosc/16 for clock source" with "ADCON2bits.ADCS =0b110;// use Fosc/64 for clock source".
 

Thread Starter

razor367

Joined Sep 12, 2016
26
I made the suggested change, but it seems my actual vs. expected is still on the low end (off by ~2.5x @ 2.6V, off by ~1.9x @ 3V). Plotted, the response looks like this. The slope is off expected in run 1, and offset in run 2. I am not sure where this variation is coming from.
upload_2016-10-12_13-37-52.png

I have checked the connections all the way to the pin and am receiving a constant voltage. Sometimes the reading is steady out of the ADC, sometimes it creeps up between subsequent debugging runs, sometimes the value swings high or low (never during the same run). Not sure what is happening.
 
Last edited:

AlbertHall

Joined Jun 4, 2014
12,625
How are you powering the PIC?
While running this test what else do you have connected to the PIC?
Please post all the code.
See what readings you get with the ADC input connected by a resistor (1k - 10k) to PIC VDD and then to PIC VSS.
 

Thread Starter

razor367

Joined Sep 12, 2016
26
C:
Main.c:

#if defined(__XC)
    #include <xc.h>        /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>       /* HiTech General Include File */
#elif defined(__18CXX)
    #include <p18cxxx.h>   /* C18 General Include File */
#endif

#if defined(__XC) || defined(HI_TECH_C)

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */

#endif

#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */
//#include "highpassbutter.h" /* Include file for IIR filter */

/******************************************************************************/
/* User Global Variable Declaration                                           */
/******************************************************************************/

/* i.e. uint8_t <variable_name>; */

/******************************************************************************/
/* Main Program                                                               */
/******************************************************************************/

void main(void)
{
    uint16_t adc_value;                 // variable to hold average ADC conversion result in
    uint16_t adc_value1;                // variable to hold 1st ADC conversion result in
    uint16_t adc_value2;                // variable to hold 2nd ADC conversion result in
    uint16_t adc_value3;                // variable to hold 3rd ADC conversion result in
    uint16_t adc_value4;                // variable to hold 4th ADC conversion result in
    uint16_t adc_value5;                // variable to hold 5th ADC conversion result in
    uint16_t adc_value6;                // variable to hold 6th ADC conversion result in
    uint16_t adc_value7;                // variable to hold 7th ADC conversion result in
    uint16_t adc_value8;                // variable to hold 8th ADC conversion result in
    uint16_t adc_value9;                // variable to hold 9th ADC conversion result in
    uint16_t adc_value10;               // variable to hold 10th ADC conversion result in
    uint16_t adc_value_sum;             // variable to hold sum of ADC conversion results in
  
    /* Configure the oscillator for the device */
    ConfigureOscillator();

    /* Initialize I/O and Peripherals for application */
    InitApp();

    /* TODO <INSERT USER APPLICATION CODE HERE> */

    TRISCbits.TRISC0 = 0; // set pin as output
    TRISCbits.TRISC1 = 0; // set pin as output
    TRISCbits.TRISC2 = 0; // set pin as output
    TRISBbits.TRISB4 = 0; // set pin as output
  
    //while(1)
    //{
        LATCbits.LATC0 = 0; // set pin LOW
        LATCbits.LATC1 = 0; // set pin LOW
        LATCbits.LATC2 = 0; // set pin LOW
        LATBbits.LATB4 = 0; // set pin LOW
        wait_ms(500);       // wait 0.5 seconds
        LATCbits.LATC0 = 1; // set pin HIGH
        LATCbits.LATC1 = 1; // set pin HIGH
        LATCbits.LATC2 = 1; // set pin HIGH
        LATBbits.LATB4 = 1; // set pin HIGH
        wait_ms(3000);       // wait 3.0 seconds to test LEDs
        LATCbits.LATC0 = 0; // set pin LOW
        LATCbits.LATC1 = 0; // set pin LOW
        LATCbits.LATC2 = 0; // set pin LOW
        LATBbits.LATB4 = 0; // set pin LOW
    //} //testing loop condition
      
    while(1)
    {
        //adc_value = 25;             //manual override adc_value variable
        adc_value1 = adc_convert(2);
        wait_ms(10);
        adc_value2 = adc_convert(2);
        wait_ms(10);
        adc_value3 = adc_convert(2);
        wait_ms(10);
        adc_value4 = adc_convert(2);
        wait_ms(10);
        adc_value5 = adc_convert(2);
        wait_ms(10);
        adc_value6 = adc_convert(2);
        wait_ms(10);
        adc_value7 = adc_convert(2);
        wait_ms(10);
        adc_value8 = adc_convert(2);
        wait_ms(10);
        adc_value9 = adc_convert(2);
        wait_ms(10);
        adc_value10 = adc_convert(2);
        wait_ms(10);
        adc_value_sum = adc_value1 + adc_value2 + adc_value3 + adc_value4 + adc_value5 + adc_value6 + adc_value7 + adc_value8 + adc_value9 + adc_value10;
        adc_value = adc_value_sum / 10;
        //adc_value = adc_convert(2);
      
        /* check the boolean condition */
        if( adc_value > 501 ) {
        //if( adc_value > 50 ) {
        /*bank0;
        movlw b'00010111';
        movwf PORTC;*/
        LATCbits.LATC0 = 1; // set pin HIGH
        LATCbits.LATC1 = 1; // set pin HIGH
        LATCbits.LATC2 = 1; // set pin HIGH
        LATBbits.LATB4 = 1; // set pin HIGH
     //printf("Value of adc_result is below range" );
        }
    else if( adc_value <= 500 && adc_value >= 430 ) {
    //else if( adc_value <= 50 && adc_value >= 40 ) {
     /*bank0;
        movlw b'00000001';
        movwf PORTC;*/
        LATCbits.LATC0 = 1; // set pin HIGH
        LATCbits.LATC1 = 0; // set pin LOW
        LATCbits.LATC2 = 0; // set pin LOW
        LATBbits.LATB4 = 0; // set pin LOW
      //printf("Value of adc_result is ORANGE" );
        }
    else if( adc_value <= 385 && adc_value >= 360  ) {
    //else if( adc_value <= 39 && adc_value >= 30  ) {
     /*bank0;
        movlw b'00000010';
        movwf PORTC;*/
        LATCbits.LATC0 = 0; // set pin LOW
        LATCbits.LATC1 = 1; // set pin HIGH
        LATCbits.LATC2 = 0; // set pin LOW
        LATBbits.LATB4 = 0; // set pin LOW
      //printf("Value of adc_result is YELLOW" );
        }
    else if( adc_value <= 335 && adc_value >= 305  ) {
    //else if( adc_value <= 29 && adc_value >= 20  ) {
     /*bank0;
        movlw b'00000100';
        movwf PORTC;*/
        LATCbits.LATC0 = 0; // set pin LOW
        LATCbits.LATC1 = 0; // set pin LOW
        LATCbits.LATC2 = 1; // set pin HIGH
        LATBbits.LATB4 = 0; // set pin LOW
      //printf("Value of adc_result is WHITE" );
        }
    else if( adc_value <= 280 && adc_value >= 265  ) {
    //else if( adc_value <= 19 && adc_value >= 10  ) {
     /*bank0;
        movlw b'00010000';
        movwf PORTC;*/
        LATCbits.LATC0 = 0; // set pin LOW
        LATCbits.LATC1 = 0; // set pin LOW
        LATCbits.LATC2 = 0; // set pin LOW
        LATBbits.LATB4 = 1; // set pin HIGH
      //printf("Value of adc_result is RED" );
        }
    else if( adc_value < 265 && adc_value >= 1 ) {
    //else if( adc_value < 50 && adc_value >= 1 ) {
     /*bank0;
        movlw b'00000000';
        movwf PORTC;*/
        LATCbits.LATC0 = 0; // set pin LOW
        LATCbits.LATC1 = 0; // set pin LOW
        LATCbits.LATC2 = 0; // set pin LOW
        LATBbits.LATB4 = 0; // set pin LOW
      //printf("Value of adc_result is above range" );
        }
    else {
     /*bank0;
        movlw b'00000000';
        movwf PORTC;*/
        LATCbits.LATC0 = 0; // set pin LOW
        LATCbits.LATC1 = 0; // set pin LOW
        LATCbits.LATC2 = 0; // set pin LOW
        LATBbits.LATB4 = 0; // set pin LOW
      //printf("Value of adc_result is not in valid window" );
        }
    //printf("Exact value of signal is: %d\1024", adc_result);
    wait_ms(1000);       // wait 1.0 second before updating
    }

}

user.c:

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#elif defined(__18CXX)
    #include <p18cxxx.h>    /* C18 General Include File */
#endif

#if defined(__XC) || defined(HI_TECH_C)

#include <stdint.h>         /* For uint8_t definition */
#include <stdbool.h>        /* For true/false definition */

#endif

#include "user.h"

/******************************************************************************/
/* User Functions                                                             */
/******************************************************************************/

/* <Initialize variables in user.h and insert code for user algorithms.> */

/** * Initialize the Analog to Digital Converter. pg213*/
void init_adc(void){
    TRISAbits.TRISA2    =0b1;  // set pin as input
    ADCON0bits.CHS      =0b0010; // set pin as analog
    ADCON1bits.PVCFG    =0b00; // set v+ reference to Vdd
    ADCON1bits.NVCFG    =0b0;  // set v- reference to GND
    //ADCON1bits.CHSN     =0b000; // set negative input to GND
    ADCON2bits.ADFM     =0b1;  // right justify the output
    ADCON2bits.ACQT     =0b110; // 16 TAD
    ADCON2bits.ADCS     =0b110; // use Fosc/64 for clock source
    //ADCON2bits.ADCS     =0b101; // use Fosc/16 for clock source
    ADCON0bits.ADON     =0b1;  // turn on the ADC
}

/** * Preform an analog to digital conversion. * [USER=120004]@Param[/USER] channel The ADC input channel to use. * [USER=190411]@Return[/USER] The value of the conversion. */
uint16_t adc_convert(uint8_t channel){
    ADCON0bits.CHS      =channel;  // select the given channel
    ADCON0bits.GO       =0b1;      // start the conversion
    while(ADCON0bits.DONE);         // wait for the conversion to finish
    return(ADRESH<<8)|ADRESL;      // return the result
}   
  
void InitApp(void)
{
    /* TODO Initialize User Ports/Peripherals/Project here */

    /* Setup analog functionality and port direction */

    /* Initialize peripherals */
    init_adc();
    /* Configure the IPEN bit (1=on) in RCON to turn on/off int priorities */

    /* Enable interrupts */
}

configuration_bits.c:
#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#elif defined(__18CXX)
    #include <p18cxxx.h>    /* C18 General Include File */
#endif

// PIC18F13K22 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1H
#pragma config FOSC = IRCCLKOUT // Oscillator Selection bits (Internal RC oscillator, CLKOUT function on OSC2)
#pragma config PLLEN = OFF      // 4 X PLL Enable bit (PLL is under software control)
#pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 19        // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled, RA3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config BBSIZ = OFF      // Boot Block Size Select bit (512W boot block size)
#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 not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

interrupts.c:
#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#elif defined(__18CXX)
    #include <p18cxxx.h>    /* C18 General Include File */
#endif

#if defined(__XC) || defined(HI_TECH_C)

#include <stdint.h>         /* For uint8_t definition */
#include <stdbool.h>        /* For true/false definition */

#endif

/******************************************************************************/
/* Interrupt Routines                                                         */
/******************************************************************************/

/* High-priority service */

#if defined(__XC) || defined(HI_TECH_C)
void interrupt high_isr(void)
#elif defined (__18CXX)
#pragma code high_isr=0x08
#pragma interrupt high_isr
void high_isr(void)
#else
#error "Invalid compiler selection for implemented ISR routines"
#endif

{

      /* This code stub shows general interrupt handling.  Note that these
      conditional statements are not handled within 3 seperate if blocks.
      Do not use a seperate if block for each interrupt flag to avoid run
      time errors. */

#if 0
  
      /* TODO Add High Priority interrupt routine code here. */

      /* Determine which flag generated the interrupt */
      if(<Interrupt Flag 1>)
      {
          <Interrupt Flag 1=0>; /* Clear Interrupt Flag 1 */
      }
      else if (<Interrupt Flag 2>)
      {
          <Interrupt Flag 2=0>; /* Clear Interrupt Flag 2 */
      }
      else
      {
          /* Unhandled interrupts */
      }

#endif

}

/* Low-priority interrupt routine */
#if defined(__XC) || defined(HI_TECH_C)
void low_priority interrupt low_isr(void)
#elif defined (__18CXX)
#pragma code low_isr=0x18
#pragma interruptlow low_isr
void low_isr(void)
#else
#error "Invalid compiler selection for implemented ISR routines"
#endif
{

      /* This code stub shows general interrupt handling.  Note that these
      conditional statements are not handled within 3 seperate if blocks.
      Do not use a seperate if block for each interrupt flag to avoid run
      time errors. */

#if 0

      /* TODO Add Low Priority interrupt routine code here. */

      /* Determine which flag generated the interrupt */
      if(<Interrupt Flag 1>)
      {
          <Interrupt Flag 1=0>; /* Clear Interrupt Flag 1 */
      }
      else if (<Interrupt Flag 2>)
      {
          <Interrupt Flag 2=0>; /* Clear Interrupt Flag 2 */
      }
      else
      {
          /* Unhandled interrupts */
      }

#endif

}

system.c:
#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#elif defined(__18CXX)
    #include <p18cxxx.h>    /* C18 General Include File */
#endif

#if defined(__XC) || defined(HI_TECH_C)

#include <stdint.h>         /* For uint8_t definition */
#include <stdbool.h>        /* For true/false definition */

#endif

#include <stdio.h>

#include "system.h"

/* Refer to the device datasheet for information about available
oscillator configurations. */
void ConfigureOscillator(void)
{
    OSCCONbits.HFIOFS   =0b1; //HFINTOSC Frequency Stable Bit unsure pg18
    OSCCONbits.OSTS     =0b0; //Oscillator Start up and time out pg18
    OSCCONbits.IRCF     =0b111; //Internal Oscillator Frequency Select pg18
    OSCCONbits.SCS      =0b00; //clock set to primary clock pg18
    OSCTUNEbits.PLLEN   =0b1;
}

/**
* Wait for a given number of milli-seconds using busy waiting scheme.
* [USER=120004]@Param[/USER] time - time in ms to wait.
*/
void wait_ms(uint16_t time)
{
    static long timel = 0;
    timel = time * 1000l;
    for( ; timel; timel--);// no initial condition, while time is >0, decrement time each loop
}

system.h:

#define SYS_FREQ        16000000L
#define FCY             SYS_FREQ/4

/******************************************************************************/
/* System Function Prototypes                                                 */
/******************************************************************************/

/* Custom oscillator configuration funtions, reset source evaluation
functions, and other non-peripheral microcontroller initialization functions
go here. */

void ConfigureOscillator(void); /* Handles clock switching/osc initialization */

void wait_ms(uint16_t);

user.h:
void InitApp(void);         /* I/O and Peripheral Initialization */
uint16_t adc_convert(uint8_t);
Moderators note: used code tags for C
 
Last edited by a moderator:

AlbertHall

Joined Jun 4, 2014
12,625
So it looks like your input signal is the problem - for further proof connect the ADC input to a pot across VDD/VSS and check a few voltages.

Where is your input from? Is it earthed?
Have you got the wires wrapped around a mains cable :D

Incidentally, I don't like it being connected by 4.7Ω though I don't think it is anything to do with the problem. 1k+ would protect the PIC pin if something unexpected happened (for instance, input set to 3.3V but no power on the PIC).
 

Thread Starter

razor367

Joined Sep 12, 2016
26
Actually, it looks like that might have been the issue. My sensor leads had worked their way near enough to some main lines. I replaced the resistor and remeasured using the instrument signal. Looks much nicer. I think I can get away with some simple y-shift in the code to line up the curves. I have to look at what is causing the dog leg around 1.5V.

upload_2016-10-13_15-38-49.png
 

AlbertHall

Joined Jun 4, 2014
12,625
If you extend the input voltage range up to 5V does the ADC reading catch up again with the expected result?
If it doesn't then something is still going on with your input signal as we know that with the ADC linked to VDD you get the right answer.
 

Thread Starter

razor367

Joined Sep 12, 2016
26
After several trials, turns out the instrument was faulty for the voltage dip. I obtained a replacement and the output tracks as expected. Thanks for your help, Albert!
 
Top