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

Read analog sensors in the background?

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



Joined: 07 Nov 2008
Posts: 4

View user's profile Send private message

Read analog sensors in the background?
PostPosted: Thu Sep 03, 2009 3:42 am     Reply with quote

Hallo,

I want to read 6 analog sensors and update their accosiated globals. I tried using int_ad with the next a/d conversion started at the end of the ad_isr, but this kept my program almost exclusively in the ad_isr leaving very little time for main() and other routines.

I'm using a PIC18F4620 with 20MHz crystal. I use setup_adc_ports (AN0_TO_AN7|VSS_VDD) with setup_adc(ADC_CLOCK_DIV_32). I am already using int_rda, int_ext1, int_rb and timer0(20ms timebase), timer2(pwm) and timer3(software pwm).

I want to update the analog readings so that my main() and other routines can use the most current readings without having to query and wait for the a/d convertion to finish.

What is a good strategy for doing this? Please point me in an efficient direction.

Thanks for the guidance!

Regards,
Madri
Ttelmah
Guest







PostPosted: Thu Sep 03, 2009 4:59 am     Reply with quote

Have a timer 'tick' interrupt. Interval to suit you, but typically perhaps about 50 to 100Hz.
Then have this use a state machine, something like:
Code:

int16 ad_readings[4]; //Have enough entries for the channel numbers in
//'chans' below.

#INT_TIMERx
void tick(void) {
   static int8 state=0;
   static int8 channel=0;
   const int8 chans[] = {0,1,4,6,255}; //put channel numbers you want
   //to read here, terminated by '255'.

   switch (state) {
   case 0:
       //First select the channel required
       set_adc_channel(chans[channel]);
       state++;
       break;
   case 1:
       //One 'tick' later, start the ADC
       read_adc(ADC_START_ONLY);
       state++;
       break;
   case 2:
       //One tick later, read the adc
       ad_readings[channel]=read_ADC(ADC_READ_ONLY);
       state++;
       break;
   case 3:
       //One tick later, tidy up
       if (chans[++channel]==255) {
            channel=0; //restart the channel scan
       }
       state=0;
       break;
   }
}

Each 'tick', is quite quick (slowest thing is the array accesses), doing just one job, on the selected channels. It works through a 'list' of ADC channel numbers (in the example, 0,1,4,6), first selecting the channel, then returnng to the main code, while the capacitor in the chip charges, then triggering sampling, and returning while this is done, then reading the channel and storing it in the array, and finally selecting the next required channel.

Beest Wishes
Guest








PostPosted: Thu Sep 03, 2009 7:24 am     Reply with quote

Thank Ttelmah for the quick reply - and the code too! This is fantastic - just what I was hoping to be able to do and not able to get my mind around how to go about it.

It works great!

Thank you so much for this - made my day for sure. Maybe even week.
Madri
asmboy



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

View user's profile Send private message AIM Address

PostPosted: Thu Sep 03, 2009 8:20 am     Reply with quote

i have been doing almost the identical thing for over a year with a four analog channel rotation, but using just 2 states :


state ZERO, TWO and THREE can be combined very efficiently
by the sequence:

STATE: 0
Start ADC CHAN
state =!state;

STATE:1
1- READ_ADC,
2- adjust chan number glo var ,
3- set next ADC_CHAN ( for acquisition time) -
state =!state;


then the reading is STARTED on the next tick,
the OTHER state of the machine )


there are only two time consuming things being done ( for good reading accuracy) and they are (1) settling time - which occurs after the chan is switched "set adc chan" and (2) conversion time "start adc conv"

this 2 state machine allocates ( equal enough ) time to each

the reason to go this way ?

Your acq rate is doubled over ttelmahs nice example and
the extra time lingering in the ISR is diddly , since other than ADC START and the ACQ time delay after chan set - all instrux are wholly deterministic.

this pretty evenly splits ACQ time and AD/CONVERT time between alternating 'ticks'

you do need to INIT the process vars of course before first call

in my implementation i actually use a rolling average integrator that sums 4 sets of readings on each of four channels and updates the running average every 16 tix - of 8.19ms , on an ~20 mhz system but that is another story
Ttelmah
Guest







PostPosted: Thu Sep 03, 2009 9:10 am     Reply with quote

Yes. In fact my normal one does the 'select next channel', immediately after reading the value, reducing the states by one. I have posted versions of this in the past.
However I normally keep one more state than the minimum, since I typically perform some averaging functionality, and prefer to perform the maths in an extra state. You can keep the arithmetic very fast, if you only perform integer addition, and integer division by a binary factor (2,4,8), using the >> function, avoiding maths re-entancy problems, and still keeping the ticks fast. Smile

It is worth also realising, that if you have the tick at some nice division of a second, using perhaps timer2, you can also do a lot of your basic system timings, with something like:
Code:

int16 time_to_wait;

    //Then in the interrupt
    static int8 ticker;
    if (ticker) --ticker;
    else {
       ticker=TICKS_PER_SECOND;
       if (time_to_wait) --time_to_wait;
    }


Then in your main code, if you want to wait for 30 seconds, you just set 'time_to_wait' to 30, and can perform other jobs, till it gets to zero.

The 'nice' thing is that the work per tick is tiny (for 99% - on a 100Hz ticker), just a single byte test, and decrement. On the 100th loop, just a 16bit test, decrement and a load. Also, you cannot 'miss' the end, since one the [spam] reaches '0', it'll stay there till re-loaded.

Using a system 'tick', is a very useful general tool.

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