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 CCS Technical Support

4 Adc channels??

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



Joined: 01 Apr 2011
Posts: 17

View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger

4 Adc channels??
PostPosted: Fri Jan 13, 2012 12:50 pm     Reply with quote

Hello !!
I would like to know a method that makes the pic read 4 adc values , evry 2ms it reads from a chennel , for example for 2 channels we can use this:
Code:

int a=0,val,va2;
Timer2 (2ms)
if (a%2)
{
set_adc_channel(0);
delay_us(16);
val=read_adc();
a=a+1;
}
else {
set_adc_channel(1);
delay_us(16);
val2=read_adc();
a=a+1;
}

THNX
_________________
REPTILE404

55AA55AA55


Last edited by reptile404 on Fri Jan 13, 2012 2:35 pm; edited 2 times in total
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri Jan 13, 2012 1:58 pm     Reply with quote

what you show is NOT simultaneous - as the sampling periods occur at different times. i know of no way using THE PIC ALONE to do what you ask for. the PIC hardware is not structured to be able to do that.
reptile404



Joined: 01 Apr 2011
Posts: 17

View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger

PostPosted: Fri Jan 13, 2012 2:27 pm     Reply with quote

Yes, I know that its impossible but I meant a method like I gave but reads 4 channels without using delay function (ofc not 16us).
_________________
REPTILE404

55AA55AA55
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri Jan 13, 2012 2:49 pm     Reply with quote

Code:

unsigned int16 val[4]={0,0,0,0};

// later

unsigned int8 i;

for (i=0; i<4;i++){
   set_adc_channel(i);
   val[i]=read_adc();
}
 


done in minimum time
can you see how to adapt the "ALL read"
i just showed to one after another ;-))
SherpaDoug



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

View user's profile Send private message

PostPosted: Fri Jan 13, 2012 3:25 pm     Reply with quote

To get any accuracy if the 4 inputs are at differing voltages you will need a delay between the channel selection and ADC reading:
Code:
unsigned int16 val[4]={0,0,0,0};

// later

unsigned int8 i;

for (i=0; i<4;i++){
   set_adc_channel(i);
   delay_us(16);
   val[i]=read_adc();
}

_________________
The search for better is endless. Instead simply find very good and get the job done.
reptile404



Joined: 01 Apr 2011
Posts: 17

View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger

PostPosted: Sat Jan 14, 2012 3:32 am     Reply with quote

Thnx Guys ! But I didn't mean to use a loop (for). I just want to know a mathematical method. For example, I used (%) for two channels, using timers interruptions. For example, it reads from a channel every 2ms(overflow) loop, its not optimal.
thnks
_________________
REPTILE404

55AA55AA55
reptile404



Joined: 01 Apr 2011
Posts: 17

View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger

PostPosted: Sat Jan 14, 2012 3:40 am     Reply with quote

Is it possible in ccs to know rest of division (a%4) ?
If a=5, so result is 1 and rest is 1.
_________________
REPTILE404

55AA55AA55
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Sat Jan 14, 2012 4:06 am     Reply with quote

OK. I think I get what you are asking. Details will depend on your chip, clock etc., but something like:
Code:

int16 adc_vals[4]; //Storage for results
enum adc_states {SELECT, START, MATHS};
#define MAX_CHAN (4)

#int_timer2
void tick_handler(void) {
   static enum adc_states state=SELECT;
   static int8 chan_num=0;
   static int16 sums[4], tempint;
   switch (state) {
   case SELECT:
      if (++chan_num)==MAX_CHAN) chan_num=0; //0...3 output
      set_adc_channel(chan_num); //select next channel
      state++;
      break;
   case START:
      read_adc(ADC_START_ONLY); //start the adc, and exit immediately
      state++;
      break;
   case MATHS:
      sums[chan_num]+=read_adc(ADC_READ_ONLY); //get the reading
      tempint=sums[chan_num]<<2; //generate the average (/4)
      sums[chan_num]-=tempint; //update the sum
      adc_vals[chan_num]=tempint; //store result
      state=SELECT;
      break;
   }
}

