|
|
View previous topic :: View next topic |
Author |
Message |
crystal_lattice
Joined: 13 Jun 2006 Posts: 164
|
CCP Frequency measurement |
Posted: Sun Mar 23, 2008 4:59 am |
|
|
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
|
frequency |
Posted: Sun Mar 23, 2008 7:32 am |
|
|
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
|
timer1 frequency input |
Posted: Tue Mar 25, 2008 3:55 am |
|
|
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);
}
}
|
|
|
|
|
|
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
|