CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Wrong AD readings on PIC18F

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
E_Blue



Joined: 13 Apr 2011
Posts: 410

View user's profile Send private message

Wrong AD readings on PIC18F
PostPosted: Mon Jun 26, 2017 1:53 pm     Reply with quote

I'm using AN0 and AN1 to read two voltages.

PIC18F67J50

+Vref=VDD=3.3V
-Vref=VSS=GND

Bat1 is a single cell lithium battery (3.3V/4.3V) But some times I get 19V on my readings
The same happen with the Bat2=12V acid battery.

I'm using different clock speeds to reduce consumption.

Can be something wrong in the code below?

The sub is called AD_ISR but DID NOT use any AD ISR.

Code:
#define Bat1 0
#define Bat2 1

char AdcChannel=Bat1;
long VoltBat1[5];
long VoltBat2[5];

short BatCellBufferReady=false;
short BatExtBufferReady=false;
char BatCelOffset=0;
char BatExtOffset=0;

void SetAdcSpeed()
{
   if(OscMode!=LastOscMode)
   {
      LastOscMode=OscMode;
      
      if(OscMode==Osc48MHz)
       {
           SETUP_ADC(ADC_CLOCK_DIV_64|ADC_TAD_MUL_20);
      }
      else if(OscMode==Osc500KHz)
      {
         SETUP_ADC(ADC_CLOCK_DIV_2|ADC_TAD_MUL_4);
      }   
      else if(OscMode==Osc32KHz)
      {
         SETUP_ADC(ADC_CLOCK_DIV_2|ADC_TAD_MUL_2);
      }   
      else if(OscMode==Osc4MHz)
      {
         SETUP_ADC(ADC_CLOCK_DIV_4|ADC_TAD_MUL_4);
      }   
   }   
}
   
void SubTensiones(void)
{
   AdcChannel=Bat1;
    SETUP_ADC_PORTS(AN_PORTS);
    SetAdcSpeed();       
    SET_ADC_CHANNEL(AdcChannel);
    delay_us(3);
    AD_ISR();
   
    AdcChannel=Bat2;
    SET_ADC_CHANNEL(AdcChannel);
    delay_us(3);
    AD_ISR();
}

void AD_ISR(void)
{
    long long DummyVolt;
    char X_Offset;
     
    DummyVolt=READ_ADC();
   
    if(AdcChannel==Bat1)
    {
        VoltBat1[Bat1Offset]=(long)((247*DummyVolt)/100);
        DummyVolt=0;
 
        if(!LVDSTAT)
        {
            VoltBat1[4]=0;
        }
         else
        {   
           for(X_Offset=0;X_Offset<=3;X_Offset++)
           {
               DummyVolt+=VoltBat1[X_Offset];
           }   
           VoltBat1[4]=(DummyVolt/4);
          
           if(Bat1Offset>=3)
           {
               Bat1Offset=0;
               Bat1BufferReady=true;
           }   
           else
           {
               Bat1Offset++;
           }   
       }
    }
    else if(AdcChannel==Bat2)
    {
        VoltBat2[Bat2Offset]=(long)(((491*DummyVolt)/100)+30);
        DummyVolt=0;
        for(X_Offset=0;X_Offset<=3;X_Offset++)
        {
            DummyVolt+=VoltBat2[X_Offset];
        }   
        VoltBat2[4]=(DummyVolt/4);
       
        if(Bat2Offset>=3)
        {
            Bat2Offset=0;
            Bat2BufferReady=true;
        }
        else
        {
            Bat2Offset++;
        }   
    }   
    disable_interrupts(INT_AD); 
}

_________________
Electric Blue
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Mon Jun 26, 2017 2:52 pm     Reply with quote

Divide and conquer.

Can you reduce your code to around 10 lines?
It helps if your code is complete and compilable so we can copy and paste.

Mike
E_Blue



Joined: 13 Apr 2011
Posts: 410

View user's profile Send private message

PostPosted: Mon Jun 26, 2017 3:04 pm     Reply with quote

The full code is about 14K lines and have devices like SPI EEPROM, a GPS and a GPRS modem.

I have no idea how to reduce all that code to 10 lines.
Also, this, doesn't happens always so I'm not sure if the error is due to some hardware glitch (GSM RF), or an error in the firmware.

