![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
arrow
Joined: 17 May 2005 Posts: 213
|
A/D on 2 (or more) channels problem? |
Posted: Tue Jul 19, 2005 6:55 am |
|
|
Hi
I have the following code snippet which works well:
Code: |
setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
//-------------------------------
while(TRUE){
set_adc_channel( 0 );
value = Read_ADC();
printf("+%x%x ", value>>8, value&0X00FF);
}
|
Now I want to measure 2 A/D channels as follows:
Code: |
setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
// set_adc_channel( 0 );
//-------------------------------
while(TRUE){
set_adc_channel( 0 );
value = Read_ADC();
printf("+%x%x ", value>>8, value&0X00FF);
set_adc_channel( 1 );
value = Read_ADC();
printf("-%x%x ", value>>8, value&0X00FF);
}
|
This does not work; the results printed are similar values, and are both wrong. Can someone please tell me what I am doing wrong?
I am using the 16LF873.
Thank you in advance.
Regards
arrow |
|
![](templates/subSilver/images/spacer.gif) |
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Tue Jul 19, 2005 7:40 am |
|
|
Try adding a delay such as:
Code: | setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
// set_adc_channel( 0 );
//-------------------------------
while(TRUE){
set_adc_channel( 0 );
delay_ms(1);
value = Read_ADC();
printf("+%x%x ", value>>8, value&0X00FF);
set_adc_channel( 1 );
delay_ms(1);
value = Read_ADC();
printf("-%x%x ", value>>8, value&0X00FF);
} |
and see if that fixes the problem. If so then read the datasheet to see just how much delay your A/D takes. It is undoubtedly much shorter than 1 ms.
You may also be able to use the printf as the delay as in:
Code: | setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
// set_adc_channel( 0 );
//-------------------------------
set_adc_channel(0);
delay_ms(1); //Only used once
while(TRUE){
value = Read_ADC();
set_adc_channel( 1 ); //Setup of opposite channel ASAP
printf("+%x%x ", value>>8, value&0X00FF); //This printf takes a while
value = Read_ADC();
set_adc_channel( 0 );
printf("-%x%x ", value>>8, value&0X00FF);
} |
_________________ The search for better is endless. Instead simply find very good and get the job done. |
|
![](templates/subSilver/images/spacer.gif) |
arrow
Joined: 17 May 2005 Posts: 213
|
|
Posted: Tue Jul 19, 2005 8:04 am |
|
|
Hi SherpaDoug
Thank you very much- the delay_ms(1) worked well!!
I have looked at the 16F876 data sheet (I am using the 873) and cant find any mention of this delay. Can you please tell me where I can find more details on the exact delay time I need?
Once again thank you
Regards
arrow |
|
![](templates/subSilver/images/spacer.gif) |
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Tue Jul 19, 2005 8:37 am |
|
|
Read the chapter in the datasheet on the A/D section. It gives parameters such as "Tad", and explains how long things take to make a conversion.
But honestly, it's all cryptic to me. I simply add a few ms delay after changing channels, and I stay away from the manual after that. ![Laughing](images/smiles/icon_lol.gif) |
|
![](templates/subSilver/images/spacer.gif) |
arrow
Joined: 17 May 2005 Posts: 213
|
|
Posted: Tue Jul 19, 2005 9:11 am |
|
|
Hi
Yes, I see Tad and Tacq. It gives me a value for Tacq, but not for Tad, are these the same?
Thank you, and
Regards
arrow |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Tue Jul 19, 2005 9:33 am |
|
|
Tacq, is the one you need.
Tad, is the cycle time of the AD clock, The actual 'sample', takes 12 cycles of this. The read_adc routine waits for this time internally.
Basically, before this, when you switch channels, you have to wait for the internal capacitor to charge within 1/2 bit value, of the incoming voltage. The time to do this depends on the source impedance, the internal impedances, and the value of the capacitor. This 'total', is Tacq.
Then to actually take a reading, you start the successive approximation A/D, which takes one cycle of it's clock/bit, plus two 'extras'. Tad, mus not be less than 1.6uSec, if the chip is to give it's specified accuracy. So the minimum time to change to, then sample a new channel, is Tacq+12*Tad, but because read_adc, automatically waits for the 12*Tad period, it is only the 'acquisition' time you have to wait for.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: A/D on 2 (or more) channels problem? |
Posted: Tue Jul 19, 2005 9:35 am |
|
|
Code: |
setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
// set_adc_channel( 0 );
//-------------------------------
while(TRUE){
set_adc_channel( 0 );
value = Read_ADC();
value = Read_ADC();
printf("+%x%x ", value>>8, value&0X00FF);
set_adc_channel( 1 );
value = Read_ADC();
value = Read_ADC();
printf("-%x%x ", value>>8, value&0X00FF);
}
|
The required delay is usually about the same as the time to read an input. So you can simply read it twice. This is in my opinion better than a delay code that waits a fixed number of instruction cycles and its smaller code wise. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
Re: A/D on 2 (or more) channels problem? |
Posted: Tue Jul 19, 2005 9:56 am |
|
|
Neutone wrote: | Code: |
setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
// set_adc_channel( 0 );
//-------------------------------
while(TRUE){
set_adc_channel( 0 );
value = Read_ADC();
value = Read_ADC();
printf("+%x%x ", value>>8, value&0X00FF);
set_adc_channel( 1 );
value = Read_ADC();
value = Read_ADC();
printf("-%x%x ", value>>8, value&0X00FF);
}
|
The required delay is usually about the same as the time to read an input. So you can simply read it twice. This is in my opinion better than a delay code that waits a fixed number of instruction cycles and its smaller code wise. |
This is _not_ a good solution.
The holding capacitor is _disconnected_ from the input pin, when an AD reading is made (this is in the data sheet...). The total connected time in the example given, is _not_ enough to ensure reliable charging.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Tue Jul 19, 2005 11:34 am |
|
|
I think this is the best solution. Set up the A/D channel for the next channel as soon as you have read the old channel. You only need an explicit delay the first time. After that the A/D capacitance charges during the serial printf.
Code: |
setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
//-------------------------------
set_adc_channel(0);
delay_ms(1); //Only used once
while(TRUE){
value = Read_ADC();
set_adc_channel( 1 ); //Setup of opposite channel ASAP
printf("+%x%x ", value>>8, value&0X00FF); //This printf takes a while - plenty of time for A/D to acquire the new signal.
value = Read_ADC();
set_adc_channel( 0 );
printf("-%x%x ", value>>8, value&0X00FF);
} |
_________________ The search for better is endless. Instead simply find very good and get the job done. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Tue Jul 19, 2005 2:51 pm |
|
|
Yes.
Using time doing something else, is a very good way of dealing with this.
It is worth also adding that if dealing with multiple channels, and sampling in an interrupt, the same sort of approach can be used, and improved by taking advantage of the ability of 'read_adc', to not wait for the conversion.
So, in the interrupt you use something like:
Code: |
int16 results[4];
//have as many numbers as results needed.
void int_timerx(void) {
static int8 state=2;
//Start with the channel selection
static int8 channel=0;
switch (state++) {
case 0 :
//Start the ADC only
read_adc(ADC_START_ONLY);
break;
case 1:
//On the next loop, take a reading
results[channel]=read_adc(ADC_READ_ONLY);
break;
case 2:
//Advance to the next channel
channel=(channel<3)?channel+1:0;
//Select the channel
set_adc_channel(channel);
state=0;
break;
}
}
|
Then provided the interrupt time interval, is longer than both the Tacq time, and 12*Tad, the routine will sequentially advance to the next channel, select it, start the ADC conversion, and take a reading, but not 'wait' in any loop. At any time, the values in 'results[0]...[3]', can be read and reflect the voltages on the pins.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
arrow
Joined: 17 May 2005 Posts: 213
|
|
Posted: Wed Jul 20, 2005 1:30 am |
|
|
Hi All
Thank you for replying.
I have implemented the following, and it works pretty well:
Code: |
setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
//-------------------------------
while(TRUE){
set_adc_channel( 0 );
delay_us(40);
value0 = Read_ADC();
set_adc_channel( 1 );
delay_us(40);
value1 = Read_ADC();
printf("+%x%x -%x%x ", value0>>8, value0&0X00FF,value1>>8, value1&0X00FF);
}
|
What I find is that it gives me approximatley 176samples/second/ channel.
Surely printf at 19200 baud rate should give me 200samples/second/channel?
The printf statement has 12bytes (?) in it, @ 19200baud rate gives 200 (?)
Please can you tell me what I am doing wrong, and how I can increaes the spped of the data a/d- with printg?
Thank you once again
Regards
arrow |
|
![](templates/subSilver/images/spacer.gif) |
arrow
Joined: 17 May 2005 Posts: 213
|
|
Posted: Wed Jul 20, 2005 1:30 am |
|
|
Hi All
Thank you for replying.
I have implemented the following, and it works pretty well:
Code: |
setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
//-------------------------------
while(TRUE){
set_adc_channel( 0 );
delay_us(40);
value0 = Read_ADC();
set_adc_channel( 1 );
delay_us(40);
value1 = Read_ADC();
printf("+%x%x -%x%x ", value0>>8, value0&0X00FF,value1>>8, value1&0X00FF);
}
|
What I find is that it gives me approximatley 176samples/second/ channel.
Surely printf at 19200 baud rate should give me 200samples/second/channel?
The printf statement has 12bytes (?) in it, @ 19200baud rate gives 200 (?)
Please can you tell me what I am doing wrong, and how I can increaes the spped of the data a/d- with printg?
Thank you once again
Regards
arrow |
|
![](templates/subSilver/images/spacer.gif) |
arrow
Joined: 17 May 2005 Posts: 213
|
|
Posted: Wed Jul 20, 2005 1:31 am |
|
|
Hi All
Thank you for replying.
I have implemented the following, and it works pretty well:
Code: |
setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
//-------------------------------
while(TRUE){
set_adc_channel( 0 );
delay_us(40);
value0 = Read_ADC();
set_adc_channel( 1 );
delay_us(40);
value1 = Read_ADC();
printf("+%x%x -%x%x ", value0>>8, value0&0X00FF,value1>>8, value1&0X00FF);
}
|
What I find is that it gives me approximatley 176samples/second/ channel.
Surely printf at 19200 baud rate should give me 200samples/second/channel?
The printf statement has 12bytes (?) in it, @ 19200baud rate gives 200 (?)
Please can you tell me what I am doing wrong, and how I can increaes the spped of the data a/d- with printg?
Thank you once again
Regards
arrow |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Wed Jul 20, 2005 4:18 am |
|
|
Print less...
You are almost hitting the max. Remember a 'byte' of data, when printed on the serial, has two extra bits added (start and stop bits). Assuming you are using 7bit printing, this gives 9bits/character, which at 19200bps, gives (for your 12 bytes):
19200/(9*12).
This is 177.7 printouts/second maximum. You appear to just about be achieving this.
Now you don't need to fiddle around splitting the bytes up yourself, and given the value is only ten bits, it is pointless to print the entire 16bits. So:
printf("+%3Lx ",value);
is both simpler to code, and will just print the three nibbles, saving one byte.
Also, why print the 'space'. Since you are already appending a '-' and a '+' to identify the gaps between the data, this is just another wasted character.
If you cut it down this way to just eight printed characters, your output rate will rise to 266 samples/second.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|