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 support@ccsinfo.com

A/D on 2 (or more) channels problem?

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



Joined: 17 May 2005
Posts: 213

View user's profile Send private message

A/D on 2 (or more) channels problem?
PostPosted: Tue Jul 19, 2005 6:55 am     Reply with quote

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
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Tue Jul 19, 2005 7:40 am     Reply with quote

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.
arrow



Joined: 17 May 2005
Posts: 213

View user's profile Send private message

PostPosted: Tue Jul 19, 2005 8:04 am     Reply with quote

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
MikeValencia



Joined: 04 Aug 2004
Posts: 238
Location: Chicago

View user's profile Send private message Send e-mail Yahoo Messenger

PostPosted: Tue Jul 19, 2005 8:37 am     Reply with quote

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
arrow



Joined: 17 May 2005
Posts: 213

View user's profile Send private message

PostPosted: Tue Jul 19, 2005 9:11 am     Reply with quote

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
Ttelmah
Guest







PostPosted: Tue Jul 19, 2005 9:33 am     Reply with quote

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
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Re: A/D on 2 (or more) channels problem?
PostPosted: Tue Jul 19, 2005 9:35 am     Reply with quote

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.
Ttelmah
Guest







Re: A/D on 2 (or more) channels problem?
PostPosted: Tue Jul 19, 2005 9:56 am     Reply with quote

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
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Tue Jul 19, 2005 11:34 am     Reply with quote

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.
Ttelmah
Guest







PostPosted: Tue Jul 19, 2005 2:51 pm     Reply with quote

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
arrow



Joined: 17 May 2005
Posts: 213

View user's profile Send private message

PostPosted: Wed Jul 20, 2005 1:30 am     Reply with quote

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
arrow



Joined: 17 May 2005
Posts: 213

View user's profile Send private message

PostPosted: Wed Jul 20, 2005 1:30 am     Reply with quote

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
arrow



Joined: 17 May 2005
Posts: 213

View user's profile Send private message

PostPosted: Wed Jul 20, 2005 1:31 am     Reply with quote

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
Ttelmah
Guest







PostPosted: Wed Jul 20, 2005 4:18 am     Reply with quote

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