|
|
View previous topic :: View next topic |
Author |
Message |
C0J
Joined: 05 Nov 2008 Posts: 25
|
A/D conversion (16F690) |
Posted: Fri Nov 14, 2008 1:36 pm |
|
|
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
|
|
|
C0J
Joined: 05 Nov 2008 Posts: 25
|
|
Posted: Sat Nov 15, 2008 2:27 am |
|
|
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
|
|
Posted: Sat Nov 15, 2008 1:06 pm |
|
|
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
|
|
Posted: Sat Nov 15, 2008 2:26 pm |
|
|
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
|
|
Posted: Sun Nov 16, 2008 3:17 am |
|
|
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
|
|
Posted: Thu Nov 20, 2008 8:54 am |
|
|
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
|
|
Posted: Thu Nov 20, 2008 8:57 am |
|
|
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
|
|
Posted: Thu Nov 20, 2008 11:12 am |
|
|
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
|
|
Posted: Thu Nov 20, 2008 12:14 pm |
|
|
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
|
|
Posted: Thu Nov 20, 2008 3:44 pm |
|
|
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 |
|
|
|
|
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
|