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

How Do i Increase Resolution with CCP Capture?

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



Joined: 24 Oct 2004
Posts: 21
Location: italy

View user's profile Send private message

How Do i Increase Resolution with CCP Capture?
PostPosted: Sun Nov 14, 2004 2:29 am     Reply with quote

hello

and excuse me for the insistence but i'm a beginner and i don't understand very well all about timers...(i'm working with pics only since september)

i am using Pic16C745 capture mode to measure a frequency with varies from 1Khz to 15Khz.


initially i have used this code


/--------------------------------------------------------------------------
// CCP1 Data
//
int16 CCP1Value;
int16 CCP1OldValue;
BOOLEAN CCP1Captured;

//--------------------------------------------------------------------------
#int_CCP1
CCP1_isr()
{
CCP1Value = CCP_1 - CCP1OldValue;
CCP1OldValue = CCP_1;
CCP1Captured = TRUE;
}
//--------------------------------------------------------------------------


void main() {

long periodo,per;


int h1,h2;

int8 out_data[USB_EP1_TX_SIZE];//array outgoing data


setup_counters(RTCC_INTERNAL,RTCC_DIV_256);
setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);//era 8

enable_interrupts(INT_CCP1);
enable_interrupts(global);

CCP1Value = 0;
CCP1OldValue = 0;
CCP1Captured = TRUE;



usb_init();//inizializza la trasmissione tramite porta usb

usb_wait_for_enumeration();

if(usb_enumerated())

while(1){


if (CCP1Captured) {

//---
// F = 1/T
// Timer1 prescaler DIV_BY_8
// Pic16C745 at 24Mz -> 1.66666e-7* 8=1.33333e-6
//---


periodo = ((float)CCP1Value*1.333e-6)*550000;




per=periodo;



CCP1Captured = FALSE;
}



//break in 2 pieces to send through usb
h1= make8(per, 0);//low
h2= make8(per, 1);///high
//h3= make8(per, 2);
//h4= make8(per, 3);



//----------------------------------------------------------------------------------



out_data[0]=0;
out_data[1]=0;
out_data[2]=0;

out_data[3]=h1;//contiene la lettura di frequenza
out_data[4]=h2;
out_data[5]=0;
out_data[6]=0;
out_data[7]=0;


usb_put_packet(1, out_data, USB_EP1_TX_SIZE, TOGGLE);
delay_ms(500);




}}


but With a 24MHz clock and a Timer1 divide by 8 the CCP count increments every 1.33333us

1/((24000000/4)/8) = 1.3333333333e-6.

So, say the CCP value is 68. 68*1.33us = 90.66us or 11.028KHz
So, say the CCP value is 69. 69*1.33us = 91.99us or 10.869KHz
So, say the CCP value is 70. 70*1.33us = 93.33us or 10.714KHz


The resolution is not high enough for timer1's increment rate.

then i've found this post:
http://www.ccsinfo.com/forum/viewtopic.php?t=906

and i used the code written inside...

but the compiler gives me many errors!! why?

can someone help me in writing the code??

after i copied this
#define BytePtr(var, offset) (char *)(&var + offset)
// The Timer1 interrupt increments an 8-bit variable which
// extends the timer to 24 bits. We need this so we can
// avoid having to switch the Timer pre-scaler between "low"
// and "high" rpm ranges.

char gc_timer1_extension;
BOOLEAN gc_capture_flag;


#int_TIMER1
void timer1_isr(void)
{
gc_timer1_extension++;
}




