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

adc in 18f66k80
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
arulchozhan



Joined: 14 Aug 2015
Posts: 12

View user's profile Send private message Send e-mail

adc in 18f66k80
PostPosted: Fri Aug 14, 2015 12:48 am     Reply with quote

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: 19339

View user's profile Send private message

PostPosted: Fri Aug 14, 2015 4:29 am     Reply with quote

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

View user's profile Send private message

Re: adc in 18f66k80
PostPosted: Fri Aug 14, 2015 4:44 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Fri Aug 14, 2015 6:52 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Aug 14, 2015 4:21 pm     Reply with quote

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: 9163
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Aug 14, 2015 6:07 pm     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Aug 17, 2015 12:15 am     Reply with quote

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: 19339

View user's profile Send private message

PostPosted: Mon Aug 17, 2015 1:13 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Aug 17, 2015 2:21 am     Reply with quote

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: 19339

View user's profile Send private message

PostPosted: Mon Aug 17, 2015 2:41 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Aug 17, 2015 4:04 am     Reply with quote

how i solved this? in my hardware the reference pin is getting Aref= 4.6v
temtronic



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

View user's profile Send private message

PostPosted: Mon Aug 17, 2015 5:38 am     Reply with quote

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

View user's profile Send private message Send e-mail

This is my schematic
PostPosted: Mon Aug 17, 2015 7:25 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Aug 17, 2015 8:03 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Aug 17, 2015 8:17 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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