Have some tendency to happen with low voltages like 3.3V on the lithium battery.
_________________
Electric Blue
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Mon Jun 26, 2017 3:17 pm     Reply with quote

You're complaining about a fault on the a2d.
So attack that problem on its own.
Should only require 10 or 20 lines of code.

I'd like to help but can't if the reason lies in code you've not shown.
Also I (and most others) don' t want to wade through pages of irrelevant code.

Mike
temtronic



Joined: 01 Jul 2010
Posts: 9100
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jun 26, 2017 5:32 pm     Reply with quote

I agree with Mike about the code, just cut a 'read adc-display result-loop forever' kind of program....

There's 100+ reasons for 'glitches', so it won't be fun to figure out which...
Mechanical switches, push buttons, loose connections, EMI, relays, the list is endless. Without knowing the product, layout, container, local EMI gennys (phones, PCs, CFLs) it's a 'make a list, test, check it off' task.

It sounds like you're running off a battery so if you're concerned about power consumption you need to read Microchip's application note about it. Ancient, maybe #0069 ? PIC16C84, adc chip, battery. LOTS of info...speed vs power vs time from real world tests.

Having the PIC go slower to save energy may NOT be the correct choice, the appnote explains this unfortunately my uChip AP book has gone 'walkabout' !

Jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jun 26, 2017 6:07 pm     Reply with quote

In additon to that, there are many things you have not told us.

1. Do you have the compiler setup for 8-bit or 10-bit A/D ?

Quote:
Bat1 is a single cell lithium battery (3.3V/4.3V) But some times I get 19V on my readings.

2. How do you calculate the 19 volts ? Post the code that does the
calculations and any conversion code that converts the binary numbers
from the raw A/D readings into the number "19".

Quote:

The same happens with the Bat2=12V acid battery.

3. Presumably you have a resistor voltage divider on the input of the
PIC to reduce the 12v down to 3.3v or less. Describe the voltage divider
and include the resistor values.

4. Apparently you call AD_ISR() multiple times. Apparently LVDSTAT
controls when the loop ends. What is LVDSTAT ? How is it updated ?
How do you guarantee that LVDSTAT goes high after exactly 4 iterations
through your loop ? At the end, you calculate an average of 4 values.

I would just used a simple for() loop to get 4 A/D readings and then
average them. In other words, you code seems too complicated to me,
which is probably why you are having problems.
Ttelmah



Joined: 11 Mar 2010
Posts: 19217

View user's profile Send private message

PostPosted: Tue Jun 27, 2017 12:33 am     Reply with quote

As a couple of other comments:

1) Consider changing your resistor values (making the same assumption as PCM_programmer about a divider somewhere), to simplify the maths. For instance, on your first reading, you have *247/100. Could you change the dropper resistor value to make the required conversion *2, or *4. Far faster, smaller code, no need to use an int32 etc etc..

2) Don't use terms like 'long', and 'long long'. These are ways of ensuring you have problems with sizing later. You switch to another processor, and these change. Use sizes that are defined. So int16, int32 etc.. These then ensure you know what size is actually being used.

3) Generally though you say you are not using INT_AD, I have to ask why this is being disabled at the end. If there is an intention to use this for something, the code would need major re-thinking.

INT_AD, triggers _when an ADC conversion completes_. It actually takes longer to handle this, than to simply wait for the conversion to complete. It's only use, is if you are triggering the ADC conversion with another source (so perhaps the CCP to have it synchronous to a PWM for example). For anything else, stop even thinking about it.

---------------------
Some other comments added:

Your TAD_MUL settings seem very dubious. These are multiples of the ADC Tad. So if the right divisor to give the right ADC clock, the TAD_MUL setting would want to stay the same at all clock rates. You also don't need the delay after setting up the ADC the converter itself delays for the Tad MUL setting.

You don't show us your definition of 'AN_PORTS', so we are blind about how you are actually configuring.

Honestly the most likely reason for a glitch is either something simple like maths overflowing (which is why if you simplify and the problem goes away, it'll give a large hint), or electrical.

Do you actually make any use of the stored individual readings?. If not, then these are a waste. The simplest way is just to add the new reading to a total, and when the number of readings reaches the total you require do your maths on this total. Reduces the waste of array storage (slow), and the space needed as well....
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group