#int_ccp1
void ccp1_isr(void)
{
char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp = 0;

// Set flag to indicate that we did a capture.
gc_capture_flag = TRUE;

current_ccp = (int32)CCP_1; // Read the current CCP

// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension;

// Check if a Timer1 interrupt is pending. If so, check if
// the CCP capture occurred before or after the Timer rolled
// over. We can tell if it occurred after it rolled over, if
// the CCP's MSB is zero. ie., if the CCP is somewhere between
// 0x0000 and 0x00FF.
// We know that we can just check if the MSB = 0x00, because
// it takes about 30 us to get into this ISR. (Using a 4 Mhz
// crystal on a 16F628). The timer increments at 1 us per
// count, so 0xFF = 255 us.
// Actually, to be safer, I'll give it 2 MSB counts, which is
// 511 us. That way, if I lengthen any of the other ISR's,
// we'll still be able to detect the roll-over OK.
// If the timer did roll over after we got a CCP interrupt,
// then we need to increment the timer extension byte, that we
// save. We have to do that because the CCP interrupt has
// priority, and so it executes before the Timer isr can
// execute and increment the extension.
// (Designing the code with the priority switched doesn't help.
// You still have the same type of problem. With CCP first,
// the fix is easier).
//

// Was CCP captured after Timer1 wrapped ?
// If so, increment the copy of the timer ext.
if(TMR1IF_BIT)
{
if(*BytePtr(current_ccp, 1) < 2)
timer_ext_copy++;

// Since we know a timer interrupt is pending, let's just
// handle it here and now. That saves a little load off
// the processor.
gc_timer1_extension++; // Increment the real timer extension
TMR1IF_BIT = 0; // Then clear the Timer1 interrupt
}

// Insert the timer extension into the proper place in the
// 32-bit CCP value.
// ie., Insert it into location "EE" as follows: 0x00EEnnnn
// (nnnn = the CCP).
*BytePtr(current_ccp, 2) = timer_ext_copy;

// Because we're using unsigned math, we don't have to worry
// if the current value is less than the old. The result is
// always the absolute value of the difference. The only way
// there could be a problem is if the new CCP value had rolled
// over twice. But with a 24-bit value, and a Timer
// pre-scalar of 1, that's 16.7 seconds. That's way beyond any
// practical value.

// Edited on Jan. 2, 2004: There was a bug in this routine,
// because I was promoting a 24-bit value to a 32-bit data type,
// but the upper byte was always left = 0. This caused a problem
// with the 32-bit subtraction when the 24-bit value rolled over past 0.
// Kenny spotted this error and provided a fix in a PM to me.
// I have commented out the original line, and inserted his fix, below.
//g32_ccp_delta = current_ccp - old_ccp;
g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);

// Save the current ccp value for next time.
old_ccp = current_ccp;

}



what i must do ???

thanks
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Nov 14, 2004 7:50 am     Reply with quote

First a general remark: When posting code use the 'Code' button! This ensures the formatting of your code is kept and will make reading much easier to us.

The errors you get are from two missing variable declarations.

Sorry, but I get the feeling that you have no clue as to what you are doing. You are browsing this forum for code that might do what you want it to do, but please do inderstand there are about a dozen different solutions for measuring period times. It all depends on the frequency of the input signal, required accuracy and update period.

In order to save everybody a lot of time, please answer the following questions:
What is your lowest input frequency?
What is your highest input frequency?
How accurate must the measurement be?
Your update period is 0,5 seonds, isn't it?
zio_pecos



Joined: 24 Oct 2004
Posts: 21
Location: italy

View user's profile Send private message

PostPosted: Sun Nov 14, 2004 11:11 am     Reply with quote

lower frequency : 1k Hz

higher frequency: 15k Hz

accuracy: 1Hz

i think that in this condition my update period is 0.5 seconds...i don't know which setting can change the update period


excuse me a lot for all this but it's hard to me understand...

i must do this work at all cost

excuse me again...

try to help me
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

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

PostPosted: Sun Nov 14, 2004 5:14 pm     Reply with quote

As I said in your other post. Using a divide by 1 will give you eight times more resolution than you currently have. Still, thats not going to give you your 1Hz accuracy. You could extend the accuracy a bit further by measuring several rising edges. Any fractional timer ticks would get added together instead of getting lost.
Kenny



Joined: 07 Sep 2003
Posts: 173
Location: Australia

View user's profile Send private message

PostPosted: Sun Nov 14, 2004 9:24 pm     Reply with quote

As Mark said, counting over multiple edges will give a better result, but the measurement accuracy will still be limited to a few Hz at the 15000Hz end of the range.
Even with the maximum ccp prescaler of 16
setup_ccp1(CCP_CAPTURE_DIV_16);
the problem remains. Successive readings could be fed into a moving average filter to further improve things a bit.

Actually with these requirements it would probably be better to setup timer 1 as a counter and connect the input to RC0, the input for timer 1.
To get the 1Hz accuracy it would be necessary to gate the counter for at least one second and this will limit the update rate.
In the example below the gate time is done with with a delay - another timer could be used to generate the gate time.

Code:

#bit timer1_on = 0x10.0 // T1CON bit 0

