Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] problem in PIC internal ADC, external Vref, MCU-pic16f886

Status
Not open for further replies.

pravin b

Member level 5
Joined
May 20, 2012
Messages
85
Helped
2
Reputation
4
Reaction score
1
Trophy points
1,288
Location
Mumbai, India
Activity points
2,083
Hello all, I am using PIC16F886 to read the input voltage 0-1 Volt (amplified to 0-2.88V) at channel AN4. I have set +Vref=2.88 (external) and -Vref=Vss. I am displaying the measured voltage on 3 digit 7 segment display. The problem I am facing is- I get the displayed voltage lesser than the actual. SO, initially I had doubt on hardware, but the other program which is in assembly language (with which I am not comfortable) is showing perfect reading. Which indicates that my software (written in C) has some issue, which I am not able to identify. I am attching here both assembly and C program, it woud be helpful if someone here can guide me to some direction. Thanks.
I am using MPLABX IDE, XC8 compiler.
MC- pic16f886, internal oscillator.
Main file C Code:
C:
// PIC16F886 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown Out Reset Selection bits (BOR disabled)
#pragma config IESO = OFF        // Internal External Switchover bit (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)

// CONFIG2
#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)

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

void systemInitialization(void)
{
    //select internal frequncy to 8Mhz
    OSCCON = 0x71;                      //IRCF=111, SCS=1
    while(!(OSCCON & (OSTS && HTS)));   //wait till OSC gets stable
    portInitialization();
    timer0_init();
    ADCInitialization();
//    UART_Init(9600);      //for debugging only
}

void main(void)
{
    unsigned int adcReading=0, avgAdcReading=0, adc_arr[ADC_AVG_COUNT]= {0}, speed = 0,  Vspeed = 0;
 
    systemInitialization();
    while(1)
    {  
        //take moving average of 10 readings
        char i=0;
        //array shifting
        for(i=0; i<ADC_AVG_COUNT-1; i++)
        {
            adc_arr[i]=adc_arr[i+1];      
        }
        //update current reading in arrac
        adc_arr[ADC_AVG_COUNT-1]=ADC_Read(SPEED_INPUT_CH);
        //take avarage of readings in array
        for(i=0;i<ADC_AVG_COUNT;i++)
        {
            avgAdcReading += adc_arr[i];
        }  
        adcReading = avgAdcReading/ADC_AVG_COUNT;       //moving average value
        avgAdcReading = 0;
       
        disNum = ((float)1000/1023)*adcReading;      //this shows 0->0 & 1023->100

//        char dstr[6];
//        sprintf(dstr, "%d\n", adcReading);
//        UART_TxString(dstr);      
    }
    return;
}

ADC code:
C:
void ADCInitialization(void)
{
    ADCON0 = 0x90;//0x91;      //fosc/32, ch4 selected
    ADCON1 =  0x90;         //Vref from RA3/AN3, right justified
    ADCON0 = ADCON0|0x01;   //turn on ADC module
}

unsigned int ADC_Read(unsigned char channel)
{
    int aadc, bbdc, ccdc;
    unsigned int adc_data=0;
//  if(channel > 7)              //Channel range is 0 ~ 7
//    return 0;
//
//  ADCON0 &= 0xC5;              //Clearing channel selection bits
//  ADCON0 |= channel<<3;        //Setting channel selection bits
  __delay_ms(2);               //Acquisition time to charge hold capacitor
  GO_nDONE = 1;                //Initializes A/D conversion
  while(GO_nDONE);             //Waiting for conversion to complete
  adc_data = ((ADRESH<<8) + ADRESL);
  return adc_data;  
}

Attaching working code in assembly language.
Thanks.
 

Incomplete code, e.g. important variable definitions missing. You also forgot to report the obtained adc readings.
--- Updated ---

I doubt that (ADRESH<<8) does what you expect, ADRESH should be type casted to unsigned int before shifting it.

Code:
((unsigned int)ADRESH<<8)
 

Hi,

an ADC always has some errors:
* offset error
* gain error
* linearity error

And the external hardware too:
* accuracy of initial input
* OPAMP circuit gain error (Rs, OPAMP..)
* OPAMP circuit offset error
* Reference voltage

and there maybe are problems in software, like hardware setup (ADC clock, I/O config), calculation errors and so on.

For me, to get a clue about the problem, I need some information about the whole queue. Form signal source (DC, AC, where does it come from?) to the digital ADC values. Are they noisy or are they stable? How much are they off the expected value?

Klaus
 

Thanks for the reply.
@FvM Yes, the code is not complete since I was keen to post the most obvious problem areas (ofcourse in my openion ;)). However, I am attaching the complete MPLABX project (in zip file), if that helps. I did not type casted ADRESH, since its a 1 byte register.

@KlausST since I am testing unit on my workbench, I am applying DC 0-1V by using resistor divider network (DC 5V to 1V). Measuring this on my multimeter shows very stable reading. 0-1V is further amplified to 0-2.88V before applying to AN4. I checked voltage at AN4 using DMM, its a stable. Amplification is linear too.

