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 CCS Technical Support

A/D conversion (16F690)

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



Joined: 05 Nov 2008
Posts: 25

View user's profile Send private message

A/D conversion (16F690)
PostPosted: Fri Nov 14, 2008 1:36 pm     Reply with quote

Hi,

1) May i know if there any function that can be use to restart A/D conversion?

2) Have seen a book & it says that there is no function to restart the A/D & the solution (for 16F877) is given as follows:

#BYTE ADCON0=0x1F

ADCON0 |=0x4; //to restart A/D by setting the GO bit of ADCON0
register

since the above is for 16F877, how should the above statements be changed for 16F690 ?


Thanks,
CJ
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 14, 2008 2:01 pm     Reply with quote

Download the CCS manual:
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
Look at the read_adc() function.
C0J



Joined: 05 Nov 2008
Posts: 25

View user's profile Send private message

PostPosted: Sat Nov 15, 2008 2:27 am     Reply with quote

Thanks PCM Programmer,

have read up the read_adc() function & the following is my understanding:
(pls correct me if i am wrong, thanks)

1) read_adc() will start the A/D conversion & read the conversion result

2) for my question 2 posted previously, the 2 statements mentioned is not needed since read_adc() will start the A/D conversion & read the conversion result

Thanks,
CJ
C0J



Joined: 05 Nov 2008
Posts: 25

View user's profile Send private message

PostPosted: Sat Nov 15, 2008 1:06 pm     Reply with quote

Hi,

I have a variable resistor connected to portA pin0 (16F690) & when I vary the resistance of the variable resistor only the statement "output_c(0x03);" is executed (refer to the code below).

Have tested out the cct with a workable assembly code & it is able to work, so I can assume that there is no problem with the cct.

Any advice on what went wrong with the code ?
Code:

#include <16F690.h>

#FUSES NOWDT,INTRC_IO,NOPROTECT,NOBROWNOUT,NOMCLR,NOCPD,NOPUT,NOIESO,NOFCMEN
#device ADC=10

int16 ch1_result;

#int_AD
AD_isr()
{
ch1_result=read_adc();
}

void main()
{
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_16);
enable_interrupts(INT_AD);
enable_interrupts(global);
set_adc_channel(1);

while(1)
{
if(ch1_result<200)
output_c(0x01);
else if(ch1_result<800)
output_c(0x02);
else
output_c(0x03);
}
}

Thanks,
CJ
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sat Nov 15, 2008 2:26 pm     Reply with quote

Quote:
1) read_adc() will start the A/D conversion & read the conversion result
True, but your example program doesn't work as the interrupt only fires when a conversion is finished. Your command to start the conversion is in the interrupt routine so this is a chicken-egg problem. Easiest solution is to get rid of the interrupt and move the adc-command into your while-loop. This also prevents problems with the 10-bit result being modified during tests in your main loop.
Ttelmah
Guest







PostPosted: Sun Nov 16, 2008 3:17 am     Reply with quote

Also, 'read_adc, can have a value passed.
So:
read_adc(ADC_START_ONLY); will start an ADC conversion, and not return anything.
While:
read_adc(ADC_READ_ONLY); will read the ADC value, without starting.

Hence PCM's answer. The function can be used to trigger the ADC, _or_ read the ADC, _or_ both (the default).

Beware of using the ADC interrupt. The problem with this, is that in general, it takes longer to get into the interrupt and out of it, than simply to wait for the conversion. The only times that using the ADC interrupt 'make sense', are in two conditions:
First, triggering the ADC off the CCP hardware. Then simply use the 'READ_ONLY' form in the interrupt code.
Second, using the ADC 'sleep' mode. Here, you don't need to have an interrupt 'handler', clear the interrupt, and have the global interrupt disabled, and use the ADC 'START_ONLY' form, as the last instruction before sleeping. When the chip awakens, use the 'READ_ONLY' form to get the result. This is _necessary_ if you want to use the internal RC clock above about 1MHz on most chips, and is actually one of the 'best' ways of getting an accurate result from the ADC.

Best Wishes
C0J



Joined: 05 Nov 2008
Posts: 25

View user's profile Send private message

PostPosted: Thu Nov 20, 2008 8:54 am     Reply with quote

Thanks for the advises

with a variable resistor connected to Vdd & RA0, i have vary the variable resistor & measured the voltage at RA0 as 3.87V

when i use the value 804 (see code below) the statement "output_c(0x04); " is executed

when i change the value to 805 the statement "output_c(0x05); " is executed

so i can say that output value of 804 correspond to a voltage of 1.87V

when i use the equation, digital o/p value= (Vin/Vfullscale) X1023,
the digital o/p value is ~792 (where Vin=3.87V, Vfullscale=5V)

Questions:

1) is there any problem with the code?

2) is there an accuracy problem since the calculated value that correspond to 3.87V is ~792 but the practical result is 804 ?

3) If there is an accuracy problem what are the possible reasons for that?

Thanks,
CJ
----------------------

Code:
#include <16F690.h>

