|
|
View previous topic :: View next topic |
Author |
Message |
arulchozhan
Joined: 14 Aug 2015 Posts: 12
|
adc in 18f66k80 |
Posted: Fri Aug 14, 2015 12:48 am |
|
|
hi this is arul,
I am working in 18f66k80 controller. I am new to this controller. I am already working on 16f877a with ccs and hitech c (mplab) compilers. Now I am moving to 18f66k80 controller.
My problem is to read adc in 18f66k80. The output is displayed in serial window, using ccs compiler. The code produces some output but not constant value. That means I am varying my pot (potentiometer connected in AN2).
The output value is not varied linearly (for example I am giving 5v that time o/p=4090 (my adc is 12 bit and I am using external crystal at 20 MHZ). If I linearly decrease the voltage using pot, my output was decreased but sometimes goes to the higher value). Here i attach my code and result.
Please anyone help me.
Code: |
#include <18f66k80.h>
#device ADC=12
#FUSES NOWDT //No Watch Dog Timer
//#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
//#FUSES NOJTAG //JTAG disabled
#device ICSP=1
#use delay(clock=20000000)
#use rs232(xmit=pin_g3,rcv=pin_g0, baud=9600 )
void main()
{
long int value; //general practice keep variables local unless they must be global
setup_adc_ports(4); //enable AN8 to multiplexer & select reference
setup_adc(ADC_CLOCK_DIV_16 ); //select clock & Tacq
set_adc_channel(2); //select the channel
while(TRUE)
{
set_adc_channel(2);
delay_ms(10); //delay_ms(100); //since you have set Tacq==0, you must delay _before_ reading
value = read_adc();
delay_ms(100);
printf("Pin AN8 A/C value = %ld \n \r", value);
}
}
|
Result in hyperterminal:
Pin AN8 A/C value = 176
Pin AN8 A/C value = 32
Pin AN8 A/C value = 159
Pin AN8 A/C value = 402
Pin AN8 A/C value = 379
Pin AN8 A/C value = 155
Pin AN8 A/C value = 29
Pin AN8 A/C value = 172
Pin AN8 A/C value = 398
Pin AN8 A/C value = 369
Pin AN8 A/C value = 137
Pin AN8 A/C value = 28
Pin AN8 A/C value = 195
Pin AN8 A/C value = 435
Pin AN8 A/C value = 380
Pin AN8 A/C value = 127
Pin AN8 A/C value = 20
Pin AN8 A/C value = 226
Pin AN8 A/C value = 435
Pin AN8 A/C value = 373
Pin AN8 A/C value = 113
Pin AN8 A/C value = 21
Pin AN8 A/C value = 247 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Fri Aug 14, 2015 4:29 am |
|
|
Code: |
setup_adc_ports(4); //enable AN8 to multiplexer & select reference
//wrong
|
Then there is a conflict in what you say. You are selecting ADC channel 2, to read, but in the comment above you say 'enable AN8'.
The line to select AN2, is:
Code: |
setup_adc_ports(sAN2); //enable AN2 to multiplexer - default reference
|
Currently '4' will select AN0. Don't use hard-coded numbers, use the defined names. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
Re: adc in 18f66k80 |
Posted: Fri Aug 14, 2015 4:44 am |
|
|
arulchozhan wrote: |
Code: |
...
void main()
{
...
setup_adc_ports(4); //enable AN8 to multiplexer & select reference
setup_adc(ADC_CLOCK_DIV_16 ); //select clock & Tacq
set_adc_channel(2); //select the channel
while(TRUE)
{
set_adc_channel(2);
delay_ms(10); //delay_ms(100); //since you have set Tacq==0, you must delay _before_ reading
value = read_adc();
delay_ms(100);
printf("Pin AN8 A/C value = %ld \n \r", value);
}
}
|
|
First off, I'll assume your PIC really is running at the right speed. I don't know if your almost empty fuse setting will work or not, or do what you intend it to do. I suspect it will select an external oscillator rather than a crystal, and so your code may not be running at 20MHz at all, but other people are much better at advising on fuse and clock selection than I am.
setup_adc_ports(4) does NOT enable AN8. It doesn't enable anything: 4 is not a valid parameter for setup_adc_ports(). Use the constants in the .h file. To enable AN8 (assuming that really is what you want to use) you need setup_adc_ports(sAN8); That will also use the 5V supply as the reference, which will not give you 12 bit accuracy. It won't even give you 10 bit accuracy. Even 8 bit is going to be poor. The 5V supply won't be 5V, it could easily be anything from 4.75V to 5.25V, or even worse. It will have lots of noise and will vary depending on what's going on. In short, its rubbish as a reference, unless your all you need is a simple coarse measurement of something.
set_adc_channel(2);
delay_ms(10); //delay_ms(100); //since you have set Tacq==0, you must delay _before_ reading
set_adc_channel(2) doesn't select AN8, it selects AN2. So what channel are you using? The comment is interesting. This ADC will use its own hardware channel select delay if you have selected it in the setup_adc(). As the comment says, you've not set it, so you must put in your own delay between selecting the channel and doing the ADC conversion. You are waiting 10ms, and presumably you've tried 100ms. Far too long. You only need 2.5us. Anything longer just wastes time. I'd give it 4 or 5us, or set Tacq to 4.
Finally (10ms is really foreveeeeeeerr...) you do an ADC conversion, but its not on the channel you want, its just on noise. So it should be no wonder the results are all over the place.
I'm not sure why you'd want to wait a further 100ms before trying to output the result, but as the delay is formatted to the left, I assume you've out it in as part of your debugging.
Cross-posted with Ttelmah :-) That happens sometimes on a Friday. He's one of the experts on clock and fuse settings I mentioned. |
|
|
arulchozhan
Joined: 14 Aug 2015 Posts: 12
|
|
Posted: Fri Aug 14, 2015 6:52 am |
|
|
Yes only comment was wrong, i am working in Analog channel 2 only. Earlier i confirmed the CRO scope, i got 20MHz frequency. and in my serial code too i gave frequency 20MHz like as follows
#use delay(crystal=20000000)
#use rs232(xmit=pin_g3,rcv=pin_g0, baud=9600)
But in MPLAB, Hitech C compiler, there we fuse fosc=HS2 for external clock selection. In ccs pic c compiler how to indicate that we use extenal clock??
I checked with serial communciation, no baud rate issue, so i think my clock source doesnot have problem.
But i still not getting a stable value from analog read. I checked ground, no issue. I think issue with setting and reading adc ports. Now i am getting similar output fluctuating. When i reach the maximum value above 3000 in digital it retains constant and when i increase it reaches til 4096. The problem is when i start decrease(POT) below some range (3000) it starts to fluctuate at low voltages.
Simply i would tell
getting equal const value at 3.5v-5v
below 3.5 it is fluctuating
my code :
Code: |
#include <18f66k80.h>
#device ADC=12
#FUSES NOWDT //No Watch Dog Timer
#use delay(crystal=20000000)
#use rs232(xmit=pin_g3,rcv=pin_g0, baud=9600)
void main()
{
long int value; //general practice keep variables local unless they must be global
setup_adc_ports(sAN2); //enable AN2
setup_adc(ADC_CLOCK_INTERNAL); //select clock & Tacq
set_adc_channel(2); //select the channel
while(1)
{
set_adc_channel(sAN2);
set_analog_pins(sAN2);
delay_ms(10);
value = read_adc();
printf("Pin AN2 A/C value = %ld \n \r", value);
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Aug 14, 2015 4:21 pm |
|
|
Quote: | setup_adc_ports(sAN2); //enable AN2
setup_adc(ADC_CLOCK_INTERNAL); //select clock & Tacq
set_adc_channel(2); //select the channel
while(1)
{
set_adc_channel(sAN2);
set_analog_pins(sAN2);
delay_ms(10);
value = read_adc();
printf("Pin AN2 A/C value = %ld \n \r", value);
} |
You already setup the ADC above the loop. Now, you are setting it up
again, inside the loop. Why ? Plus, you are setting it up incorrectly,
inside the loop. Look in the CCS manual for set_adc_channel().
What is the correct parameter ? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Fri Aug 14, 2015 6:07 pm |
|
|
re:
setup_adc(ADC_CLOCK_INTERNAL); //select clock & Tacq
once again someone is trying to use the internal ADC clock.
A quick review of the PICs datasheet,page 368, chapter 23.5 explains why this is NOT a good choice( see note 2)
also
unless you've got an expensive pot, well, cheap ones are 'noisy' and not precise adding yet another potential problem.
Jay |
|
|
arulchozhan
Joined: 14 Aug 2015 Posts: 12
|
|
Posted: Mon Aug 17, 2015 12:15 am |
|
|
am try to do that also, that means instead of adc internal clock am change clock divided by 16 because my clock is 20mhz (in the data sheet they give Tad value for equal clock freq)
my syntax
setup_adc(ADC_CLOCK_DIV_16);
no change in my output
please any other correction in my code |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Mon Aug 17, 2015 1:13 am |
|
|
The point is that you are ignoring what the manual, and the processor include file says for the functions:
Code: |
#include <18f66k80.h>
#device ADC=12
#FUSES NOWDT //No Watch Dog Timer
#fuses HSH, SOSC_DIG. NOPLLEN, PUT, NOIESO, NOFCMEN
#fuses BROWNOUT_SW, NOMCLR, NODEBUG, STVREN, NOPROTECT
#fuses CANB
//Set your fuses - currently you are 'hoping' that the defaults will be right
#use delay(crystal=20MHz)
//'crystal', ought to set HSH, but you are relying on the compiler getting this
//right. Safer to be explicit, and set the oscillator yourself.
#use rs232(UART1, baud=9600, ERRORS)
//another 'general practice'. Use UART names. Also always use 'ERRORS' on
//a hardware UART, unless _you_ are handling errors yourself.
void main()
{
int16 value; //general practice don't use 'long' this means different things
//on different compilers - be explicit with sizes
setup_adc_ports(sAN2 | VSS_VDD); //enable AN2 - supply as Vref
//The Vref will default to this, but better to be explicit.
setup_adc(ADC_CLOCK_DIV_16); //select clock & Tacq
set_adc_channel(2); //select the channel
while(1)
{
delay_ms(10);
value = read_adc();
printf("Pin AN2 A/C value = %ld \n \r", value);
}
}
|
People are telling to change individual things and then you shoot off and change all sorts of other things incorrectly.
Just use the correct syntax to select the multiplexer pins, then the correct clock, then select the channel. Then read. |
|
|
arulchozhan
Joined: 14 Aug 2015 Posts: 12
|
|
Posted: Mon Aug 17, 2015 2:21 am |
|
|
Thank you for your reply.
I modified the code, the adc output is printed to the serial but the problem was my adc i/p set using 10k pot. If I'm setting voltage 4v (measured by multimeter) the serial output is shown as 3.6v. Also I am varying my pot, voltage is 5v but my serial window shows same 3.6 as well. I'm decreasing the voltage to 0v, that time the serial window shows 1.2.
This is my problem. How can i solve this. Please anyone help me. My code is given below.
Code: |
#include <18f66k80.h>
#device ADC=12
#FUSES NOWDT //No Watch Dog Timer
#fuses HSH, SOSC_DIG, NOPLLEN, PUT, NOIESO, NOFCMEN
#fuses BROWNOUT_SW, MCLR, NODEBUG, STVREN, NOPROTECT
#fuses CANB
#use delay(crystal=20MHz)
#use rs232(UART1, baud=9600, ERRORS)
//#use rs232(xmit=pin_g3,rcv=pin_g0, baud=9600)
void main()
{
int16 value=0; //general practice keep variables local unless they must be global
float ad=0;
setup_adc_ports(sAN2 | VSS_VDD); //enable AN2
setup_adc(ADC_CLOCK_DIV_16); //select clock & Tacq
set_adc_channel(2); //select the channel
while(1)
{
delay_ms(10);
value = read_adc();
ad = (float)value* (5.0/4096);
printf("Pin AN2 A/C value = %f \n \r", ad);
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Mon Aug 17, 2015 2:41 am |
|
|
Several things:
First your accuracy is completely dependant on the accuracy of the supply. Worse, the ADC circuit has a tendency to 'integrate' noise on the supply rail. So if you have 100mV of ripple on the supply (or more), then the value read will be relative to this, not the 'nominal' 5v. The _only_ way to get high accuracy from the ADC, is to use a high accuracy external Vref. Using the supply you will be lucky to get a 'near' value.
Then the impedance of your signal source is too high. The _maximum_ recommended source impedance is 2.5KR.
Then the measure is relative to Vss. Unless your DVM, is actually connected to exactly the same point, the readings will differ.
Then most DVM's tend to integrate. If there is ripple on the voltage, the results will differ. |
|
|
arulchozhan
Joined: 14 Aug 2015 Posts: 12
|
|
Posted: Mon Aug 17, 2015 4:04 am |
|
|
how i solved this? in my hardware the reference pin is getting Aref= 4.6v |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Mon Aug 17, 2015 5:38 am |
|
|
You should post (using a 3rd party website) your schematic and if possible a picture of your project.
Also try using the ADC in '8 bit ' mode. Getting ANY ADC to be accurate and repeatable in 10, 12, 16 bits IS a challenge! You must follow the manufacturers requirements AND bypass a 'tight power supply AND do a proper PCB layout. 'Noise' will get in from several sources. I always use a quality rail-to-rail opamp as a voltage follower buffer.
If possible use an oscilloscope to see Vdd, gnd, the actual analog signals. Also be sure to use ALL VDD pins and ALL GND pins.
Jay |
|
|
arulchozhan
Joined: 14 Aug 2015 Posts: 12
|
This is my schematic |
Posted: Mon Aug 17, 2015 7:25 am |
|
|
Hi, here i attached my schematic
See the analog reference circuit in controller
[img]http://postimg.org/image/iko9itry7/[/img]
http://postimg.org/image/iko9itry7/[/img][/url] |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Aug 17, 2015 8:03 am |
|
|
Your crystal is 40MHz, not the 20MHz your fuses and setting state! The maximum your PIC will go to with a crystal is 25MHz. It will work to 64MHz with an external oscillator, but the internal oscillator will only go to 25MHz. This could be the root of your problems.
I run this family of PICs with a 16MHz crystal and use the PLL to give 64MHz processor clock. Its cheaper and smaller than an oscilllator. I have a well tested PCB layout block that I use for all 66K80 family devices.
I regularly run these with the 12 bit ADC and get close to 11 bit precision with a low cost external reference. There is an errata issue that causes an offset in the results, but that can often be calibrated out if required. So I know these PICs produce good ADC readings when used correctly. |
|
|
arulchozhan
Joined: 14 Aug 2015 Posts: 12
|
|
Posted: Mon Aug 17, 2015 8:17 am |
|
|
Thank you for your reply, actually am using 20 MHz crystal in my real hardware because we don't use crystal directly on 40 MHz, so I replace my crystal at 20 MHz .
The above discussion are for 20 mhz. I forget to change in schematic, sorry sir.
Any other issue in my hardware and software side please help me, am waiting your reply, thanks again. |
|
|
|
|
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
|