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

CCP Frequency measurement

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



Joined: 13 Jun 2006
Posts: 164

View user's profile Send private message

CCP Frequency measurement
PostPosted: Sun Mar 23, 2008 4:59 am     Reply with quote

Hi all, hope you having a good easter!

I have a few questions regarding frequency measurement (my measurement range will be roughly between 5Khz and 500Khz) with a 18F4450 @ 20Mhz Xtal,and this code below. (originally found at:http://www.ccsinfo.com/forum/viewtopic.php?t=33153 ) This is the first time i'm using the CCP, and really using timers for something useful so please bare with me!

In my application i would like to make frequency measurements 'on demand', eg only when a function 'get_freq()' gets called should it calc/measure the freq. The application would benefit greatly if i could place the PIC in sleep mode or switch between clock speeds since it will be batt operated.

Firstly, I managed to get the code to compile on a 4450 even though i was originally for a 4550, my readings seem accurate at around 10Khz based on the dail of the function gen, but seem a bit off towards the lower 1000Hz band, PIC reads ~1500Hz, not really a problem now as i will confirm with scope during week, but suggestions will be welcome.

Secondly, my attempt to 'gate' the signal is shown using the 'if (gc_capture_flag)' in the isr to stop and the 'if (input(pin_c1))' in the main to start, this is just for crude testing so no de-bouncing was used.

I was wondering if this implementation of start/stop is the best method to do so considering the pic will be put to sleep after a reading and how this will affect timer1 as it will stop, right?

Thirdly, in my case where i want to make measurements 'on demand' would it not be better to start timer1, detect two rising edges and reset timer1 again and next time start the whole process over, or am i not considering all the complications?

Regards

Code:

#include <18F4450.H>
//#fuses HSPLL, PLL3, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP   // 12 MHz xtal
#fuses HSPLL, PLL5, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP // 20 MHz xtal
#use delay(clock=48000000)
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#priority CCP1, TIMER1

#define BytePtr(var, offset)   (char *)(&(char *)var + offset)

#byte PIR1 = 0xF9E
#bit  TMR1IF = PIR1.0

int8  gc_timer1_extension = 0;
int8  gc_capture_flag = FALSE;
int32 g32_ccp_delta;

//------------------------------------------------------
#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;


if (gc_capture_flag)                   //if the second rising edge of the pulse is detected then disable the ccp interrupt.
{
   disable_interrupts(INT_CCP1);
}


gc_capture_flag = TRUE;       

current_ccp = (int32)CCP_1;   

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


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

   // 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 = 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;

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;

}

//=======================
void main()
{
int16 frequency;
int32 current_ccp_delta;

set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);   

setup_ccp1(CCP_CAPTURE_RE);   

// Enable interrupts.
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);

clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);

enable_interrupts(GLOBAL);


while(1)
  {
   disable_interrupts(GLOBAL);
   current_ccp_delta = g32_ccp_delta;;
   enable_interrupts(GLOBAL);
   
   if (input(pin_c1))
   {
      clear_interrupt(INT_CCP1);
      enable_interrupts(INT_CCP1);
   }


   if(gc_capture_flag == TRUE)
     {
      frequency = (int16)((12000000L + (current_ccp_delta >> 1)) / current_ccp_delta);

      printf("%lu Hz\n\r", frequency);
//      printf("%lu Hz, delta = %lx \n\r", frequency, current_ccp_delta);

      gc_capture_flag = FALSE;
    }
  else
    {
    // printf("No signal\n\r");
    }

  delay_ms(100);
 }

}
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

frequency
PostPosted: Sun Mar 23, 2008 7:32 am     Reply with quote

with 12MIPS timer1 (1:1 prescaler) will increment
24 times for 500khz;240 times for 50khz; 2400 times for 5khz
25 times for 480khz;241 times for 49.792khz; 2401 times for 4.997khz
is the resolution ok?
at 500khz timer1 increment=20khz
at 50khz timer1 increment=208hz
I am measuring frequency as below, but up to 50khz, using 32mhz clock.
ccp1 is holding timer1 content when interrupt
more simple to calculate.
best regards
joseph