All you do is setup timer2, to tick at (say) 100Hz, and enable the interrupts. Then the code first selects the next adc channel and exit's.
On the next interrupt (so allowing plenty of time for the ADC to acquire), it starts the acquisition (which now carries on between the interrupts).
On the next interrupt, it takes the reading, and performs a rolling average. This last interrupt takes the longest, mainly because of performing four array accesses, but still only perhaps 60 instructions. Obviously without averaging, the work is much simpler - up to you whether this is needed.

At any time in the main code you can get the current reading by just looking at the values in 'adc_vals'. Only 'caveat' here is that since these are 16bit values, you should either disable interrupts for a couple of cycles while you read the value, or test that the value you get matches what is in the array. So:
Code:

int16 get_adc_val(int8 n) {
    int16 local_temp;
   
    do {
       local_temp=adc_vals[n];
    } while (local_temp!=adc_vals[n]);
    return(local_temp);
}
//OR
int16 get_adc_val(int8 n) {
    int16 local_temp;
    disable_interrupts(GLOBAL);
    local_temp=adc_vals[n];
    enable_interrupts(GLOBAL);
    return(local_temp);
}


Either version makes sure you get the value avoiding problems with 'half' the value being updated between the two reads. In the first case, if the value changes between the read and the test, then an update occurred
on one of them, so 'try again', while in the second, the interrupts are disabled just for the array access.

You can actually shorten the code, combining the 'select' with the end of the 'maths' phases, so a reading is taken every other interrupt, instead of every third interrupt. However if you do, you need to perform the first 'select' in the main code before the interrupt is enabled, and give long enough for acquisition to occur before starting the interrupt.

As it stands, it'll take a total of 12 interrupts for all the values to update, but at any time you can just read the array and get the last updated value..

Best Wishes
SherpaDoug



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

View user's profile Send private message

PostPosted: Sat Jan 14, 2012 9:50 pm     Reply with quote

reptile404 wrote:
Is it possible in ccs to know rest of division (a%4) ?
If a=5, so result is 1 and rest is 1.


Is this what you are looking for?

a = 5
a/4 = 1
a%4 = 1

a=6
a/4 = 1
a%4 = 2

a=24
a/4 = 6
a%4 = 0
_________________
The search for better is endless. Instead simply find very good and get the job done.
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Sun Jan 15, 2012 2:42 am     Reply with quote

Look at the div operator.
This returns both quotient and remainder. So:
Code:

#include <stdlib.h>
div_t idiv;

idiv=div(6,4);
//Then idiv.quot will be '1'  - the integer division result and
//idiv.rem will be '2' - the remainder

Saves having to do both division and modulus when you want both parts. Changed it to '6', rather than '5', so that the two results are different, so you can see what is going on. Smile

Best Wishes
reptile404



Joined: 01 Apr 2011
Posts: 17

View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger

PostPosted: Sun Jan 15, 2012 10:40 am     Reply with quote

Thanks Mr.Ttelmah
i think its what i was looking for , i just need to know the remainder cauz i will do division on 4 and remainder values will be (0,1,2,3) whatever variable A is , then rem=0 => set_adc_channel(0);
rem=1=> set_adc_channel(1);
.
.
rem=3=> set_adc_channel(3);

as you said idiv.rem will return the remainder
_________________
REPTILE404

55AA55AA55
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Sun Jan 15, 2012 10:56 am     Reply with quote

Seriously, look at how I do the channel select maths in the example I posted:
Code:

  if (++chan_num)==MAX_CHAN) chan_num=0; //0...3 output

With 'MAX_CHAN' set to 5,
chan_num will then count, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4 etc..

This takes about four machine instructions, whereas using a division or modulus takes possibly about 100.....

Rather a large difference.

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