|
|
View previous topic :: View next topic |
Author |
Message |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
Wrong AD readings on PIC18F |
Posted: Mon Jun 26, 2017 1:53 pm |
|
|
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
|
|
Posted: Mon Jun 26, 2017 2:52 pm |
|
|
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: 417
|
|
Posted: Mon Jun 26, 2017 3:04 pm |
|
|
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
|
|
Posted: Mon Jun 26, 2017 3:17 pm |
|
|
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: 9229 Location: Greensville,Ontario
|
|
Posted: Mon Jun 26, 2017 5:32 pm |
|
|
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
|
|
Posted: Mon Jun 26, 2017 6:07 pm |
|
|
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: 19520
|
|
Posted: Tue Jun 27, 2017 12:33 am |
|
|
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.... |
|
|
|
|
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
|