View previous topic :: View next topic |
Author |
Message |
ingemilo
Joined: 19 Apr 2016 Posts: 6
|
ADC module in 18F4550 |
Posted: Wed Apr 20, 2016 9:21 am |
|
|
I am working in a project with 18F4550.
It needs to acquire data from an LM35 and send it to a PC via USB
The problem is the data acquired is "jumping" in value about 3 or 5 degrees above or below. It must be steady unless temperature arises or changes.
I think something is wrong with the configuration of everything involved with the ADC MODULE, Specially the adjustment of the Tad.
I have a 20MHZ Xtal and it is raised by PLL to 48MHZ
I would like somebody of you could write for me some example of the lines I should write into my program for the ADC.
I think the Tad is too short and that is the reason why it jumps.
Thank you in advance. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Apr 20, 2016 9:34 am |
|
|
Use the forum's search page:
http://www.ccsinfo.com/forum/search.php
Search for:
Set it to search for all term:
Quote: | [x]Search for all terms |
This will get you every thread that has ADC code for the LM35. |
|
|
ingemilo
Joined: 19 Apr 2016 Posts: 6
|
|
Posted: Wed Apr 20, 2016 10:23 am |
|
|
PCM programmer wrote: | Use the forum's search page:
http://www.ccsinfo.com/forum/search.php
Search for:
Set it to search for all term:
Quote: | [x]Search for all terms |
This will get you every thread that has ADC code for the LM35. |
I found something similar to my problem
in "Extrange changes in ADC" by verba
Data entered to the hyperterminal is similar to this. The diference is I am using just one channel, and I am using 18F4550 instead 16F876
C0=0 - C1=64 - C2=0 - C3=1018 - C4=51 - C5=58
C0=2 - C1=64 - C2=0 - C3=1023 - C4=58 - C5=56
C0=0 - C1=55 - C2=0 - C3=1022 - C4=60 - C5=56
C0=2 - C1=59 - C2=0 - C3=1023 - C4=64 - C5=56
C0=0 - C1=58 - C2=2 - C3=1022 - C4=60 - C5=60
C0=1 - C1=60 - C2=0 - C3=1022 - C4=55 - C5=56
C0=1 - C1=57 - C2=0 - C3=1023 - C4=60 - C5=56
C0=0 - C1=59 - C2=2 - C3=1023 - C4=57 - C5=57
C0=4 - C1=60 - C2=1 - C3=1021 - C4=57 - C5=55
C0=0 - C1=58 - C2=1 - C3=1023 - C4=61 - C5=58
C0=0 - C1=58 - C2=1 - C3=1022 - C4=60 - C5=56
C0=0 - C1=51 - C2=0 - C3=1023 - C4=58 - C5=56
C0=0 - C1=56 - C2=0 - C3=1021 - C4=60 - C5=57
C0=0 - C1=58 - C2=0 - C3=1022 - C4=56 - C5=57
C0=4 - C1=58 - C2=0 - C3=1019 - C4=51 - C5=60
C0=2 - C1=59 - C2=0 - C3=1022 - C4=56 - C5=56
C0=0 - C1=58 - C2=0 - C3=1023 - C4=56 - C5=56
C0=0 - C1=55 - C2=0 - C3=1023 - C4=59 - C5=51
C0=0 - C1=59 - C2=3 - C3=1023 - C4=59 - C5=51
C0=1 - C1=58 - C2=0 - C3=1022 - C4=60 - C5=56
C0=0 - C1=57 - C2=0 - C3=1022 - C4=55 - C5=60
C0=1 - C1=61 - C2=2 - C3=1023 - C4=60 - C5=60
C0=0 - C1=60 - C2=0 - C3=1023 - C4=57 - C5=58
C0=0 - C1=60 - C2=0 - C3=1023 - C4=57 - C5=56
any idea what to do for solve this? making changes in the adc module? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Wed Apr 20, 2016 10:54 am |
|
|
Obvious questions.
What are you using for Vref?.
What other circuitry is on the board?.
If you are using the PIC supply, then this is almost certainly 90% of the reason for variations.....
If you look at other threads with variable values, like:
<http://www.ccsinfo.com/forum/viewtopic.php?t=50585&highlight=lm35+setupadc>
You will see that this was caused by insufficient smoothing.
The software solution, is to average the adc readings. Will only 'solve' the problem if the noise is basically random.
Looking at the noise pattern, one thing leaps out, which is that the change is basically the same for low values as the high values. Suggests noise in the ground connection between the PIC and the LM35... |
|
|
ingemilo
Joined: 19 Apr 2016 Posts: 6
|
|
Posted: Wed Apr 20, 2016 11:22 am |
|
|
This is my code
Code: |
#include <18f4550.h>
#device adc=10
#fuses hspll,nowdt,noprotect,nodebug,usbdiv,pll5,cpudiv1,vregen
#use delay(clock=48000000)
#include <usb_cdc.h>
int16 grados;
int16 medicion;
void main(){
usb_cdc_init();
usb_init();
do{
usb_task();
setup_adc(adc_clock_div_32);
setup_adc_ports(all_analog);
setup_adc_ports(AN0);
set_adc_channel(0);
delay_us(20);
if(usb_enumerated()){
medicion=read_adc();
delay_us(20);
setup_adc(adc_off);
grados=((medicion)*(500))/(1024);
printf(usb_cdc_putc,"\r %Lu C",grados);
delay_ms(1000);
}
}
while(true);
}
|
Please let me know if I have to make any change in it.
Circuit is fed with +5V regulated with 7805.
I have a doubt in the line .
Code: | setup_adc(adc_clock_div_32); |
Is taken 48MHz/32? or
is taken 20MHz/32?
Because my Xtal is 20MHz
Another doubt I have:
If I use
Code: | setup_adc(adc_clock_internal); |
Is the time always between 2-4 us regardless the oscillator of 48MHz or 20MHz or 4MHz or whatever? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Wed Apr 20, 2016 2:37 pm |
|
|
ADC_CLOCK_INTERNAL is not recommended for processor speeds above 1MHz, unless you put the processor to sleep for the conversion.
The reason is that the clock is asynchronous to the processor operation, and with lots of processor instructions in each ADC clock, you will get random variation in the results as the processor instruction clock 'beats' with the adc clock. A sure way to get poor stability.
Couple this to using the Vss supply as a Vref, and you are unlikely to get values ever better than several counts of variation. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Wed Apr 20, 2016 3:13 pm |
|
|
Whenever I used the LM34/ LM35 sensors I built a 'signal conditioning PCB which consisted of the LM34, a rail to rail OP AMP used as a voltage follower, 2- 10r resistors and 2- 22mfd caps. The Rs and Cs formed a 2 stage R-C filter on the power going to the opamp and LM34. As well there was a small cap (I think 1 mfd) on the output of the opamp to slow down the analog signal. I easily had 50 feet (20 meters ?) of cable between the sensor and the PIC. Generally speaking 'temperature' controllers do NOT require fast response, 1/4 second is actually fast.
Also, 'noise' can come in the Vdd and gnd lines of the PIC, so be sure to use bypass caps (.1 mfd) at all power feeds.
To get very stable readings Vref of the ADC needs to be precise, the LM7805 isn't, can easily be 4.9 to 5.1 and WILL vary depending on load. Turning on a couple LEDs can drop Vdd, and your math conversion as well as actual ADC reading will be wrong.
Also, consider that a DVM or DMM actually only sample at 3-4 times per second. It's well 'filtered' to NOT jump around and actually hides noise.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu Apr 21, 2016 1:13 am |
|
|
Also, the code posted is turning the ADC off after the first reading. Read then has to switch it back on. It will do so, but there will then be no acquisition time. Another reason for getting poor readings. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Thu Apr 21, 2016 9:12 am |
|
|
You also need to think about this conversion:
Code: | grados=((medicion)*(500))/(1024);
|
Over what range will this work? Hint: not the full range of the sensor. What will happen if the value is out of range? Hint: not what you may expect. Why? Hint: think about the ranges of the intermediate values in the expression. While this uses integer maths, which is good, it uses 16 bit integer arithmetic and that isn't enough to deal with all possible ADC values that the sensor can produce.
This would work better as:
Code: | grados = (medicion * 125)/256;
// There is no need for all those brackets, they just confuse things.
// This could even be, as this is a special case (think about it...):
grados = make8(medicion * 125, 1);
// In all three versions, grados only needs to be int8.
|
And in no case will it work below a few degrees C. |
|
|
ingemilo
Joined: 19 Apr 2016 Posts: 6
|
|
Posted: Sat Apr 23, 2016 8:16 am |
|
|
Ttelmah wrote: | Also, the code posted is turning the ADC off after the first reading. Read then has to switch it back on. It will do so, but there will then be no acquisition time. Another reason for getting poor readings. |
Good point. Let me check it. |
|
|
|