|
|
View previous topic :: View next topic |
Author |
Message |
weg22
Joined: 08 Jul 2005 Posts: 91
|
Help reading in analog signal |
Posted: Wed Nov 15, 2006 10:00 am |
|
|
Hi all,
I'm reading an analog signal from a Sharp IR sensor (GP2Y0A02YK) into my PIC18F8722. I have a few questions I was hoping someone could answer:
1. The values I get back from the sensor range from about 700-840 depending on distance. However, once in a while I will get a value of 1023. I'm wondering is this a problem with my code (i.e. I'm reading the values too fast) or is it just something to expect from the sensor (see code below). I'm hoping it's software, but if not I can always just feed it through a low-pass filter.
2. Is there anyway to expand this range...from 0-800 for example.
3. It seems like setting up the adc during each iteration of the while loop is not efficient. However, if I take the setup_adc_ports, setup_adc, and set_adc_channel commands outside the loop, it doesn't work. Do I need to keep these inside the while loop?
Thanks in advance,
-weg
Code: |
#include <18F8722.h>
#device adc=10
#include <stdlib.h>
#include <math.h>
#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_A4, rcv=PIN_A5, stream=PC)
#define LED PIN_F0
main()
{
long value=0;
output_high(LED);
while(1)
{
// setup to do A/D conversion on AN5
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
delay_us(20);
value = read_adc();
setup_adc(ADC_OFF);
fprintf(PC, "%ld\r\n", value);
}
} // end of main
|
|
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Wed Nov 15, 2006 10:26 am |
|
|
You're right - you're reading the A/D too fast. Whether that will give you a value of 1023 or not, I don't know. Since you are seeing 1023 sometimes, I guess so.
When it comes to using the PIC's internal A/D, I like to use it a little differently. There is an interrupt, INT_AD, that fires when the A/D converter is done doing a conversion. I use a timer to trigger an A/D conversion at a steady, repeatable rate and when the conversion is finished, the AD interrupt lets me know it's finished. It is then safe to read the result of the A/D conversion.
That aside, your code should work just fine if you change your loop delay from 20 us to 1 ms. Also move the setup code OUT of the while loop. That stuff only needs to execute once, not continually. Also get rid of the line disabling the A/D - not needed, and may be the source of some of your troubles.
Once you make these minor changes, see what kind of readings you get from the sensor. I've used similar sensors, and they output voltages down to almost 0V, so your lower bound of 700 is suspect. |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 15, 2006 10:31 am |
|
|
You certainly should not need to setup the ADC on each loop.
Code: |
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
while(1) {
value = read_adc();
fprintf(PC, "%ld\r\n", value);
}
|
Should work fine.
Realistically, you are going to need an external amplifier for the signal. An op-amp, set to subtract the voltage corresponding to about 700 counts, and then give *5 gain, will give you a much more worthwhile reading. You could potentially expand the range a little, by rising the VrefL pin of the PIC, but the range you have is small enough, that you are not going to get full accuracy from the PIC's ADC.
Best Wishes |
|
|
weg22
Joined: 08 Jul 2005 Posts: 91
|
|
Posted: Wed Nov 15, 2006 12:26 pm |
|
|
I tried both suggestions and neither of them seem to work...although I believe both should since my code above works?? The first listing of code (below) just moves the analog setup commands outside the while loop and all I'm getting are max values (i.e. 1023). The second listing of code attempts A/D with the interrupt, but the interrupt is never triggered (i.e. LED never lights) so I just get a value of 0. Any suggestions would be appreciated.
Code: |
#include <18F8722.h>
#device adc=10
#include <stdlib.h>
#include <math.h>
#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_A4, rcv=PIN_A5, stream=PC)
#define LED PIN_F0
main()
{
long value=0;
// setup to do A/D conversion on AN5
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
output_high(LED);
while(1)
{
delay_ms(1);
value = read_adc();
fprintf(PC, "%ld\r\n", value);
}
} // end of main
|
Code: |
#include <18F8722.h>
#device adc=10
#include <stdlib.h>
#include <math.h>
#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_A4, rcv=PIN_A5, stream=PC)
#define LED PIN_F0
long value=0;
#INT_AD
void adc_isr()
{
value = read_adc();
output_high(LED);
}
main()
{
// setup to do A/D conversion on AN5
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
while(1)
{
fprintf(PC, "%ld\r\n", value);
}
} // end of main
|
|
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Wed Nov 15, 2006 12:33 pm |
|
|
Forget the interrupt for now - you have to manually trigger the A/D to start a conversion, and that's why it isn't working.
I notice that in your setup_adc_ports() function that you have AN0 as the only argument. You should have:
Code: | setup_adc_ports(AN0|VSS_VDD); |
If you omit the VSS_VDD, I'm not sure what default state the A/D uses for its voltage limits. Make this small change and see if that helps.
Before I forget, also try this:
Code: | setup_adc(ADC_CLOCK_DIV_64|ADC_TAD_MUL_0); |
The A/D will give strange results if the clock feeding it is too fast. This will slow it down. |
|
|
weg22
Joined: 08 Jul 2005 Posts: 91
|
|
Posted: Wed Nov 15, 2006 12:59 pm |
|
|
Still the same result. I don't know what can be going wrong? How can it work with the adc setup commands inside the while loop, but not outside? |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 15, 2006 1:49 pm |
|
|
You are using A4, as the serial transmit output, yet this pin is an open collector (pull down only) output. Has this got a pull-up resistor?. If not, the serial is 'dubious'.
Vss-Vdd for the reference, is the default. The value 'ored' in to enable this, is zero.
It is almost never worth trying to use interrupts with the ADC. The time needed to enter the interrupt, is as long as the conversion takes. You still have to trigger the conversion. The only time this is worth doing, is when the conversion is being triggered off an external source using the CTC for example.
The only thing I'd suspect, is a lack of supply decoupling, and the contents of the registers are getting corrupted when you do the serial I/O. I think you have a hardware problem like this...
Best Wishes |
|
|
weg22
Joined: 08 Jul 2005 Posts: 91
|
|
Posted: Wed Nov 15, 2006 2:04 pm |
|
|
I removed the rs232 statement and used the LED to tell me if the value is above or below a threshold...and still the same result. It doesn't work if take the adc setup statements outside the while loop. I'm stumped.
On a side note, I checked the voltage range with a multimeter and it looks like it goes from 0.6-1.2 volts. Pretty small to get any kind of resolution with the PIC I guess. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
weg22
Joined: 08 Jul 2005 Posts: 91
|
|
Posted: Wed Nov 15, 2006 2:51 pm |
|
|
I'm familiar with the sensor, in particular it's nonlinearities. This I can deal with as I don't need an accurate distance reading. I can just use the digital value of the voltage. The voltage range I'm getting is actually 0.5-2.8 volts as spec'd out in the sensor's datasheet. If this is the case, then I should be seeing a digital value range of 102 to 573 if I'm using a 10-bit number and 26-143 if I'm using an 8-bit number, right?
voltage*(255/5) = digital value // 8-bit
voltage*(1023/5) = digital value // 10-bit
I'm definitely not seeing this range...so I guess my A/D isn't working correctly even inside the while loop. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Thu Nov 16, 2006 7:34 am |
|
|
Quote: |
I checked the voltage range with a multimeter and it looks like it goes
from 0.6-1.2 volts. Pretty small to get any kind of resolution with the
PIC I guess. |
The range of the sensor is 0.6V which is about 1/8 of the A/D range of 5V. 1/8 scale means you lose 3 bits. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Nov 16, 2006 7:34 am |
|
|
The only real difference between your first code and RJ's is the setup_adc(ADC_OFF) command. You shouldn't need it but try this out:
Code: | #include <18F8722.h>
#device adc=10
#include <stdlib.h>
#include <math.h>
#fuses HS,NOWDT,NOPROTECT,PUT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_A4, rcv=PIN_A5, stream=PC)
#define LED PIN_F0
main()
{
long value=0;
// setup to do A/D conversion on AN5
setup_adc(ADC_OFF);
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
output_high(LED);
while(1)
{
delay_ms(1);
value = read_adc();
fprintf(PC, "%ld\r\n", value);
}
} // end of main
|
|
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 16, 2006 8:22 am |
|
|
The 'ADC_OFF' call, is why he needs to have the setup in the loop. Once the ADC is switched off, it is the 'setup_adc' command, with a clock value, which turns it back on.
I have just tried just about all the code versions, and most work. Seriously, two suggestions still exist. First, there is a hardware problem, and the second, is the question 'what compiler version'. In the past, there have been compiler versions that incorrectly initialise some peripherals, and though I cannot think of a misconfiguration that wuld behave like this, it should be checked.
The other question, regarding the value being returned, is 'what is the output impedance of the device'?. The PIC ADC, requires a fairly low impedance drive, to give reasonable values. Sharp give no figure for this parameter. If the impedance is above about 2.5KR, then a buffer amplifier is needed, and might as well be used to give better use of the ADC range as well. For instance, if the signal was multiplied *4, and VrefL, fed from 2v, then the signal would be 2.4 to 4.8v, and the PIC would read this as 136 to 956.
Best Wishes |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Nov 16, 2006 8:25 am |
|
|
My point is that if we believe that his original code works (most of the time) then he should get the same results with the code that you posted. I suggested the adding setup_adc(ADC_OFF) in case the compiler was not setting something up correctly and this made it work. It is really the only difference. |
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 16, 2006 8:31 am |
|
|
Yes.
The other 'glaring' difference though, is that he keps re-initialising the ADC, after performing the printf, or LED toggle which then raises back the possibility that this is a supply decoupling issue. There have been quite a few people with 'inexplicable oddities', where it turned out the supply rail was noisy. On the 8722, there are a total of ten power pins (5*Vss, and 5*Vdd), that must all be connected, and properly decoupled, or this sort of problem can appear. Something silly, like Avss not connected, can give exactly this type of behaviour.
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
|