Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC16F88 ADC reads value too high

Status
Not open for further replies.

tubos

New Member
I'm using an ADC pin to measure 9v battery voltage.
I have a 4x voltagedivider so the battery never exceeds 2.5v -> ADC pin
I use a vref+ external reference of 2.5V reference diode.
All ADC values are too high ie 9.6v for an 8.6v battery.
Using mikroc library or my own function doesnt change result .
See code below.


Code:
unsigned myreadADC(unsigned short channel)
  {
    char local;
    local = channel << 3;          // Adjust for correct offset
    ADCON0=local;                  // Set required channel
    ADCON0.ADON = 1;               // Enable ADC
    delay_us(50);                  // Wait for cap to charge
    ADCON0.GO_DONE = 1;            // Start conversion
    while(ADCON0.GO_DONE == 1);    // Wait here until complete
    ADCON0.ADON = 0;               // Disable ADC
    return ADRESL | (ADRESH<<8);   // Return result
  }

 void main(void)
  {
    char txt[8];
    unsigned ADval;
    unsigned result;

    INTCON     = 0;                // Interrupts are off (Soft I2C)
    OPTION_REG = 0b00000000;       // Pullups on by Latch
    PORTB      = 0b00000000;       // All OFF
    TRISB      = 0b00000000;       // All outputs
    PORTA      = 0b00000000;       // All OFF
    TRISA      = 0b00001011;       // All outputs except A0 & A1  & A3
    CMCON      = 7;                // comparator is Off
    CVRCON     = 0;                // Comparator refs are off
    ANSEL      = 0b00001011;       // AN3=Vref+ AN1,AN0 are Analog
    OSCCON     = 0b01101000;       // 4 Mhz / INTOSC / INTRC
    ADCON0     = 0b01000001;       // Fosc/8 & ADON=1
    ADCON1     = 0b10100000;       // Configure Vref+ = on Vref-=Gnd  ADC2=0
    
    //ADC_Init();
    
    Lcd_Init();                       // Initialize LCD on PORTB
    Lcd_Cmd(_LCD_CURSOR_OFF);         // Turn off cursor
    Lcd_Cmd(_LCD_CLEAR);
    // Lcd_Out(1,1,"2500m 23.0v 9.6v");               // Show on LCD
  
    Delay_ms(5000);
  
    while(1)
     {
       // ADval=ADC_Read(CURRENT);
       // result=( (long) 2500 * ADval)/1023;
       // IntToStr(result, txt);
       // Lcd_Out(1,1,txt);               // Show Current
       
       ADval=ADC_Get_Sample(BATTERY);
       result=( (long) 10000 * ADval)/1023;
       
       IntToStr(ADval, txt);
       Lcd_Out(1,1,txt);               // Show Currentin 10bit
       
       ADval=myreadADC(BATTERY);
       IntToStr(ADval, txt);
       Lcd_Out(2,1,txt);               // Show Current
       
       Delay_ms(250);
       
     }

 }
 
What tolerance resistors are you using for your divider? If the "gain" is off by 10%, that would make a 8.6V value show up as 9.5V. You want 1% tolerance resistors or better.
 
Last edited:
What do you get when you feed the 2.5V reference to the ADC input? And what about GND to ADC input?
 
Last edited:
10v and 0v

When i set my tad as 32TOSC the error decreases.
Can I set it at 64Tosc with a 4mhz internal clock?
 
Last edited:
10v and 0v

When i set my tad as 32TOSC the error decreases.
Can I set it at 64Tosc with a 4mhz internal clock?

Maybe you have just answered your problem.... What resistors are you using for your divider? According to the pic adc information.
The source impedance affects the offset voltage
at the analog input (due to pin leakage current). The
maximum recommended impedance for analog
sources is 2.5 k Ω
.

If you have a slow moving analogue input you may use 64tosc IMHO.
 
Last edited:
If increasing the charge time improves the accuracy then your charge time is too fast. What value resistors are you using in the divider? You might be creating a long RC time constant.

