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 sampling

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



Joined: 15 Apr 2009
Posts: 4

View user's profile Send private message

A/D sampling
PostPosted: Thu May 28, 2009 7:17 am     Reply with quote

Hello guys.
I'm confronting with a problem. I'm trying to control a servo-motor. I need in order to move the servo, 128 samples of A/D conversion continuously, one sample of A/D per ms. I need the values of the 128 samples for calculating standard deviation, after that another 128 samples and so on. For the initialization I use this:
Code:
void main()
{
//A/D configuration
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
delay_ms(200);

//TIMER2 configuration
set_timer_2(0);
setup_timer_2(T2_DIV_BY_4, 125, 10);     //interrupts at 1 ms
}

How can I use the code inside #INT_TIMER2 in order to make it repeat 128 times and not loose the values of A/D conversion in order to calculate the standard deviation.
I thought about using the #INT_AD, which interrupts when the conversion is over, but I'm not sure about the time that it's used, or whether will work as I want.
I need continuously sampled 128 values, one value per second.

I will appreciate any idea.
Thanks in advance.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu May 28, 2009 1:32 pm     Reply with quote

Declare a global int8 variable. Initialize it to 0 in main(), before you
enable Timer2 interrupts. This variable will be an index into a global
array and will also be your interrupt event counter.

Every time you get a Timer2 interrupt, do the following:
1. Read the A/D and write the result to a global array (which holds 128
elements), at the current index location.
2. Increment the index variable.
3. If the index == 128, then set a global flag to indicate to your main()
code that 128 values have been captured.
4. Reset the index to 0.

Possibly you should also add the means to disable the capturing of
more values while you are processing the current 128 values. You
could do this by disabling Timer2 interrupts, or by looking at a flag
in the Timer2 isr (which could be the index).

Quote:
setup_timer_2(T2_DIV_BY_4, 125, 10); //interrupts at 1 ms

I need continuously sampled 128 values, one value per second.

Can you clarify the sample rate ? Is it 1 per second or 1 per ms ?

If you really want to sample at a rate of 1 per second, then you'll need
a static int16 variable inside the Timer2 isr to count 1000 interrupts.
Then read the A/D when the count reaches that point, and reset the
count to 0. Initialize the static int16 variable to 0 in the declaration.
SherpaDoug



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

View user's profile Send private message

PostPosted: Thu May 28, 2009 3:55 pm     Reply with quote

I don't think you have to actually store all 128 samples to calculate the STD. I think there is a formula that uses the number of samples, the sum of the samples, and the sum of their squares. Just update the count and the two sums as you go. That is how a pocket calculator that only has a few dozen registers can find the STD of a list of a hundred values.
_________________
The search for better is endless. Instead simply find very good and get the job done.
sisif85



Joined: 15 Apr 2009
Posts: 4

View user's profile Send private message

PostPosted: Fri May 29, 2009 2:25 am     Reply with quote

Hey guys.
When I set up the TIMER2 I was meaning to 1 sample of A/D per millisecond.

Thanks for your prompt answers.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri May 29, 2009 2:34 am     Reply with quote

I would prefer a streaming Std calculation as mentioned by SherpaDoug and extend it to 1000 samples to get a true representative 1 sec. value. The calculation involves two accumulators for ADC-value and squared ADC-value and a sample counter. The accumulators must have 32 bit width, for 128 or 1000 samples either. The Std final calculation time may possibly exceed 1 ms, so it's meaningful to do the 1 ms action on a interrupt base.
sisif85



Joined: 15 Apr 2009
Posts: 4

View user's profile Send private message

PostPosted: Fri May 29, 2009 4:13 am     Reply with quote

Hey.

I made a program after PCM Programmer's algorithm. Here is the program:
Code:

#include <16F876.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use fast_io(A)
//#device ADC=10

int8 index;
int1 flag;
int8 nrSamples, vector[128];
int32 standard_value;   //for servo

#INT_TIMER2
void timer2_isr()
{
long adc_sample;

adc_sample=read_adc();
vector[index]=adc_sample;
index=index+1;

if (index==128)
   {
   flag=1;
   index=0;
   }
}

void main()
{

setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
delay_ms(200);

set_timer2(0);
setup_timer_2(T2_DIV_BY_4, 125, 10);     //1 ms

index=0;
flag=0;
int8 i;
int32 modul;
float32 mean,sum,deviation;

enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER2);

if (flag==1)
   {
   disable_interrupts(INT_TIMER2);
   for (i=1;i<=128;i++)
       {
           sum=sum+vector[i];
       }
   mean=suma/nrSamples;
   for (i=1;i<=128;i++)
       {
      modul=mfabs(x[i]-mean);
           deviation=modul+deviation;
       }
   deviation=deviation/nrSamples;
   deviation=sqrt(deviation);
   
        if (deviation>standard_value)   set_servo(forward);
      else                    set_servo(backward);
   }
}

I wold like to know if I handled well with the globals and the algorithm correct in practice.

For FvM: when you refered to streaming did you mean that I should do inside the #int_timer2 the calculations? For example:
Code:
#int_timer2
void isr_timer2()
{
int counter;
int32 accumulator;
value=read_adc();
accumulator1=accumulator1+value;
++counter;
if (counter==128) 
    {
         if (accumulator > x)    // move_servo
   }
}
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri May 29, 2009 4:32 am     Reply with quote

From your previous posts, I didn't understand, that you intended to move the servo only each 128 ms, based on the averaged measurements. This changes a lot.
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