View previous topic :: View next topic |
Author |
Message |
omid_juve
Joined: 25 Oct 2012 Posts: 8
|
Internal reference using for adc? |
Posted: Thu Oct 25, 2012 1:35 am |
|
|
I am becoming so confused why my code is not working. I want to use internal vref 2.048v as a reference for my adc conversion but it doesn't work.
Please see my setup to see if it is correct.
Code: |
#int_AD
void AD_isr()
{
value[0] = Read_ADC(ADC_READ_ONLY);
}
void main()
{
setup_vref(VREF_ON|VREF_ADC_2v048);
setup_adc_ports(sAN0|VSS_FVR);
setup_adc(ADC_CLOCK_DIV_64);
set_adc_channel( 0 );
Read_ADC(ADC_START_ONLY);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
}
|
When I put 2.5v on AN0 input channel it reads 511 !!!!!
plz help me.
My pic is 16f1947 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Thu Oct 25, 2012 2:01 am |
|
|
First thing, don't use INT_AD. INT_AD, is only wanted, when you have something else triggering the ADC (CCP for example), or you use sleep for the conversion (it will then allow you to wake). Otherwise it takes longer to get into the interrupt than it would take to just wait for the conversion.....
What compiler?. Then we can check if the version you have does set this up correctly.
Obvious comment Tad. You _must_ always wait for Tad, between selecting an ADC channel, and reading it, or the value you get will be wrong. This may be your main problem. Internally the ADC has a small 'hold' capacitor, and this takes time to charge.
Best Wishes |
|
|
omid_juve
Joined: 25 Oct 2012 Posts: 8
|
|
Posted: Thu Oct 25, 2012 4:47 am |
|
|
Ttelmah wrote: | First thing, don't use INT_AD. INT_AD, is only wanted, when you have something else triggering the ADC (CCP for example), or you use sleep for the conversion (it will then allow you to wake). Otherwise it takes longer to get into the interrupt than it would take to just wait for the conversion.....
What compiler?. Then we can check if the version you have does set this up correctly.
Obvious comment Tad. You _must_ always wait for Tad, between selecting an ADC channel, and reading it, or the value you get will be wrong. This may be your main problem. Internally the ADC has a small 'hold' capacitor, and this takes time to charge.
Best Wishes |
I use delay but the problem is still exist.
Please see the code.
Code: |
#int_AD
void AD_isr()
{
value[0] = Read_ADC(ADC_READ_ONLY);
delay_ms(1);
Read_ADC(ADC_START_ONLY);
}
void main()
{
setup_vref(VREF_ON|VREF_ADC_2v048);
setup_adc_ports(sAN0|VSS_FVR);
setup_adc(ADC_CLOCK_DIV_64);
set_adc_channel( 0 );
Read_ADC(ADC_START_ONLY);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
}
|
What do you mean by ""First thing, don't use INT_AD. INT_AD, is only wanted,""
Also my compiler version is 4.13 pcm |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Thu Oct 25, 2012 7:28 am |
|
|
Code: |
void main(void) {
unsigned int16 value;
setup_vref(VREF_ON|VREF_ADC_2v048);
setup_adc_ports(sAN0|VSS_FVR);
setup_adc(ADC_CLOCK_DIV_64);
set_adc_channel( 0 );
do {
//This is where the delay is needed to allow the ADC to acquire
delay_us(500);
//Only needs to typically be 2.5 to 10uSec, but put longer
//delay here to slow the output
value=read_adc(); //Using INT_AD, _just costs time_
printf("ADC value = %04lu\n\r",value);
} while (TRUE);
}
|
INT_AD, gains you absolutely nothing. It should _only_ be used, if you are either starting the ADC with a timer (in which case it triggers to tell you the conversion has happened), or if you are putting the processor to sleep for the ADC conversion. Otherwise all it does is _costs time_.
The delay needs to be between selecting the ADC channel, and performing the conversion, and between successive conversions _read the data sheet_. |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Thu Oct 25, 2012 8:58 am |
|
|
I have not looked at the spec sheet for your chip (not all chips have internal Vref sources you can use) - the one I was using is the 18f14k22 and when I was working on it last year, I found the compiler at that time did not correctly let me set the Vref to the internal bandgap reference. I ended up setting the config register myself - here is a snippet of code from my code showing how I did it - this may be what you have to do (I have not yet tried the new version of the compiler to see if it now understands the internal reference settings (I did notifiy CCS about the issue) - note that the page numbers referenced in the comments are for my chip the 18f14k22 (for my project, 1024 was full scale from the temp sensors).
Code: |
// Processor specific ADC config info
// Define some SFR registers we need access to ...
#BYTE VREFCON0 = 0xFBA // Vref configuration registers
#BYTE VREFCON1 = 0xFBB
#BYTE VREFCON2 = 0xFBC
#BYTE ADCON0 = 0xFC2 // A/D converter config registers
#BYTE ADCON1 = 0xFC1
#BYTE ADCON2 = 0xFC0
#define VSS_VFVR 0x800 // new definition to use internal vref not listed in .h
#BYTE ANSEL = 0xF7E // Analog Select Registers
#BYTE ANSELH = 0xF7F
#BYTE OSCCON = 0xFD3 // Oscillator control register
#BYTE OSCCON2= 0xFD2
.
.
.
setup_adc(ADC_CLOCK_DIV_16);
// Have to enable the internal FVR and set to 1x
VREFCON0 = 0x90; // FVR enabled, 1x (1.024v) (pg 245)
// VREFCON1 = 0x00; // DAC is disabled (pg 246)
// VREFCON2 = 0x00; // DAC output disabled (pg 246)
// ADCON1 = 0x08; // pos vref from FVR, neg vref from Vss (pg 214,207)
// ADCON2 = 0x95; // Rt. justify, TAD4,Fosc/16 (pg 215)
// setup_adc_ports(AIR_PORT | HTR_PORT);
// AN2 (RA2) = ambient temp, AN10 (RA10)=htr temp |
_________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Thu Oct 25, 2012 9:14 am |
|
|
The 1947, does have this ability, but that is why I asked the compiler version. Like many such features, CCS tend to get them 'wrong' for the first few releases. It does appear to set the bits correctly with the current compiler.
Best Wishes |
|
|
omid_juve
Joined: 25 Oct 2012 Posts: 8
|
|
Posted: Thu Oct 25, 2012 1:02 pm |
|
|
Thanks to all of you that help me.
Finally I made it.
See the code below for your ref.
Code: |
#byte fvrcon=0x117
fvrcon=0b10000010;
setup_adc_ports(sAN0|sAN1|sAN2|sAN3|sAN4,VSS_FVR,);
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Fri Oct 26, 2012 4:07 am |
|
|
Also, for _your_ reference, you have never answered the question asked right at the start - 'what compiler version'.
On 4.137, the compiler line:
Code: |
setup_vref(VREF_ON|VREF_ADC_2v048);
|
Generates:
Code: |
0015: MOVLB 01
0016: MOVLW 82
0017: MOVWF 17
|
Which is putting 0x82, into address 117, which is what you are doing....
Best Wishes |
|
|
|