3
\$\begingroup\$

I am currently using a PIC16f1826 to try and measure the voltage of the 3.7v battery that is powering said microcontroller.

From my understanding, the ADC can measure from 0v up to the reference voltage divided in 1024 parts so I can't use the battery as a reference voltage. Instead I'm using a Fixed Voltage Reference at 2.048v that is generated in the microcontroller.

However 2.048 is below the 3.7v battery that I'm trying to measure so I'm using a voltage divider to halve the input so I can get meaningful readings, however when I do this and try and get my reading I get a value of 6-5/1023 which seems plain wrong. If I connect the battery without the voltage divider I get the full 1023/1023.

My circuit looks like the following:

schematic

simulate this circuit – Schematic created using CircuitLab

I have left out the UART connection because it is not relevant to the question. My code for the ADC is the following:

#include <xc.h>
#include <stdlib.h>

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

// Define Oscillator Frecuency to use in delay_ms calculations.
#define _XTAL_FREQ   4000000  // 4MHz

// Function that initializes ADC parameters.
void initADC(void) {

    // Enable Fixed Voltage Reference.
    FVRCONbits.FVREN = 1;

    // Set Fixed Voltage Reference to 2.048V.
    FVRCONbits.ADFVR = 0b10;

    // Enable Analog input on RA1.
    TRISA1 = 0;
    ANSELAbits.ANSA1 = 0;

    // Define Conversion Clock to use FOSC/4.
    ADCON1bits.ADCS = 0b100;

    // Configure ADC Positive Reference Voltage to use FVR buffer.
    ADCON1bits.ADPREF = 0b11;

    // Configure ADC Negative Reference Voltage to use VSS.
    ADCON1bits.ADNREF = 0;

    // Output format as right justified.
    ADCON1bits.ADFM = 1;

    // Select Pin AN1 as Channel.
    ADCON0bits.CHS = 0b00001;

    // Start ADC Module.
    ADCON0bits.ADON = 1;

    // Start conversion.
    ADCON0bits.GO_nDONE = 1;
}
// Main function.
void main(void) {

    // Setup Internal Oscillator to run at 4MHz.
    OSCCONbits.IRCF = 0b1101;

    // Initialize ADC.
    initADC();

    while(1) {
        if(!ADCON0bits.GO_nDONE) {
            sendString("Ready: ");
            // Read ADC Result Register High and 
            // Register Low for full 10 bit scope.
            int adcResult = ((ADRESH)<<8)|(ADRESL);

            char percentToChar[5];
            itoa(percentToChar, adcResult, 10);
            sendString(percentToChar);
            sendString("\n");
            ADCON0bits.GO_nDONE = 1;

        } else {
            sendString("Not ready \n");
        }
        __delay_ms(300);
    }
}

The manual for the microcontroller can be found at: http://ww1.microchip.com/downloads/en/DeviceDoc/41391D.pdf Page 135 covers the Fixed Voltage Reference and Page 140 covers ADC.

Why am I getting the reading I'm getting in the ADC? It doesn't make sense to me, am I doing something wrong in the code maybe? Should I use the comparator module instead of the ADC to do this? Any help you can provide to help me solve this will be greatly appreciated!

\$\endgroup\$
  • 1
    \$\begingroup\$ It looks like you are not using itoa right. First argument should be value to convert, second is the buffer. \$\endgroup\$ – Eugene Sh. Nov 17 '15 at 17:52
  • 3
    \$\begingroup\$ You don't need any external components if you use the internal reference as A/D input, and the Vdd as reference. A reading of N correcsponds to a Vdd of 1023 * Vref / N. \$\endgroup\$ – Wouter van Ooijen Nov 17 '15 at 18:20
  • \$\begingroup\$ @EugeneSh. you are right actually, changed it and getting different results now, will tweak around with it to see if this was what was wrong with it. \$\endgroup\$ – patrickdamery Nov 17 '15 at 19:06
  • 1
    \$\begingroup\$ You just saved yourself 2 resistors and (maybe more important) 0.2 mA :) \$\endgroup\$ – Wouter van Ooijen Nov 17 '15 at 21:54
  • 1
    \$\begingroup\$ @WoutervanOoijen I did indeed, your answer in the end was what solved it for me, so if you want to write the answer I'll accept it so you can get the points :) \$\endgroup\$ – patrickdamery Nov 18 '15 at 22:20
3
\$\begingroup\$

This is not my answer, but this question has been sitting here with the answer in the comments for months.

As Wouter van Ooijen states in the comments, using the internal reference as the A/D input and using Vdd as the reference, the

reading of N coresponds to a Vdd of 1023 * Vref/N

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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