EDIT: Ian beat me to it. :)
 
Last edited:
Yes indeed I wanted to save battery thats why i chose those values :)
will check tomorrow and post the progress

thx all
 
I have used the circuit below with battery powered circuits before:

View attachment 66793

When you don't want any current to flow, both pins can be set as digital outputs and forced high. As long as the PIC is directly powered by the signal you are monitoring (the battery) there should be no potential difference in the resistor divider and no current should flow.

During the times when you want to monitor the battery you can set the tap point of the resistor divider to an input (for the ADC) and the lower portion to 0, which should effectively be GND.

I probably used lower resistor values when I actually built the board as I also discovered the maximum impedance in the datasheet.

The code I use is below, with many comments because I'm still working on the board.

Code:
void check_battery_voltage() {
    short result = 0;
    short voltage = 0;

    // RA0 and RA1 for battery voltage monitoring.  Shunt A1 to GND so current
    // can flow through the divider, set A0 to input (middle point).
    TRISAbits.TRISA0 = 1;
    LATAbits.LATA1 = 0;

    ANSA0 = 1;

    // Enable the fixed voltage reference module, select x2 mode, for 2.048v.
    FVREN = 1;
    VREFCON0bits.FVRS = 0b10;

    // Wait for voltage reference to become stable
    while (!FVRST);

    // Choose AN0, positive reference is the internal FVR
    ADCON0bits.CHS = 0;
    ADCON1bits.PVCFG = 0b10;

    // Right justify the result and turn the A/D module on
    ADCON2bits.ADFM = 1;
    ADCON0bits.ADON = 1;

    for (int n = 0; n < 3; n++) {
        // Delay long enough for ADC capacitor to charge
        /* @todo Calculate correct delay in uS */
        DelayMs(4);

        ADCON0bits.GO = 1;
        while (ADCON0bits.GO);

        result = (ADRESH & 0b11) << 8;
        result += ADRESL;

        // 2mV per ADC step, input voltage divided by 1/2 by
        // resistors so we need to scale.
        voltage = result * 4;
    }

    printf("Power input %umV\r\n", voltage);

    ADCON0bits.ADON = 0;
    FVREN = 0;

    // Not necessary ??
    ANSA0 = 0;
}

void disable_battery_monitoring() {
    // Set the two pins to outputs and write a 1, to stop
    // any current flowing through the resistor divider.
    TRISAbits.TRISA0 = 0;
    LATAbits.LATA0 = 1;
    LATAbits.LATA1 = 1;
}
 
I've tested it with lower value resistors , but no change in accuracy.

When I changed the TOSC to 64 8.6v battery show up as 8.75v

I'm back on 10k and 3k3 I think i will settle for this.



Is it ok to use the high Tosc64 setting for my ADC?
 
It should be, especially if you put a cap from the analogue input to ground. :) I have used higher value resistors than that with no problems, in the range of 56k:27k etc.

Have you checked the voltage on the Vref pin (ie checked everything is ok with your 2.35v reference device)?

Are you switching the ADC between multiple pins? If you are then I would increase your 50uS delay to a much larger delay after changing the ADC pin over.
 
I have used the circuit below with battery powered circuits before:

View attachment 66793

Surely if both pins are pulled high (5V) and the voltage measured is 9 volts, you'll have a current flowing through R5 - possibly limited to 5.7 volts through the PIC protection diodes ?

You also run the risk of putting the full 9 volts through the PIC if your 5 volt supply fails ?
 
Surely if both pins are pulled high (5V) and the voltage measured is 9 volts, you'll have a current flowing through R5 - possibly limited to 5.7 volts through the PIC protection diodes ?

You also run the risk of putting the full 9 volts through the PIC if your 5 volt supply fails ?

The bit below is very important:

As long as the PIC is directly powered by the signal you are monitoring (the battery) there should be no potential difference in the resistor divider and no current should flow.

Changes would need to be made if you wanted to check a different power supply.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top