Code:
int frequencytime=0;
short int startflag=0;
//when you want to measure frequency start by enabling int.ccp1
enable_interrupts(INT_CCP1);

#int_CCP1
void CCP1_isr()
{   
   set_timer1(0);
   if (startflag==1)
   {
      frequencytime=CCP_1;
      disable_interrupts(INT_CCP1);
//      "calculating the frequency"
      startflag=0;//for the next time frequency check
   else
   {
      startflag=1;
   }   
}
crystal_lattice



Joined: 13 Jun 2006
Posts: 164

View user's profile Send private message

timer1 frequency input
PostPosted: Tue Mar 25, 2008 3:55 am     Reply with quote

Hi guys, i've modified my code a little and it seems OK, i'm still wondering about the complications involved with enabling/disabling timer1 like this.

I am also new to the PLL function, if my understanding is correct,then if i have a 12Mhz crystal and the PLL is set to x4 that the PIC will be running at 48Mhz, and timer1 at max 12Mhz? is there a way to increase the timer1 frequency but keeping the clock frequency of the 'core' low (for battery life purposes)? Would i have to use two crystals?

i'm trying to increase the resolution of the frequency measurement and it seems that increasing the CCP prescaler will only increases the accuracy of the measurement and NOT the resolution. The only way i can see is to increase the timer1 frequency, or is there other methods that 1'm not seeing.

If someone could explain how the prescaler changes one's calculations i would greatly appreciate it. My understanding is that a 1:16 prescaled will interrupt after 16 rising edges, but this is only 15 periods??

Code:

#include <18F4450.H>
//#fuses HSPLL, PLL3, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP   // 12 MHz xtal
#fuses HSPLL, PLL5, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP // 20 MHz xtal
#use delay(clock=48000000)
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#priority CCP1, TIMER1

#define BytePtr(var, offset)   (char *)(&(char *)var + offset)

#byte PIR1 = 0xF9E
#bit  TMR1IF = PIR1.0

int32 First_CCP, Second_CCP;

int8  gc_timer1_extension = 0;
int8  gc_capture_flag = FALSE;
int32 g32_ccp_delta;

//------------------------------------------------------
#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}

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

#int_ccp1
void ccp1_isr(void)
{

   if (gc_capture_flag)                   //if the second rising edge of the pulse is detected then disable the ccp interrupt.
   {
     
      disable_interrupts(INT_TIMER1);
      disable_interrupts(INT_CCP1);
      setup_timer_1(T1_DISABLED);
      second_ccp = (int32)CCP_1;
      gc_capture_flag = true;
   }

   else
   {
      first_ccp = (int32)CCP_1;

   }
 
}

//=======================
void main()
{
int16 frequency;
int32 current_ccp_delta;

//set_timer1(0);           
//setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);   

setup_ccp1(CCP_CAPTURE_RE);   

// Enable interrupts.
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);

clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);

enable_interrupts(GLOBAL);


while(1)
  {
   disable_interrupts(GLOBAL);
   current_ccp_delta = g32_ccp_delta;;
   enable_interrupts(GLOBAL);
   
   if (input(pin_c1))
   {
      clear_interrupt(INT_CCP1);
      enable_interrupts(INT_CCP1);
     
      set_timer1(0);
      setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
      clear_interrupt(INT_TIMER1);
      enable_interrupts(INT_TIMER1);
     
   }


   if(gc_capture_flag == TRUE)
     {
      setup_timer_1(T1_DISABLED);

      (int32)current_ccp_delta = second_ccp-first_ccp;
      frequency = (int16)((12000000L + (current_ccp_delta >> 1)) / current_ccp_delta);

      printf("%lu Hz First: %lu Second: %lu\n\r", frequency, first_ccp,second_ccp);
//      printf("%lu Hz, delta = %lx \n\r", frequency, current_ccp_delta);

      gc_capture_flag = FALSE;
    }
  else
    {
    // printf("No signal\n\r");
    }

  delay_ms(100);
 }

}
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