@FvM @KlausST I will share the table of expected and actual adc readings. As i said earlier, other program which is in assembly language (with which I am not comfortable) is showing perfect reading. I did attached assembly language program as attachment. Can you guys please confirm if you are able to see it?
Thank you.
 

Hi,
I checked voltage at AN4 using DMM, its a stable
It´s hard to compare an instantaneous ADC value with a rather low pass filtered DVM reading.
If the signal or the reference is noisy then you will see it only o the ADC, but not on the DVM.
.. on the other hand its betther than nothing.

I did not type casted ADRESH, since its a 1 byte register.
Yes, this exactly is the problem.
Have an 8 bit value and shift it 8 bits left. then surely the result it zero.

Thus you have to typecast the 8 bit value to 16 bit integer value, then shift it 8 bits left.
The result is 256 times the value before.

Klaus
 

.zip is generally working for attachments, but there's apparently a problem with the mplab.x project folder content, may be Edaboard server is interpreting some files as viruses.
 

I hope you are able to view and download my mplabx project folder through link I shared. @FvM @KlausST

Please find the adc reading (expected vs actual) for 0-1V with step of 50mV

Volts
(in mV)
Expected
ADC count
Actual
ADC count
000
505146
10010297
150154148
200205199
250256248
300307299
350358350
400410400
450461451
500512502
550563552
600614602
650666654
700717705
750768754
800819805
850870856
900922907
950973957
100010241007
 
Last edited:

adding table by adding column for voltage at pic analog channel after amplification below:
Volts
(in mV)
V at AN4 (in Volts-
post amplification)
Expected
ADC count
Actual
ADC count
0000
500.135146
1000.2610297
1500.39154148
2000.52205199
2500.65256248
3000.78307299
3500.91358350
4001.04410400
4501.17461451
5001.3512502
5501.43563552
6001.56614602
6501.69666654
7001.82717705
7501.95768754
8002.08819805
8502.21870856
9002.34922907
9502.47973957
10002.8810241007
 

Hi,

The values in the 2 left colums are perfect. Not the tinyiest error. Are they really measured values?
ADC value of 1024 is impossible.

The actual ADC values do have some small offset error and a bit of gain error.
The gain error may be caused by a too high reference voltage. Did you check the 2.88V accuracy?
I miss a schematic and a PCB layout.

Why didn't you simply include the ASM program using the "insert code" button?
Or as attachment - renamed as ".txt"?
(I'm working on old tablet)

Klaus
 

I checked how XC8 treats the (ADRESH<<8) operation. It actually converts it to unsigned int without a type cast. This is expectable due to C integer promotion rule, which says that character and short int types are converted to int or unsigned int respectively when used in an integer expression. Sorry for misleading.

Code:
  2944                           ;adc.c: 31: adc_data = ((ADRESH<<8) + ADRESL);
  2945  072C  081E                   movf    30,w    ;volatile
  2946  072D  00AA                   movwf    ADC_Read@adc_data+1
  2947  072E  1683                   bsf    3,5    ;RP0=1, select bank1
  2948  072F  1303                   bcf    3,6    ;RP1=0, select bank1
  2949  0730  081E                   movf    30,w    ;volatile
  2950  0731  1283                   bcf    3,5    ;RP0=0, select bank0
  2951  0732  1303                   bcf    3,6    ;RP1=0, select bank0
  2952  0733  00A9                   movwf    ADC_Read@adc_data
--- Updated ---

Regarding reported ADC deviations, it's not clear to me how the above "Actual ADC count" numbers have been obtained. The posted code doesn't output output ADC results directly.
 

@KlausST Please find attached asm code in .txt file.
Yes column 1 & 2 are real values measured on actual hardware using DVM. Also, I checked the refrence voltage for entire range of input voltage i.e. 0-1Volts, its rock steady. Sorry, i cant publish circuit schematic here as it is developed by external vendor and is not in my control.
@FvM i displayed "Actual ADC count " on 7 segment display temporarily for debugging purpose.
 

Attachments

  • eco_CBI.txt
    46.7 KB · Views: 103

Also, I checked the refrence voltage for entire range of input voltage i.e. 0-1Volts, its rock steady.
"rock steady" means precision, but not accuracy.

If we talk about noise or fluctuation we talk about precision.
If we talk about gain error, then we talk about accuracy. It means it should be 2.88V but actally it is 2.92V, for example.

Klaus
 

"rock steady" means precision, but not accuracy.

If we talk about noise or fluctuation we talk about precision.
If we talk about gain error, then we talk about accuracy. It means it should be 2.88V but actally it is 2.92V, for example.

Klaus
Ok. I didn't check it on oscilloscope for noise or fluctuations (as I don't have it in my home setup) but when checked on DVM, it constantly shows 2.88V.
 

DVMs are useless for variations faster than a few tenth's of a Hz - for example my DVM updates every couple of seconds.
Even a cheap USB scope would be useful in this case.
Susan
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top