#FUSES NOWDT,INTRC_IO,NOPROTECT,NOBROWNOUT,NOMCLR,NOCPD,NOPUT,NOIESO,NOFCMEN
#device ADC=10

int16 ch1_result;

void main()
{
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_16);
set_adc_channel(0);       

while(1)
{
ch1_result=read_adc();   

else if(ch1_result<804)
output_c(0x04);
else
output_c(0x05);
}
}
C0J



Joined: 05 Nov 2008
Posts: 25

View user's profile Send private message

PostPosted: Thu Nov 20, 2008 8:57 am     Reply with quote

Have posted the wrong code

Pls see the new code below

Thanks
------------------

Code:
#include <16F690.h>

#FUSES NOWDT,INTRC_IO,NOPROTECT,NOBROWNOUT,NOMCLR,NOCPD,NOPUT,NOIESO,NOFCMEN
#device ADC=10

int16 ch1_result;

void main()
{
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_16);
set_adc_channel(0);       

while(1)
{
ch1_result=read_adc();   

if(ch1_result<804)
output_c(0x04);
else
output_c(0x05);
}
}
Ttelmah
Guest







PostPosted: Thu Nov 20, 2008 11:12 am     Reply with quote

First comment, 'read up' on the PIC ADC. On most ADC's the correct conversion is Vef/1023, but on the PIC one, it is Vref/1024.
Second thing is to be aware, that if you are using the Vdd supply as your 'Vref', unless you are _very_ careful with smoothing close to the PIC, you are unlikely to actually 'get' 5v, even if the supply voltage is 5v. The problem is that the ADC, tends to integrate noise spikes on the supply rail, leading to it behaving as if the supply was at a slightly different voltage.
Then the typical voltage regulator will only give perhaps 1 or 2% accuracy, so a value of 793 counts, would probably happen anywhere from perhaps 3.79 to 3.94 volts, even without the noise problem. If you want accuracy, you _must_ use an external Vref, with careful connections as well.
Your figure would be 'spot on', if the supply is actually 4.926v at the PIC. Not at all an unlikely value.
Third comment, you need to allow _time_ between your readings (and before the first one). The PIC ADC, is electrically 'seen' as a small capacitor, connected to the outside world via a resistor (internal resistance in the multiplexer etc.). This capacitor takes _time_ to charge to the incoming voltage. This is why if you select a new ADC channel, you need to wait for a few uSec, before taking the reading. the total time needed, depends on the electrical characteristics of your source, and how close you want to allow the capacitor to charge, but is typically perhaps 10 to 12uSec, for a reasonably low impedance source. The conversion itself, is done with the capacitor disconnected, and voltage on the capacitor _will_change. You therefore need to allow a similar time, between successive conversions. Your total loop time is less than this, so results will not be as good as they can be.

Best Wishes
C0J



Joined: 05 Nov 2008
Posts: 25

View user's profile Send private message

PostPosted: Thu Nov 20, 2008 12:14 pm     Reply with quote

Thanks Ttelmah,

I will read up ADC section of the 16F690 datasheet after sending this.

In the mean time have the following questions that need your help

1)
Quote:
Your figure would be 'spot on', if the supply is actually 4.926v

How is the calculation done for the above quote ?

2) Is it correct for me to say that the statement "ch1_result=read_adc();"
will do the conversion & immediately store the result to 'ch1_result '?

3) Is the following code a better way to allow time between readings?

Thanks again,
CJ
Code:

while(1)
{
read_adc(ADC_START_ONLY);
delay_us(12);
ch1_result=read_adc(ADC_READ_ONLY);   

if(ch1_result<804)
output_c(0x04);
else
output_c(0x05);
}
Ttelmah
Guest







PostPosted: Thu Nov 20, 2008 3:44 pm     Reply with quote

No.
You need time _between_ the readings.
The point is that when the converter is sitting _not reading_, the capacitor is charging. Then when you perform the reading, the capacitor is disconnected from the charging source, to perform the conversion. After the conversion completes, you need to allow time for the capacitor to recharge.
Normally if there is a 'print' of something in the loop, there is enough time. Your loop, only performs one test, and one I/O operation, only perhaps a couple of uSec at 8MHz (your code doesn't show what clock rate is selected).
So:
Code:

while(1) {
   delay_us(10);
   ch1_result=read_adc();   
   
   if(ch1_result<804)
      output_c(0x04);
   else
      output_c(0x05);
}

The Vref voltage is _approximately_ 1024/804.5 * Vin = 4.926
The data sheet itself, doesn't give details of the way the ADC on the PICs behaves. There is a detailed application note for the PIC16, giving the 'best approximation' to use, and the sampling principle is the same on all the ADCs.
In some ways you need to understand the differences between resolution, and accuracy. The PIC ADC, has a _resolution_ of 10bits. It'll only achieve this as an _accuracy_, if the total errors from all other sources (the Vref etc.), is less than 1 in 2048. Even with this,unless your noise sources are below the same limits, your SNR, will be less than 10bits.

Best Wishes
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