void main()
{
   int16 freq;
   int16 new_count;
   int16 old_count;
   setup_timer_1(T1_EXTERNAL);
     
  while(1)
   {
      timer1_on = TRUE;
      delay_ms(1000);
      timer1_on = FALSE;
      new_count = get_timer1();
      freq = new_count - old_count;
      old_count = new_count;
   }
}   
zio_pecos



Joined: 24 Oct 2004
Posts: 21
Location: italy

View user's profile Send private message

PostPosted: Tue Nov 16, 2004 3:53 am     Reply with quote

ok now that's all right

with your help i've founded a solution!!!

thank you very much

but
i want to ask you another question:


i want to capture 2 signal from ccp1 and ccp2 pins

this code is right?
Code:

//--------------------------------------------------------------------------
// CCP1 Data
//
int16 CCP1Value;
int16 CCP1OldValue;
BOOLEAN CCP1Captured;

//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// CCP2 Data
//
int16 CCP2Value;
int16 CCP2OldValue;
BOOLEAN CCP2Captured;

//--------------------------------------------------------------------------





#int_CCP1
CCP1_isr()
 {
CCP1Value = CCP_1 - CCP1OldValue;
CCP1OldValue = CCP_1;
CCP1Captured = TRUE;
}
//--------------------------------------------------------------------------


#int_CCP2
CCP2_isr()
{
CCP2Value = CCP_2 - CCP2OldValue;
CCP2OldValue = CCP_2;
CCP2Captured = TRUE;
}
//--------------------------------------------------------------------------
void main() {

int16 periodo,per;
   int16 periodo1,per1;

setup_counters(RTCC_INTERNAL,RTCC_DIV_256);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
   setup_ccp1(CCP_CAPTURE_RE|CCP_CAPTURE_DIV_16);
   setup_ccp2(CCP_CAPTURE_RE|CCP_CAPTURE_DIV_16);
   enable_interrupts(INT_CCP1);
   enable_interrupts(INT_CCP2);
   enable_interrupts(global);

CCP1Value = 0;
CCP1OldValue = 0;
CCP1Captured = TRUE;

CCP2Value = 0;
CCP2OldValue = 0;
CCP2Captured = TRUE;

if (CCP1Captured) {

//---
// F = 1/T
// Timer1 prescaler DIV_BY_1
// Pic16C745 at 24Mz -> 4/24M= 1.66666e-7;ans*(timeprescaler/ccpprescaler)
//

periodo=((float)CCP1Value*4/(24e6)/16)*100000000;
per=periodo;
CCP1Captured = FALSE;
}


if (CCP2Captured) {

//---
// F = 1/T
// Timer1 prescaler DIV_BY_1
// Pic16C745 at 24Mz -> 4/24M= 1.66666e-7;ans*(timeprescaler/ccpprescaler)
//

periodo1=((float)CCP2Value*4/(24e6)/16)*100000000;
per1=periodo1;
CCP2Captured = FALSE;
}

[/code]


thank you
Kenny



Joined: 07 Sep 2003
Posts: 173
Location: Australia

View user's profile Send private message

PostPosted: Tue Nov 16, 2004 4:46 pm     Reply with quote

As stated before, the CCP capture approach will not be accurate at the 15kHz end of the range.

Personally I would use int32 instead of float for the scaling calculations.
Float generates a lot of code and the rounding error may be a problem.

With the CCP prescaler of 16, at 1kHz the count would be 96,000 and at 15kHz it would be 6400.
96,000 exceeds the 16 bit boundary so it is necessary to use PCM Programmer's timer 1 extension code. It works brilliantly well.

The code calculates the change in value.

Code:


int32 freq;

while(!gc_capture_flag);
gc_capture_flag = 0;

// Limit count to within maximum for 24 bit
if (g32_ccp_delta > 15000000) g32_ccp_delta = 15000000;

// Calculate frequency from captured count
// Apply rounding by adding half denominator.
freq = ((15000 * 6400) + (g32_ccp_delta/2))/ g32_ccp_delta;


For the second CCP it would be necessary to duplicate t1_extend.h for it.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

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

PostPosted: Wed Nov 17, 2004 6:48 am     Reply with quote

Well if you only have to update every 0.5 seconds, then just count the number of pulses in 0.5 seconds and multiply by 2. That will give you accuracy of 2 Hz and would be much simplier for a beginner.
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